editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, 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)]
  780pub struct 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 is_within_block_comment = buffer
 4009                                    .language_scope_at(start_point)
 4010                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4011                                if !is_within_block_comment {
 4012                                    return None;
 4013                                }
 4014
 4015                                let (snapshot, range) =
 4016                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4017
 4018                                let num_of_whitespaces = snapshot
 4019                                    .chars_for_range(range.clone())
 4020                                    .take_while(|c| c.is_whitespace())
 4021                                    .count();
 4022
 4023                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4024                                let column = start_point.column;
 4025                                let cursor_is_after_start_tag = {
 4026                                    let start_tag_len = start_tag.len();
 4027                                    let start_tag_line = snapshot
 4028                                        .chars_for_range(range.clone())
 4029                                        .skip(num_of_whitespaces)
 4030                                        .take(start_tag_len)
 4031                                        .collect::<String>();
 4032                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4033                                        num_of_whitespaces + start_tag_len <= column as usize
 4034                                    } else {
 4035                                        false
 4036                                    }
 4037                                };
 4038
 4039                                let cursor_is_after_delimiter = {
 4040                                    let delimiter_trim = delimiter.trim_end();
 4041                                    let delimiter_line = snapshot
 4042                                        .chars_for_range(range.clone())
 4043                                        .skip(num_of_whitespaces)
 4044                                        .take(delimiter_trim.len())
 4045                                        .collect::<String>();
 4046                                    if delimiter_line.starts_with(delimiter_trim) {
 4047                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4048                                    } else {
 4049                                        false
 4050                                    }
 4051                                };
 4052
 4053                                let cursor_is_before_end_tag_if_exists = {
 4054                                    let mut char_position = 0u32;
 4055                                    let mut end_tag_offset = None;
 4056
 4057                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4058                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4059                                            let chars_before_match =
 4060                                                chunk[..byte_pos].chars().count() as u32;
 4061                                            end_tag_offset =
 4062                                                Some(char_position + chars_before_match);
 4063                                            break 'outer;
 4064                                        }
 4065                                        char_position += chunk.chars().count() as u32;
 4066                                    }
 4067
 4068                                    if let Some(end_tag_offset) = end_tag_offset {
 4069                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4070                                        if cursor_is_after_start_tag {
 4071                                            if cursor_is_before_end_tag {
 4072                                                insert_extra_newline = true;
 4073                                            }
 4074                                            let cursor_is_at_start_of_end_tag =
 4075                                                column == end_tag_offset;
 4076                                            if cursor_is_at_start_of_end_tag {
 4077                                                indent_on_extra_newline.len = (*len).into();
 4078                                            }
 4079                                        }
 4080                                        cursor_is_before_end_tag
 4081                                    } else {
 4082                                        true
 4083                                    }
 4084                                };
 4085
 4086                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4087                                    && cursor_is_before_end_tag_if_exists
 4088                                {
 4089                                    if cursor_is_after_start_tag {
 4090                                        indent_on_newline.len = (*len).into();
 4091                                    }
 4092                                    Some(delimiter.clone())
 4093                                } else {
 4094                                    None
 4095                                }
 4096                            });
 4097
 4098                            (
 4099                                comment_delimiter,
 4100                                doc_delimiter,
 4101                                insert_extra_newline,
 4102                                indent_on_newline,
 4103                                indent_on_extra_newline,
 4104                            )
 4105                        } else {
 4106                            (
 4107                                None,
 4108                                None,
 4109                                false,
 4110                                IndentSize::default(),
 4111                                IndentSize::default(),
 4112                            )
 4113                        };
 4114
 4115                        let prevent_auto_indent = doc_delimiter.is_some();
 4116                        let delimiter = comment_delimiter.or(doc_delimiter);
 4117
 4118                        let capacity_for_delimiter =
 4119                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4120                        let mut new_text = String::with_capacity(
 4121                            1 + capacity_for_delimiter
 4122                                + existing_indent.len as usize
 4123                                + indent_on_newline.len as usize
 4124                                + indent_on_extra_newline.len as usize,
 4125                        );
 4126                        new_text.push('\n');
 4127                        new_text.extend(existing_indent.chars());
 4128                        new_text.extend(indent_on_newline.chars());
 4129
 4130                        if let Some(delimiter) = &delimiter {
 4131                            new_text.push_str(delimiter);
 4132                        }
 4133
 4134                        if insert_extra_newline {
 4135                            new_text.push('\n');
 4136                            new_text.extend(existing_indent.chars());
 4137                            new_text.extend(indent_on_extra_newline.chars());
 4138                        }
 4139
 4140                        let anchor = buffer.anchor_after(end);
 4141                        let new_selection = selection.map(|_| anchor);
 4142                        (
 4143                            ((start..end, new_text), prevent_auto_indent),
 4144                            (insert_extra_newline, new_selection),
 4145                        )
 4146                    })
 4147                    .unzip()
 4148            };
 4149
 4150            let mut auto_indent_edits = Vec::new();
 4151            let mut edits = Vec::new();
 4152            for (edit, prevent_auto_indent) in edits_with_flags {
 4153                if prevent_auto_indent {
 4154                    edits.push(edit);
 4155                } else {
 4156                    auto_indent_edits.push(edit);
 4157                }
 4158            }
 4159            if !edits.is_empty() {
 4160                this.edit(edits, cx);
 4161            }
 4162            if !auto_indent_edits.is_empty() {
 4163                this.edit_with_autoindent(auto_indent_edits, cx);
 4164            }
 4165
 4166            let buffer = this.buffer.read(cx).snapshot(cx);
 4167            let new_selections = selection_info
 4168                .into_iter()
 4169                .map(|(extra_newline_inserted, new_selection)| {
 4170                    let mut cursor = new_selection.end.to_point(&buffer);
 4171                    if extra_newline_inserted {
 4172                        cursor.row -= 1;
 4173                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4174                    }
 4175                    new_selection.map(|_| cursor)
 4176                })
 4177                .collect();
 4178
 4179            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4180                s.select(new_selections)
 4181            });
 4182            this.refresh_inline_completion(true, false, window, cx);
 4183        });
 4184    }
 4185
 4186    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4187        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4188
 4189        let buffer = self.buffer.read(cx);
 4190        let snapshot = buffer.snapshot(cx);
 4191
 4192        let mut edits = Vec::new();
 4193        let mut rows = Vec::new();
 4194
 4195        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4196            let cursor = selection.head();
 4197            let row = cursor.row;
 4198
 4199            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4200
 4201            let newline = "\n".to_string();
 4202            edits.push((start_of_line..start_of_line, newline));
 4203
 4204            rows.push(row + rows_inserted as u32);
 4205        }
 4206
 4207        self.transact(window, cx, |editor, window, cx| {
 4208            editor.edit(edits, cx);
 4209
 4210            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4211                let mut index = 0;
 4212                s.move_cursors_with(|map, _, _| {
 4213                    let row = rows[index];
 4214                    index += 1;
 4215
 4216                    let point = Point::new(row, 0);
 4217                    let boundary = map.next_line_boundary(point).1;
 4218                    let clipped = map.clip_point(boundary, Bias::Left);
 4219
 4220                    (clipped, SelectionGoal::None)
 4221                });
 4222            });
 4223
 4224            let mut indent_edits = Vec::new();
 4225            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4226            for row in rows {
 4227                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4228                for (row, indent) in indents {
 4229                    if indent.len == 0 {
 4230                        continue;
 4231                    }
 4232
 4233                    let text = match indent.kind {
 4234                        IndentKind::Space => " ".repeat(indent.len as usize),
 4235                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4236                    };
 4237                    let point = Point::new(row.0, 0);
 4238                    indent_edits.push((point..point, text));
 4239                }
 4240            }
 4241            editor.edit(indent_edits, cx);
 4242        });
 4243    }
 4244
 4245    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4246        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4247
 4248        let buffer = self.buffer.read(cx);
 4249        let snapshot = buffer.snapshot(cx);
 4250
 4251        let mut edits = Vec::new();
 4252        let mut rows = Vec::new();
 4253        let mut rows_inserted = 0;
 4254
 4255        for selection in self.selections.all_adjusted(cx) {
 4256            let cursor = selection.head();
 4257            let row = cursor.row;
 4258
 4259            let point = Point::new(row + 1, 0);
 4260            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4261
 4262            let newline = "\n".to_string();
 4263            edits.push((start_of_line..start_of_line, newline));
 4264
 4265            rows_inserted += 1;
 4266            rows.push(row + rows_inserted);
 4267        }
 4268
 4269        self.transact(window, cx, |editor, window, cx| {
 4270            editor.edit(edits, cx);
 4271
 4272            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4273                let mut index = 0;
 4274                s.move_cursors_with(|map, _, _| {
 4275                    let row = rows[index];
 4276                    index += 1;
 4277
 4278                    let point = Point::new(row, 0);
 4279                    let boundary = map.next_line_boundary(point).1;
 4280                    let clipped = map.clip_point(boundary, Bias::Left);
 4281
 4282                    (clipped, SelectionGoal::None)
 4283                });
 4284            });
 4285
 4286            let mut indent_edits = Vec::new();
 4287            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4288            for row in rows {
 4289                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4290                for (row, indent) in indents {
 4291                    if indent.len == 0 {
 4292                        continue;
 4293                    }
 4294
 4295                    let text = match indent.kind {
 4296                        IndentKind::Space => " ".repeat(indent.len as usize),
 4297                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4298                    };
 4299                    let point = Point::new(row.0, 0);
 4300                    indent_edits.push((point..point, text));
 4301                }
 4302            }
 4303            editor.edit(indent_edits, cx);
 4304        });
 4305    }
 4306
 4307    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4308        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4309            original_indent_columns: Vec::new(),
 4310        });
 4311        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4312    }
 4313
 4314    fn insert_with_autoindent_mode(
 4315        &mut self,
 4316        text: &str,
 4317        autoindent_mode: Option<AutoindentMode>,
 4318        window: &mut Window,
 4319        cx: &mut Context<Self>,
 4320    ) {
 4321        if self.read_only(cx) {
 4322            return;
 4323        }
 4324
 4325        let text: Arc<str> = text.into();
 4326        self.transact(window, cx, |this, window, cx| {
 4327            let old_selections = this.selections.all_adjusted(cx);
 4328            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4329                let anchors = {
 4330                    let snapshot = buffer.read(cx);
 4331                    old_selections
 4332                        .iter()
 4333                        .map(|s| {
 4334                            let anchor = snapshot.anchor_after(s.head());
 4335                            s.map(|_| anchor)
 4336                        })
 4337                        .collect::<Vec<_>>()
 4338                };
 4339                buffer.edit(
 4340                    old_selections
 4341                        .iter()
 4342                        .map(|s| (s.start..s.end, text.clone())),
 4343                    autoindent_mode,
 4344                    cx,
 4345                );
 4346                anchors
 4347            });
 4348
 4349            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4350                s.select_anchors(selection_anchors);
 4351            });
 4352
 4353            cx.notify();
 4354        });
 4355    }
 4356
 4357    fn trigger_completion_on_input(
 4358        &mut self,
 4359        text: &str,
 4360        trigger_in_words: bool,
 4361        window: &mut Window,
 4362        cx: &mut Context<Self>,
 4363    ) {
 4364        let ignore_completion_provider = self
 4365            .context_menu
 4366            .borrow()
 4367            .as_ref()
 4368            .map(|menu| match menu {
 4369                CodeContextMenu::Completions(completions_menu) => {
 4370                    completions_menu.ignore_completion_provider
 4371                }
 4372                CodeContextMenu::CodeActions(_) => false,
 4373            })
 4374            .unwrap_or(false);
 4375
 4376        if ignore_completion_provider {
 4377            self.show_word_completions(&ShowWordCompletions, window, cx);
 4378        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4379            self.show_completions(
 4380                &ShowCompletions {
 4381                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4382                },
 4383                window,
 4384                cx,
 4385            );
 4386        } else {
 4387            self.hide_context_menu(window, cx);
 4388        }
 4389    }
 4390
 4391    fn is_completion_trigger(
 4392        &self,
 4393        text: &str,
 4394        trigger_in_words: bool,
 4395        cx: &mut Context<Self>,
 4396    ) -> bool {
 4397        let position = self.selections.newest_anchor().head();
 4398        let multibuffer = self.buffer.read(cx);
 4399        let Some(buffer) = position
 4400            .buffer_id
 4401            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4402        else {
 4403            return false;
 4404        };
 4405
 4406        if let Some(completion_provider) = &self.completion_provider {
 4407            completion_provider.is_completion_trigger(
 4408                &buffer,
 4409                position.text_anchor,
 4410                text,
 4411                trigger_in_words,
 4412                cx,
 4413            )
 4414        } else {
 4415            false
 4416        }
 4417    }
 4418
 4419    /// If any empty selections is touching the start of its innermost containing autoclose
 4420    /// region, expand it to select the brackets.
 4421    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4422        let selections = self.selections.all::<usize>(cx);
 4423        let buffer = self.buffer.read(cx).read(cx);
 4424        let new_selections = self
 4425            .selections_with_autoclose_regions(selections, &buffer)
 4426            .map(|(mut selection, region)| {
 4427                if !selection.is_empty() {
 4428                    return selection;
 4429                }
 4430
 4431                if let Some(region) = region {
 4432                    let mut range = region.range.to_offset(&buffer);
 4433                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4434                        range.start -= region.pair.start.len();
 4435                        if buffer.contains_str_at(range.start, &region.pair.start)
 4436                            && buffer.contains_str_at(range.end, &region.pair.end)
 4437                        {
 4438                            range.end += region.pair.end.len();
 4439                            selection.start = range.start;
 4440                            selection.end = range.end;
 4441
 4442                            return selection;
 4443                        }
 4444                    }
 4445                }
 4446
 4447                let always_treat_brackets_as_autoclosed = buffer
 4448                    .language_settings_at(selection.start, cx)
 4449                    .always_treat_brackets_as_autoclosed;
 4450
 4451                if !always_treat_brackets_as_autoclosed {
 4452                    return selection;
 4453                }
 4454
 4455                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4456                    for (pair, enabled) in scope.brackets() {
 4457                        if !enabled || !pair.close {
 4458                            continue;
 4459                        }
 4460
 4461                        if buffer.contains_str_at(selection.start, &pair.end) {
 4462                            let pair_start_len = pair.start.len();
 4463                            if buffer.contains_str_at(
 4464                                selection.start.saturating_sub(pair_start_len),
 4465                                &pair.start,
 4466                            ) {
 4467                                selection.start -= pair_start_len;
 4468                                selection.end += pair.end.len();
 4469
 4470                                return selection;
 4471                            }
 4472                        }
 4473                    }
 4474                }
 4475
 4476                selection
 4477            })
 4478            .collect();
 4479
 4480        drop(buffer);
 4481        self.change_selections(None, window, cx, |selections| {
 4482            selections.select(new_selections)
 4483        });
 4484    }
 4485
 4486    /// Iterate the given selections, and for each one, find the smallest surrounding
 4487    /// autoclose region. This uses the ordering of the selections and the autoclose
 4488    /// regions to avoid repeated comparisons.
 4489    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4490        &'a self,
 4491        selections: impl IntoIterator<Item = Selection<D>>,
 4492        buffer: &'a MultiBufferSnapshot,
 4493    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4494        let mut i = 0;
 4495        let mut regions = self.autoclose_regions.as_slice();
 4496        selections.into_iter().map(move |selection| {
 4497            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4498
 4499            let mut enclosing = None;
 4500            while let Some(pair_state) = regions.get(i) {
 4501                if pair_state.range.end.to_offset(buffer) < range.start {
 4502                    regions = &regions[i + 1..];
 4503                    i = 0;
 4504                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4505                    break;
 4506                } else {
 4507                    if pair_state.selection_id == selection.id {
 4508                        enclosing = Some(pair_state);
 4509                    }
 4510                    i += 1;
 4511                }
 4512            }
 4513
 4514            (selection, enclosing)
 4515        })
 4516    }
 4517
 4518    /// Remove any autoclose regions that no longer contain their selection.
 4519    fn invalidate_autoclose_regions(
 4520        &mut self,
 4521        mut selections: &[Selection<Anchor>],
 4522        buffer: &MultiBufferSnapshot,
 4523    ) {
 4524        self.autoclose_regions.retain(|state| {
 4525            let mut i = 0;
 4526            while let Some(selection) = selections.get(i) {
 4527                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4528                    selections = &selections[1..];
 4529                    continue;
 4530                }
 4531                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4532                    break;
 4533                }
 4534                if selection.id == state.selection_id {
 4535                    return true;
 4536                } else {
 4537                    i += 1;
 4538                }
 4539            }
 4540            false
 4541        });
 4542    }
 4543
 4544    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4545        let offset = position.to_offset(buffer);
 4546        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4547        if offset > word_range.start && kind == Some(CharKind::Word) {
 4548            Some(
 4549                buffer
 4550                    .text_for_range(word_range.start..offset)
 4551                    .collect::<String>(),
 4552            )
 4553        } else {
 4554            None
 4555        }
 4556    }
 4557
 4558    pub fn toggle_inline_values(
 4559        &mut self,
 4560        _: &ToggleInlineValues,
 4561        _: &mut Window,
 4562        cx: &mut Context<Self>,
 4563    ) {
 4564        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4565
 4566        self.refresh_inline_values(cx);
 4567    }
 4568
 4569    pub fn toggle_inlay_hints(
 4570        &mut self,
 4571        _: &ToggleInlayHints,
 4572        _: &mut Window,
 4573        cx: &mut Context<Self>,
 4574    ) {
 4575        self.refresh_inlay_hints(
 4576            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4577            cx,
 4578        );
 4579    }
 4580
 4581    pub fn inlay_hints_enabled(&self) -> bool {
 4582        self.inlay_hint_cache.enabled
 4583    }
 4584
 4585    pub fn inline_values_enabled(&self) -> bool {
 4586        self.inline_value_cache.enabled
 4587    }
 4588
 4589    #[cfg(any(test, feature = "test-support"))]
 4590    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4591        self.display_map
 4592            .read(cx)
 4593            .current_inlays()
 4594            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4595            .cloned()
 4596            .collect()
 4597    }
 4598
 4599    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4600        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4601            return;
 4602        }
 4603
 4604        let reason_description = reason.description();
 4605        let ignore_debounce = matches!(
 4606            reason,
 4607            InlayHintRefreshReason::SettingsChange(_)
 4608                | InlayHintRefreshReason::Toggle(_)
 4609                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4610                | InlayHintRefreshReason::ModifiersChanged(_)
 4611        );
 4612        let (invalidate_cache, required_languages) = match reason {
 4613            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4614                match self.inlay_hint_cache.modifiers_override(enabled) {
 4615                    Some(enabled) => {
 4616                        if enabled {
 4617                            (InvalidationStrategy::RefreshRequested, None)
 4618                        } else {
 4619                            self.splice_inlays(
 4620                                &self
 4621                                    .visible_inlay_hints(cx)
 4622                                    .iter()
 4623                                    .map(|inlay| inlay.id)
 4624                                    .collect::<Vec<InlayId>>(),
 4625                                Vec::new(),
 4626                                cx,
 4627                            );
 4628                            return;
 4629                        }
 4630                    }
 4631                    None => return,
 4632                }
 4633            }
 4634            InlayHintRefreshReason::Toggle(enabled) => {
 4635                if self.inlay_hint_cache.toggle(enabled) {
 4636                    if enabled {
 4637                        (InvalidationStrategy::RefreshRequested, None)
 4638                    } else {
 4639                        self.splice_inlays(
 4640                            &self
 4641                                .visible_inlay_hints(cx)
 4642                                .iter()
 4643                                .map(|inlay| inlay.id)
 4644                                .collect::<Vec<InlayId>>(),
 4645                            Vec::new(),
 4646                            cx,
 4647                        );
 4648                        return;
 4649                    }
 4650                } else {
 4651                    return;
 4652                }
 4653            }
 4654            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4655                match self.inlay_hint_cache.update_settings(
 4656                    &self.buffer,
 4657                    new_settings,
 4658                    self.visible_inlay_hints(cx),
 4659                    cx,
 4660                ) {
 4661                    ControlFlow::Break(Some(InlaySplice {
 4662                        to_remove,
 4663                        to_insert,
 4664                    })) => {
 4665                        self.splice_inlays(&to_remove, to_insert, cx);
 4666                        return;
 4667                    }
 4668                    ControlFlow::Break(None) => return,
 4669                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4670                }
 4671            }
 4672            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4673                if let Some(InlaySplice {
 4674                    to_remove,
 4675                    to_insert,
 4676                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4677                {
 4678                    self.splice_inlays(&to_remove, to_insert, cx);
 4679                }
 4680                self.display_map.update(cx, |display_map, _| {
 4681                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4682                });
 4683                return;
 4684            }
 4685            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4686            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4687                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4688            }
 4689            InlayHintRefreshReason::RefreshRequested => {
 4690                (InvalidationStrategy::RefreshRequested, None)
 4691            }
 4692        };
 4693
 4694        if let Some(InlaySplice {
 4695            to_remove,
 4696            to_insert,
 4697        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4698            reason_description,
 4699            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4700            invalidate_cache,
 4701            ignore_debounce,
 4702            cx,
 4703        ) {
 4704            self.splice_inlays(&to_remove, to_insert, cx);
 4705        }
 4706    }
 4707
 4708    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4709        self.display_map
 4710            .read(cx)
 4711            .current_inlays()
 4712            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4713            .cloned()
 4714            .collect()
 4715    }
 4716
 4717    pub fn excerpts_for_inlay_hints_query(
 4718        &self,
 4719        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4720        cx: &mut Context<Editor>,
 4721    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4722        let Some(project) = self.project.as_ref() else {
 4723            return HashMap::default();
 4724        };
 4725        let project = project.read(cx);
 4726        let multi_buffer = self.buffer().read(cx);
 4727        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4728        let multi_buffer_visible_start = self
 4729            .scroll_manager
 4730            .anchor()
 4731            .anchor
 4732            .to_point(&multi_buffer_snapshot);
 4733        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4734            multi_buffer_visible_start
 4735                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4736            Bias::Left,
 4737        );
 4738        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4739        multi_buffer_snapshot
 4740            .range_to_buffer_ranges(multi_buffer_visible_range)
 4741            .into_iter()
 4742            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4743            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4744                let buffer_file = project::File::from_dyn(buffer.file())?;
 4745                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4746                let worktree_entry = buffer_worktree
 4747                    .read(cx)
 4748                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4749                if worktree_entry.is_ignored {
 4750                    return None;
 4751                }
 4752
 4753                let language = buffer.language()?;
 4754                if let Some(restrict_to_languages) = restrict_to_languages {
 4755                    if !restrict_to_languages.contains(language) {
 4756                        return None;
 4757                    }
 4758                }
 4759                Some((
 4760                    excerpt_id,
 4761                    (
 4762                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4763                        buffer.version().clone(),
 4764                        excerpt_visible_range,
 4765                    ),
 4766                ))
 4767            })
 4768            .collect()
 4769    }
 4770
 4771    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4772        TextLayoutDetails {
 4773            text_system: window.text_system().clone(),
 4774            editor_style: self.style.clone().unwrap(),
 4775            rem_size: window.rem_size(),
 4776            scroll_anchor: self.scroll_manager.anchor(),
 4777            visible_rows: self.visible_line_count(),
 4778            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4779        }
 4780    }
 4781
 4782    pub fn splice_inlays(
 4783        &self,
 4784        to_remove: &[InlayId],
 4785        to_insert: Vec<Inlay>,
 4786        cx: &mut Context<Self>,
 4787    ) {
 4788        self.display_map.update(cx, |display_map, cx| {
 4789            display_map.splice_inlays(to_remove, to_insert, cx)
 4790        });
 4791        cx.notify();
 4792    }
 4793
 4794    fn trigger_on_type_formatting(
 4795        &self,
 4796        input: String,
 4797        window: &mut Window,
 4798        cx: &mut Context<Self>,
 4799    ) -> Option<Task<Result<()>>> {
 4800        if input.len() != 1 {
 4801            return None;
 4802        }
 4803
 4804        let project = self.project.as_ref()?;
 4805        let position = self.selections.newest_anchor().head();
 4806        let (buffer, buffer_position) = self
 4807            .buffer
 4808            .read(cx)
 4809            .text_anchor_for_position(position, cx)?;
 4810
 4811        let settings = language_settings::language_settings(
 4812            buffer
 4813                .read(cx)
 4814                .language_at(buffer_position)
 4815                .map(|l| l.name()),
 4816            buffer.read(cx).file(),
 4817            cx,
 4818        );
 4819        if !settings.use_on_type_format {
 4820            return None;
 4821        }
 4822
 4823        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4824        // hence we do LSP request & edit on host side only — add formats to host's history.
 4825        let push_to_lsp_host_history = true;
 4826        // If this is not the host, append its history with new edits.
 4827        let push_to_client_history = project.read(cx).is_via_collab();
 4828
 4829        let on_type_formatting = project.update(cx, |project, cx| {
 4830            project.on_type_format(
 4831                buffer.clone(),
 4832                buffer_position,
 4833                input,
 4834                push_to_lsp_host_history,
 4835                cx,
 4836            )
 4837        });
 4838        Some(cx.spawn_in(window, async move |editor, cx| {
 4839            if let Some(transaction) = on_type_formatting.await? {
 4840                if push_to_client_history {
 4841                    buffer
 4842                        .update(cx, |buffer, _| {
 4843                            buffer.push_transaction(transaction, Instant::now());
 4844                            buffer.finalize_last_transaction();
 4845                        })
 4846                        .ok();
 4847                }
 4848                editor.update(cx, |editor, cx| {
 4849                    editor.refresh_document_highlights(cx);
 4850                })?;
 4851            }
 4852            Ok(())
 4853        }))
 4854    }
 4855
 4856    pub fn show_word_completions(
 4857        &mut self,
 4858        _: &ShowWordCompletions,
 4859        window: &mut Window,
 4860        cx: &mut Context<Self>,
 4861    ) {
 4862        self.open_completions_menu(true, None, window, cx);
 4863    }
 4864
 4865    pub fn show_completions(
 4866        &mut self,
 4867        options: &ShowCompletions,
 4868        window: &mut Window,
 4869        cx: &mut Context<Self>,
 4870    ) {
 4871        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4872    }
 4873
 4874    fn open_completions_menu(
 4875        &mut self,
 4876        ignore_completion_provider: bool,
 4877        trigger: Option<&str>,
 4878        window: &mut Window,
 4879        cx: &mut Context<Self>,
 4880    ) {
 4881        if self.pending_rename.is_some() {
 4882            return;
 4883        }
 4884        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4885            return;
 4886        }
 4887
 4888        let position = self.selections.newest_anchor().head();
 4889        if position.diff_base_anchor.is_some() {
 4890            return;
 4891        }
 4892        let (buffer, buffer_position) =
 4893            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4894                output
 4895            } else {
 4896                return;
 4897            };
 4898        let buffer_snapshot = buffer.read(cx).snapshot();
 4899        let show_completion_documentation = buffer_snapshot
 4900            .settings_at(buffer_position, cx)
 4901            .show_completion_documentation;
 4902
 4903        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4904
 4905        let trigger_kind = match trigger {
 4906            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4907                CompletionTriggerKind::TRIGGER_CHARACTER
 4908            }
 4909            _ => CompletionTriggerKind::INVOKED,
 4910        };
 4911        let completion_context = CompletionContext {
 4912            trigger_character: trigger.and_then(|trigger| {
 4913                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4914                    Some(String::from(trigger))
 4915                } else {
 4916                    None
 4917                }
 4918            }),
 4919            trigger_kind,
 4920        };
 4921
 4922        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4923        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4924            let word_to_exclude = buffer_snapshot
 4925                .text_for_range(old_range.clone())
 4926                .collect::<String>();
 4927            (
 4928                buffer_snapshot.anchor_before(old_range.start)
 4929                    ..buffer_snapshot.anchor_after(old_range.end),
 4930                Some(word_to_exclude),
 4931            )
 4932        } else {
 4933            (buffer_position..buffer_position, None)
 4934        };
 4935
 4936        let completion_settings = language_settings(
 4937            buffer_snapshot
 4938                .language_at(buffer_position)
 4939                .map(|language| language.name()),
 4940            buffer_snapshot.file(),
 4941            cx,
 4942        )
 4943        .completions;
 4944
 4945        // The document can be large, so stay in reasonable bounds when searching for words,
 4946        // otherwise completion pop-up might be slow to appear.
 4947        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4948        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4949        let min_word_search = buffer_snapshot.clip_point(
 4950            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4951            Bias::Left,
 4952        );
 4953        let max_word_search = buffer_snapshot.clip_point(
 4954            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4955            Bias::Right,
 4956        );
 4957        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4958            ..buffer_snapshot.point_to_offset(max_word_search);
 4959
 4960        let provider = self
 4961            .completion_provider
 4962            .as_ref()
 4963            .filter(|_| !ignore_completion_provider);
 4964        let skip_digits = query
 4965            .as_ref()
 4966            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4967
 4968        let (mut words, provided_completions) = match provider {
 4969            Some(provider) => {
 4970                let completions = provider.completions(
 4971                    position.excerpt_id,
 4972                    &buffer,
 4973                    buffer_position,
 4974                    completion_context,
 4975                    window,
 4976                    cx,
 4977                );
 4978
 4979                let words = match completion_settings.words {
 4980                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4981                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4982                        .background_spawn(async move {
 4983                            buffer_snapshot.words_in_range(WordsQuery {
 4984                                fuzzy_contents: None,
 4985                                range: word_search_range,
 4986                                skip_digits,
 4987                            })
 4988                        }),
 4989                };
 4990
 4991                (words, completions)
 4992            }
 4993            None => (
 4994                cx.background_spawn(async move {
 4995                    buffer_snapshot.words_in_range(WordsQuery {
 4996                        fuzzy_contents: None,
 4997                        range: word_search_range,
 4998                        skip_digits,
 4999                    })
 5000                }),
 5001                Task::ready(Ok(None)),
 5002            ),
 5003        };
 5004
 5005        let sort_completions = provider
 5006            .as_ref()
 5007            .map_or(false, |provider| provider.sort_completions());
 5008
 5009        let filter_completions = provider
 5010            .as_ref()
 5011            .map_or(true, |provider| provider.filter_completions());
 5012
 5013        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5014
 5015        let id = post_inc(&mut self.next_completion_id);
 5016        let task = cx.spawn_in(window, async move |editor, cx| {
 5017            async move {
 5018                editor.update(cx, |this, _| {
 5019                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5020                })?;
 5021
 5022                let mut completions = Vec::new();
 5023                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5024                    completions.extend(provided_completions);
 5025                    if completion_settings.words == WordsCompletionMode::Fallback {
 5026                        words = Task::ready(BTreeMap::default());
 5027                    }
 5028                }
 5029
 5030                let mut words = words.await;
 5031                if let Some(word_to_exclude) = &word_to_exclude {
 5032                    words.remove(word_to_exclude);
 5033                }
 5034                for lsp_completion in &completions {
 5035                    words.remove(&lsp_completion.new_text);
 5036                }
 5037                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5038                    replace_range: old_range.clone(),
 5039                    new_text: word.clone(),
 5040                    label: CodeLabel::plain(word, None),
 5041                    icon_path: None,
 5042                    documentation: None,
 5043                    source: CompletionSource::BufferWord {
 5044                        word_range,
 5045                        resolved: false,
 5046                    },
 5047                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5048                    confirm: None,
 5049                }));
 5050
 5051                let menu = if completions.is_empty() {
 5052                    None
 5053                } else {
 5054                    let mut menu = CompletionsMenu::new(
 5055                        id,
 5056                        sort_completions,
 5057                        show_completion_documentation,
 5058                        ignore_completion_provider,
 5059                        position,
 5060                        buffer.clone(),
 5061                        completions.into(),
 5062                        snippet_sort_order,
 5063                    );
 5064
 5065                    menu.filter(
 5066                        if filter_completions {
 5067                            query.as_deref()
 5068                        } else {
 5069                            None
 5070                        },
 5071                        cx.background_executor().clone(),
 5072                    )
 5073                    .await;
 5074
 5075                    menu.visible().then_some(menu)
 5076                };
 5077
 5078                editor.update_in(cx, |editor, window, cx| {
 5079                    match editor.context_menu.borrow().as_ref() {
 5080                        None => {}
 5081                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5082                            if prev_menu.id > id {
 5083                                return;
 5084                            }
 5085                        }
 5086                        _ => return,
 5087                    }
 5088
 5089                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5090                        let mut menu = menu.unwrap();
 5091                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5092                        crate::hover_popover::hide_hover(editor, cx);
 5093                        *editor.context_menu.borrow_mut() =
 5094                            Some(CodeContextMenu::Completions(menu));
 5095
 5096                        if editor.show_edit_predictions_in_menu() {
 5097                            editor.update_visible_inline_completion(window, cx);
 5098                        } else {
 5099                            editor.discard_inline_completion(false, cx);
 5100                        }
 5101
 5102                        cx.notify();
 5103                    } else if editor.completion_tasks.len() <= 1 {
 5104                        // If there are no more completion tasks and the last menu was
 5105                        // empty, we should hide it.
 5106                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5107                        // If it was already hidden and we don't show inline
 5108                        // completions in the menu, we should also show the
 5109                        // inline-completion when available.
 5110                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5111                            editor.update_visible_inline_completion(window, cx);
 5112                        }
 5113                    }
 5114                })?;
 5115
 5116                anyhow::Ok(())
 5117            }
 5118            .log_err()
 5119            .await
 5120        });
 5121
 5122        self.completion_tasks.push((id, task));
 5123    }
 5124
 5125    #[cfg(feature = "test-support")]
 5126    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5127        let menu = self.context_menu.borrow();
 5128        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5129            let completions = menu.completions.borrow();
 5130            Some(completions.to_vec())
 5131        } else {
 5132            None
 5133        }
 5134    }
 5135
 5136    pub fn confirm_completion(
 5137        &mut self,
 5138        action: &ConfirmCompletion,
 5139        window: &mut Window,
 5140        cx: &mut Context<Self>,
 5141    ) -> Option<Task<Result<()>>> {
 5142        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5143        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5144    }
 5145
 5146    pub fn confirm_completion_insert(
 5147        &mut self,
 5148        _: &ConfirmCompletionInsert,
 5149        window: &mut Window,
 5150        cx: &mut Context<Self>,
 5151    ) -> Option<Task<Result<()>>> {
 5152        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5153        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5154    }
 5155
 5156    pub fn confirm_completion_replace(
 5157        &mut self,
 5158        _: &ConfirmCompletionReplace,
 5159        window: &mut Window,
 5160        cx: &mut Context<Self>,
 5161    ) -> Option<Task<Result<()>>> {
 5162        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5163        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5164    }
 5165
 5166    pub fn compose_completion(
 5167        &mut self,
 5168        action: &ComposeCompletion,
 5169        window: &mut Window,
 5170        cx: &mut Context<Self>,
 5171    ) -> Option<Task<Result<()>>> {
 5172        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5173        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5174    }
 5175
 5176    fn do_completion(
 5177        &mut self,
 5178        item_ix: Option<usize>,
 5179        intent: CompletionIntent,
 5180        window: &mut Window,
 5181        cx: &mut Context<Editor>,
 5182    ) -> Option<Task<Result<()>>> {
 5183        use language::ToOffset as _;
 5184
 5185        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5186        else {
 5187            return None;
 5188        };
 5189
 5190        let candidate_id = {
 5191            let entries = completions_menu.entries.borrow();
 5192            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5193            if self.show_edit_predictions_in_menu() {
 5194                self.discard_inline_completion(true, cx);
 5195            }
 5196            mat.candidate_id
 5197        };
 5198
 5199        let buffer_handle = completions_menu.buffer;
 5200        let completion = completions_menu
 5201            .completions
 5202            .borrow()
 5203            .get(candidate_id)?
 5204            .clone();
 5205        cx.stop_propagation();
 5206
 5207        let snapshot = self.buffer.read(cx).snapshot(cx);
 5208        let newest_anchor = self.selections.newest_anchor();
 5209
 5210        let snippet;
 5211        let new_text;
 5212        if completion.is_snippet() {
 5213            let mut snippet_source = completion.new_text.clone();
 5214            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5215                if scope.prefers_label_for_snippet_in_completion() {
 5216                    if let Some(label) = completion.label() {
 5217                        if matches!(
 5218                            completion.kind(),
 5219                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5220                        ) {
 5221                            snippet_source = label;
 5222                        }
 5223                    }
 5224                }
 5225            }
 5226            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5227            new_text = snippet.as_ref().unwrap().text.clone();
 5228        } else {
 5229            snippet = None;
 5230            new_text = completion.new_text.clone();
 5231        };
 5232
 5233        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5234        let buffer = buffer_handle.read(cx);
 5235        let replace_range_multibuffer = {
 5236            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5237            let multibuffer_anchor = snapshot
 5238                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5239                .unwrap()
 5240                ..snapshot
 5241                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5242                    .unwrap();
 5243            multibuffer_anchor.start.to_offset(&snapshot)
 5244                ..multibuffer_anchor.end.to_offset(&snapshot)
 5245        };
 5246        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5247            return None;
 5248        }
 5249
 5250        let old_text = buffer
 5251            .text_for_range(replace_range.clone())
 5252            .collect::<String>();
 5253        let lookbehind = newest_anchor
 5254            .start
 5255            .text_anchor
 5256            .to_offset(buffer)
 5257            .saturating_sub(replace_range.start);
 5258        let lookahead = replace_range
 5259            .end
 5260            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5261        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5262        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5263
 5264        let selections = self.selections.all::<usize>(cx);
 5265        let mut ranges = Vec::new();
 5266        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5267
 5268        for selection in &selections {
 5269            let range = if selection.id == newest_anchor.id {
 5270                replace_range_multibuffer.clone()
 5271            } else {
 5272                let mut range = selection.range();
 5273
 5274                // if prefix is present, don't duplicate it
 5275                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5276                    range.start = range.start.saturating_sub(lookbehind);
 5277
 5278                    // if suffix is also present, mimic the newest cursor and replace it
 5279                    if selection.id != newest_anchor.id
 5280                        && snapshot.contains_str_at(range.end, suffix)
 5281                    {
 5282                        range.end += lookahead;
 5283                    }
 5284                }
 5285                range
 5286            };
 5287
 5288            ranges.push(range.clone());
 5289
 5290            if !self.linked_edit_ranges.is_empty() {
 5291                let start_anchor = snapshot.anchor_before(range.start);
 5292                let end_anchor = snapshot.anchor_after(range.end);
 5293                if let Some(ranges) = self
 5294                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5295                {
 5296                    for (buffer, edits) in ranges {
 5297                        linked_edits
 5298                            .entry(buffer.clone())
 5299                            .or_default()
 5300                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5301                    }
 5302                }
 5303            }
 5304        }
 5305
 5306        cx.emit(EditorEvent::InputHandled {
 5307            utf16_range_to_replace: None,
 5308            text: new_text.clone().into(),
 5309        });
 5310
 5311        self.transact(window, cx, |this, window, cx| {
 5312            if let Some(mut snippet) = snippet {
 5313                snippet.text = new_text.to_string();
 5314                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5315            } else {
 5316                this.buffer.update(cx, |buffer, cx| {
 5317                    let auto_indent = match completion.insert_text_mode {
 5318                        Some(InsertTextMode::AS_IS) => None,
 5319                        _ => this.autoindent_mode.clone(),
 5320                    };
 5321                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5322                    buffer.edit(edits, auto_indent, cx);
 5323                });
 5324            }
 5325            for (buffer, edits) in linked_edits {
 5326                buffer.update(cx, |buffer, cx| {
 5327                    let snapshot = buffer.snapshot();
 5328                    let edits = edits
 5329                        .into_iter()
 5330                        .map(|(range, text)| {
 5331                            use text::ToPoint as TP;
 5332                            let end_point = TP::to_point(&range.end, &snapshot);
 5333                            let start_point = TP::to_point(&range.start, &snapshot);
 5334                            (start_point..end_point, text)
 5335                        })
 5336                        .sorted_by_key(|(range, _)| range.start);
 5337                    buffer.edit(edits, None, cx);
 5338                })
 5339            }
 5340
 5341            this.refresh_inline_completion(true, false, window, cx);
 5342        });
 5343
 5344        let show_new_completions_on_confirm = completion
 5345            .confirm
 5346            .as_ref()
 5347            .map_or(false, |confirm| confirm(intent, window, cx));
 5348        if show_new_completions_on_confirm {
 5349            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5350        }
 5351
 5352        let provider = self.completion_provider.as_ref()?;
 5353        drop(completion);
 5354        let apply_edits = provider.apply_additional_edits_for_completion(
 5355            buffer_handle,
 5356            completions_menu.completions.clone(),
 5357            candidate_id,
 5358            true,
 5359            cx,
 5360        );
 5361
 5362        let editor_settings = EditorSettings::get_global(cx);
 5363        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5364            // After the code completion is finished, users often want to know what signatures are needed.
 5365            // so we should automatically call signature_help
 5366            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5367        }
 5368
 5369        Some(cx.foreground_executor().spawn(async move {
 5370            apply_edits.await?;
 5371            Ok(())
 5372        }))
 5373    }
 5374
 5375    pub fn toggle_code_actions(
 5376        &mut self,
 5377        action: &ToggleCodeActions,
 5378        window: &mut Window,
 5379        cx: &mut Context<Self>,
 5380    ) {
 5381        let quick_launch = action.quick_launch;
 5382        let mut context_menu = self.context_menu.borrow_mut();
 5383        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5384            if code_actions.deployed_from == action.deployed_from {
 5385                // Toggle if we're selecting the same one
 5386                *context_menu = None;
 5387                cx.notify();
 5388                return;
 5389            } else {
 5390                // Otherwise, clear it and start a new one
 5391                *context_menu = None;
 5392                cx.notify();
 5393            }
 5394        }
 5395        drop(context_menu);
 5396        let snapshot = self.snapshot(window, cx);
 5397        let deployed_from = action.deployed_from.clone();
 5398        let mut task = self.code_actions_task.take();
 5399        let action = action.clone();
 5400        cx.spawn_in(window, async move |editor, cx| {
 5401            while let Some(prev_task) = task {
 5402                prev_task.await.log_err();
 5403                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5404            }
 5405
 5406            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5407                if editor.focus_handle.is_focused(window) {
 5408                    let multibuffer_point = match &action.deployed_from {
 5409                        Some(CodeActionSource::Indicator(row)) => {
 5410                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5411                        }
 5412                        _ => editor.selections.newest::<Point>(cx).head(),
 5413                    };
 5414                    let (buffer, buffer_row) = snapshot
 5415                        .buffer_snapshot
 5416                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5417                        .and_then(|(buffer_snapshot, range)| {
 5418                            editor
 5419                                .buffer
 5420                                .read(cx)
 5421                                .buffer(buffer_snapshot.remote_id())
 5422                                .map(|buffer| (buffer, range.start.row))
 5423                        })?;
 5424                    let (_, code_actions) = editor
 5425                        .available_code_actions
 5426                        .clone()
 5427                        .and_then(|(location, code_actions)| {
 5428                            let snapshot = location.buffer.read(cx).snapshot();
 5429                            let point_range = location.range.to_point(&snapshot);
 5430                            let point_range = point_range.start.row..=point_range.end.row;
 5431                            if point_range.contains(&buffer_row) {
 5432                                Some((location, code_actions))
 5433                            } else {
 5434                                None
 5435                            }
 5436                        })
 5437                        .unzip();
 5438                    let buffer_id = buffer.read(cx).remote_id();
 5439                    let tasks = editor
 5440                        .tasks
 5441                        .get(&(buffer_id, buffer_row))
 5442                        .map(|t| Arc::new(t.to_owned()));
 5443                    if tasks.is_none() && code_actions.is_none() {
 5444                        return None;
 5445                    }
 5446
 5447                    editor.completion_tasks.clear();
 5448                    editor.discard_inline_completion(false, cx);
 5449                    let task_context =
 5450                        tasks
 5451                            .as_ref()
 5452                            .zip(editor.project.clone())
 5453                            .map(|(tasks, project)| {
 5454                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5455                            });
 5456
 5457                    Some(cx.spawn_in(window, async move |editor, cx| {
 5458                        let task_context = match task_context {
 5459                            Some(task_context) => task_context.await,
 5460                            None => None,
 5461                        };
 5462                        let resolved_tasks =
 5463                            tasks
 5464                                .zip(task_context.clone())
 5465                                .map(|(tasks, task_context)| ResolvedTasks {
 5466                                    templates: tasks.resolve(&task_context).collect(),
 5467                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5468                                        multibuffer_point.row,
 5469                                        tasks.column,
 5470                                    )),
 5471                                });
 5472                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5473                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5474                                maybe!({
 5475                                    let project = editor.project.as_ref()?;
 5476                                    let dap_store = project.read(cx).dap_store();
 5477                                    let mut scenarios = vec![];
 5478                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5479                                    let buffer = buffer.read(cx);
 5480                                    let language = buffer.language()?;
 5481                                    let file = buffer.file();
 5482                                    let debug_adapter =
 5483                                        language_settings(language.name().into(), file, cx)
 5484                                            .debuggers
 5485                                            .first()
 5486                                            .map(SharedString::from)
 5487                                            .or_else(|| {
 5488                                                language
 5489                                                    .config()
 5490                                                    .debuggers
 5491                                                    .first()
 5492                                                    .map(SharedString::from)
 5493                                            })?;
 5494
 5495                                    dap_store.update(cx, |dap_store, cx| {
 5496                                        for (_, task) in &resolved_tasks.templates {
 5497                                            if let Some(scenario) = dap_store
 5498                                                .debug_scenario_for_build_task(
 5499                                                    task.original_task().clone(),
 5500                                                    debug_adapter.clone().into(),
 5501                                                    task.display_label().to_owned().into(),
 5502                                                    cx,
 5503                                                )
 5504                                            {
 5505                                                scenarios.push(scenario);
 5506                                            }
 5507                                        }
 5508                                    });
 5509                                    Some(scenarios)
 5510                                })
 5511                                .unwrap_or_default()
 5512                            } else {
 5513                                vec![]
 5514                            }
 5515                        })?;
 5516                        let spawn_straight_away = quick_launch
 5517                            && resolved_tasks
 5518                                .as_ref()
 5519                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5520                            && code_actions
 5521                                .as_ref()
 5522                                .map_or(true, |actions| actions.is_empty())
 5523                            && debug_scenarios.is_empty();
 5524                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5525                            crate::hover_popover::hide_hover(editor, cx);
 5526                            *editor.context_menu.borrow_mut() =
 5527                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5528                                    buffer,
 5529                                    actions: CodeActionContents::new(
 5530                                        resolved_tasks,
 5531                                        code_actions,
 5532                                        debug_scenarios,
 5533                                        task_context.unwrap_or_default(),
 5534                                    ),
 5535                                    selected_item: Default::default(),
 5536                                    scroll_handle: UniformListScrollHandle::default(),
 5537                                    deployed_from,
 5538                                }));
 5539                            if spawn_straight_away {
 5540                                if let Some(task) = editor.confirm_code_action(
 5541                                    &ConfirmCodeAction { item_ix: Some(0) },
 5542                                    window,
 5543                                    cx,
 5544                                ) {
 5545                                    cx.notify();
 5546                                    return task;
 5547                                }
 5548                            }
 5549                            cx.notify();
 5550                            Task::ready(Ok(()))
 5551                        }) {
 5552                            task.await
 5553                        } else {
 5554                            Ok(())
 5555                        }
 5556                    }))
 5557                } else {
 5558                    Some(Task::ready(Ok(())))
 5559                }
 5560            })?;
 5561            if let Some(task) = spawned_test_task {
 5562                task.await?;
 5563            }
 5564
 5565            anyhow::Ok(())
 5566        })
 5567        .detach_and_log_err(cx);
 5568    }
 5569
 5570    pub fn confirm_code_action(
 5571        &mut self,
 5572        action: &ConfirmCodeAction,
 5573        window: &mut Window,
 5574        cx: &mut Context<Self>,
 5575    ) -> Option<Task<Result<()>>> {
 5576        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5577
 5578        let actions_menu =
 5579            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5580                menu
 5581            } else {
 5582                return None;
 5583            };
 5584
 5585        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5586        let action = actions_menu.actions.get(action_ix)?;
 5587        let title = action.label();
 5588        let buffer = actions_menu.buffer;
 5589        let workspace = self.workspace()?;
 5590
 5591        match action {
 5592            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5593                workspace.update(cx, |workspace, cx| {
 5594                    workspace.schedule_resolved_task(
 5595                        task_source_kind,
 5596                        resolved_task,
 5597                        false,
 5598                        window,
 5599                        cx,
 5600                    );
 5601
 5602                    Some(Task::ready(Ok(())))
 5603                })
 5604            }
 5605            CodeActionsItem::CodeAction {
 5606                excerpt_id,
 5607                action,
 5608                provider,
 5609            } => {
 5610                let apply_code_action =
 5611                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5612                let workspace = workspace.downgrade();
 5613                Some(cx.spawn_in(window, async move |editor, cx| {
 5614                    let project_transaction = apply_code_action.await?;
 5615                    Self::open_project_transaction(
 5616                        &editor,
 5617                        workspace,
 5618                        project_transaction,
 5619                        title,
 5620                        cx,
 5621                    )
 5622                    .await
 5623                }))
 5624            }
 5625            CodeActionsItem::DebugScenario(scenario) => {
 5626                let context = actions_menu.actions.context.clone();
 5627
 5628                workspace.update(cx, |workspace, cx| {
 5629                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5630                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5631                });
 5632                Some(Task::ready(Ok(())))
 5633            }
 5634        }
 5635    }
 5636
 5637    pub async fn open_project_transaction(
 5638        this: &WeakEntity<Editor>,
 5639        workspace: WeakEntity<Workspace>,
 5640        transaction: ProjectTransaction,
 5641        title: String,
 5642        cx: &mut AsyncWindowContext,
 5643    ) -> Result<()> {
 5644        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5645        cx.update(|_, cx| {
 5646            entries.sort_unstable_by_key(|(buffer, _)| {
 5647                buffer.read(cx).file().map(|f| f.path().clone())
 5648            });
 5649        })?;
 5650
 5651        // If the project transaction's edits are all contained within this editor, then
 5652        // avoid opening a new editor to display them.
 5653
 5654        if let Some((buffer, transaction)) = entries.first() {
 5655            if entries.len() == 1 {
 5656                let excerpt = this.update(cx, |editor, cx| {
 5657                    editor
 5658                        .buffer()
 5659                        .read(cx)
 5660                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5661                })?;
 5662                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5663                    if excerpted_buffer == *buffer {
 5664                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5665                            let excerpt_range = excerpt_range.to_offset(buffer);
 5666                            buffer
 5667                                .edited_ranges_for_transaction::<usize>(transaction)
 5668                                .all(|range| {
 5669                                    excerpt_range.start <= range.start
 5670                                        && excerpt_range.end >= range.end
 5671                                })
 5672                        })?;
 5673
 5674                        if all_edits_within_excerpt {
 5675                            return Ok(());
 5676                        }
 5677                    }
 5678                }
 5679            }
 5680        } else {
 5681            return Ok(());
 5682        }
 5683
 5684        let mut ranges_to_highlight = Vec::new();
 5685        let excerpt_buffer = cx.new(|cx| {
 5686            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5687            for (buffer_handle, transaction) in &entries {
 5688                let edited_ranges = buffer_handle
 5689                    .read(cx)
 5690                    .edited_ranges_for_transaction::<Point>(transaction)
 5691                    .collect::<Vec<_>>();
 5692                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5693                    PathKey::for_buffer(buffer_handle, cx),
 5694                    buffer_handle.clone(),
 5695                    edited_ranges,
 5696                    DEFAULT_MULTIBUFFER_CONTEXT,
 5697                    cx,
 5698                );
 5699
 5700                ranges_to_highlight.extend(ranges);
 5701            }
 5702            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5703            multibuffer
 5704        })?;
 5705
 5706        workspace.update_in(cx, |workspace, window, cx| {
 5707            let project = workspace.project().clone();
 5708            let editor =
 5709                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5710            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5711            editor.update(cx, |editor, cx| {
 5712                editor.highlight_background::<Self>(
 5713                    &ranges_to_highlight,
 5714                    |theme| theme.editor_highlighted_line_background,
 5715                    cx,
 5716                );
 5717            });
 5718        })?;
 5719
 5720        Ok(())
 5721    }
 5722
 5723    pub fn clear_code_action_providers(&mut self) {
 5724        self.code_action_providers.clear();
 5725        self.available_code_actions.take();
 5726    }
 5727
 5728    pub fn add_code_action_provider(
 5729        &mut self,
 5730        provider: Rc<dyn CodeActionProvider>,
 5731        window: &mut Window,
 5732        cx: &mut Context<Self>,
 5733    ) {
 5734        if self
 5735            .code_action_providers
 5736            .iter()
 5737            .any(|existing_provider| existing_provider.id() == provider.id())
 5738        {
 5739            return;
 5740        }
 5741
 5742        self.code_action_providers.push(provider);
 5743        self.refresh_code_actions(window, cx);
 5744    }
 5745
 5746    pub fn remove_code_action_provider(
 5747        &mut self,
 5748        id: Arc<str>,
 5749        window: &mut Window,
 5750        cx: &mut Context<Self>,
 5751    ) {
 5752        self.code_action_providers
 5753            .retain(|provider| provider.id() != id);
 5754        self.refresh_code_actions(window, cx);
 5755    }
 5756
 5757    pub fn code_actions_enabled(&self, cx: &App) -> bool {
 5758        !self.code_action_providers.is_empty()
 5759            && EditorSettings::get_global(cx).toolbar.code_actions
 5760    }
 5761
 5762    pub fn has_available_code_actions(&self) -> bool {
 5763        self.available_code_actions
 5764            .as_ref()
 5765            .is_some_and(|(_, actions)| !actions.is_empty())
 5766    }
 5767
 5768    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 5769        &self.context_menu
 5770    }
 5771
 5772    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5773        let newest_selection = self.selections.newest_anchor().clone();
 5774        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5775        let buffer = self.buffer.read(cx);
 5776        if newest_selection.head().diff_base_anchor.is_some() {
 5777            return None;
 5778        }
 5779        let (start_buffer, start) =
 5780            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5781        let (end_buffer, end) =
 5782            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5783        if start_buffer != end_buffer {
 5784            return None;
 5785        }
 5786
 5787        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5788            cx.background_executor()
 5789                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5790                .await;
 5791
 5792            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5793                let providers = this.code_action_providers.clone();
 5794                let tasks = this
 5795                    .code_action_providers
 5796                    .iter()
 5797                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5798                    .collect::<Vec<_>>();
 5799                (providers, tasks)
 5800            })?;
 5801
 5802            let mut actions = Vec::new();
 5803            for (provider, provider_actions) in
 5804                providers.into_iter().zip(future::join_all(tasks).await)
 5805            {
 5806                if let Some(provider_actions) = provider_actions.log_err() {
 5807                    actions.extend(provider_actions.into_iter().map(|action| {
 5808                        AvailableCodeAction {
 5809                            excerpt_id: newest_selection.start.excerpt_id,
 5810                            action,
 5811                            provider: provider.clone(),
 5812                        }
 5813                    }));
 5814                }
 5815            }
 5816
 5817            this.update(cx, |this, cx| {
 5818                this.available_code_actions = if actions.is_empty() {
 5819                    None
 5820                } else {
 5821                    Some((
 5822                        Location {
 5823                            buffer: start_buffer,
 5824                            range: start..end,
 5825                        },
 5826                        actions.into(),
 5827                    ))
 5828                };
 5829                cx.notify();
 5830            })
 5831        }));
 5832        None
 5833    }
 5834
 5835    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5836        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5837            self.show_git_blame_inline = false;
 5838
 5839            self.show_git_blame_inline_delay_task =
 5840                Some(cx.spawn_in(window, async move |this, cx| {
 5841                    cx.background_executor().timer(delay).await;
 5842
 5843                    this.update(cx, |this, cx| {
 5844                        this.show_git_blame_inline = true;
 5845                        cx.notify();
 5846                    })
 5847                    .log_err();
 5848                }));
 5849        }
 5850    }
 5851
 5852    fn show_blame_popover(
 5853        &mut self,
 5854        blame_entry: &BlameEntry,
 5855        position: gpui::Point<Pixels>,
 5856        cx: &mut Context<Self>,
 5857    ) {
 5858        if let Some(state) = &mut self.inline_blame_popover {
 5859            state.hide_task.take();
 5860            cx.notify();
 5861        } else {
 5862            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5863            let show_task = cx.spawn(async move |editor, cx| {
 5864                cx.background_executor()
 5865                    .timer(std::time::Duration::from_millis(delay))
 5866                    .await;
 5867                editor
 5868                    .update(cx, |editor, cx| {
 5869                        if let Some(state) = &mut editor.inline_blame_popover {
 5870                            state.show_task = None;
 5871                            cx.notify();
 5872                        }
 5873                    })
 5874                    .ok();
 5875            });
 5876            let Some(blame) = self.blame.as_ref() else {
 5877                return;
 5878            };
 5879            let blame = blame.read(cx);
 5880            let details = blame.details_for_entry(&blame_entry);
 5881            let markdown = cx.new(|cx| {
 5882                Markdown::new(
 5883                    details
 5884                        .as_ref()
 5885                        .map(|message| message.message.clone())
 5886                        .unwrap_or_default(),
 5887                    None,
 5888                    None,
 5889                    cx,
 5890                )
 5891            });
 5892            self.inline_blame_popover = Some(InlineBlamePopover {
 5893                position,
 5894                show_task: Some(show_task),
 5895                hide_task: None,
 5896                popover_bounds: None,
 5897                popover_state: InlineBlamePopoverState {
 5898                    scroll_handle: ScrollHandle::new(),
 5899                    commit_message: details,
 5900                    markdown,
 5901                },
 5902            });
 5903        }
 5904    }
 5905
 5906    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5907        if let Some(state) = &mut self.inline_blame_popover {
 5908            if state.show_task.is_some() {
 5909                self.inline_blame_popover.take();
 5910                cx.notify();
 5911            } else {
 5912                let hide_task = cx.spawn(async move |editor, cx| {
 5913                    cx.background_executor()
 5914                        .timer(std::time::Duration::from_millis(100))
 5915                        .await;
 5916                    editor
 5917                        .update(cx, |editor, cx| {
 5918                            editor.inline_blame_popover.take();
 5919                            cx.notify();
 5920                        })
 5921                        .ok();
 5922                });
 5923                state.hide_task = Some(hide_task);
 5924            }
 5925        }
 5926    }
 5927
 5928    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5929        if self.pending_rename.is_some() {
 5930            return None;
 5931        }
 5932
 5933        let provider = self.semantics_provider.clone()?;
 5934        let buffer = self.buffer.read(cx);
 5935        let newest_selection = self.selections.newest_anchor().clone();
 5936        let cursor_position = newest_selection.head();
 5937        let (cursor_buffer, cursor_buffer_position) =
 5938            buffer.text_anchor_for_position(cursor_position, cx)?;
 5939        let (tail_buffer, tail_buffer_position) =
 5940            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5941        if cursor_buffer != tail_buffer {
 5942            return None;
 5943        }
 5944
 5945        let snapshot = cursor_buffer.read(cx).snapshot();
 5946        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5947        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5948        if start_word_range != end_word_range {
 5949            self.document_highlights_task.take();
 5950            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5951            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5952            return None;
 5953        }
 5954
 5955        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5956        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5957            cx.background_executor()
 5958                .timer(Duration::from_millis(debounce))
 5959                .await;
 5960
 5961            let highlights = if let Some(highlights) = cx
 5962                .update(|cx| {
 5963                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5964                })
 5965                .ok()
 5966                .flatten()
 5967            {
 5968                highlights.await.log_err()
 5969            } else {
 5970                None
 5971            };
 5972
 5973            if let Some(highlights) = highlights {
 5974                this.update(cx, |this, cx| {
 5975                    if this.pending_rename.is_some() {
 5976                        return;
 5977                    }
 5978
 5979                    let buffer_id = cursor_position.buffer_id;
 5980                    let buffer = this.buffer.read(cx);
 5981                    if !buffer
 5982                        .text_anchor_for_position(cursor_position, cx)
 5983                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5984                    {
 5985                        return;
 5986                    }
 5987
 5988                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5989                    let mut write_ranges = Vec::new();
 5990                    let mut read_ranges = Vec::new();
 5991                    for highlight in highlights {
 5992                        for (excerpt_id, excerpt_range) in
 5993                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5994                        {
 5995                            let start = highlight
 5996                                .range
 5997                                .start
 5998                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5999                            let end = highlight
 6000                                .range
 6001                                .end
 6002                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6003                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6004                                continue;
 6005                            }
 6006
 6007                            let range = Anchor {
 6008                                buffer_id,
 6009                                excerpt_id,
 6010                                text_anchor: start,
 6011                                diff_base_anchor: None,
 6012                            }..Anchor {
 6013                                buffer_id,
 6014                                excerpt_id,
 6015                                text_anchor: end,
 6016                                diff_base_anchor: None,
 6017                            };
 6018                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6019                                write_ranges.push(range);
 6020                            } else {
 6021                                read_ranges.push(range);
 6022                            }
 6023                        }
 6024                    }
 6025
 6026                    this.highlight_background::<DocumentHighlightRead>(
 6027                        &read_ranges,
 6028                        |theme| theme.editor_document_highlight_read_background,
 6029                        cx,
 6030                    );
 6031                    this.highlight_background::<DocumentHighlightWrite>(
 6032                        &write_ranges,
 6033                        |theme| theme.editor_document_highlight_write_background,
 6034                        cx,
 6035                    );
 6036                    cx.notify();
 6037                })
 6038                .log_err();
 6039            }
 6040        }));
 6041        None
 6042    }
 6043
 6044    fn prepare_highlight_query_from_selection(
 6045        &mut self,
 6046        cx: &mut Context<Editor>,
 6047    ) -> Option<(String, Range<Anchor>)> {
 6048        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6049            return None;
 6050        }
 6051        if !EditorSettings::get_global(cx).selection_highlight {
 6052            return None;
 6053        }
 6054        if self.selections.count() != 1 || self.selections.line_mode {
 6055            return None;
 6056        }
 6057        let selection = self.selections.newest::<Point>(cx);
 6058        if selection.is_empty() || selection.start.row != selection.end.row {
 6059            return None;
 6060        }
 6061        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6062        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6063        let query = multi_buffer_snapshot
 6064            .text_for_range(selection_anchor_range.clone())
 6065            .collect::<String>();
 6066        if query.trim().is_empty() {
 6067            return None;
 6068        }
 6069        Some((query, selection_anchor_range))
 6070    }
 6071
 6072    fn update_selection_occurrence_highlights(
 6073        &mut self,
 6074        query_text: String,
 6075        query_range: Range<Anchor>,
 6076        multi_buffer_range_to_query: Range<Point>,
 6077        use_debounce: bool,
 6078        window: &mut Window,
 6079        cx: &mut Context<Editor>,
 6080    ) -> Task<()> {
 6081        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6082        cx.spawn_in(window, async move |editor, cx| {
 6083            if use_debounce {
 6084                cx.background_executor()
 6085                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6086                    .await;
 6087            }
 6088            let match_task = cx.background_spawn(async move {
 6089                let buffer_ranges = multi_buffer_snapshot
 6090                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6091                    .into_iter()
 6092                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6093                let mut match_ranges = Vec::new();
 6094                let Ok(regex) = project::search::SearchQuery::text(
 6095                    query_text.clone(),
 6096                    false,
 6097                    false,
 6098                    false,
 6099                    Default::default(),
 6100                    Default::default(),
 6101                    false,
 6102                    None,
 6103                ) else {
 6104                    return Vec::default();
 6105                };
 6106                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6107                    match_ranges.extend(
 6108                        regex
 6109                            .search(&buffer_snapshot, Some(search_range.clone()))
 6110                            .await
 6111                            .into_iter()
 6112                            .filter_map(|match_range| {
 6113                                let match_start = buffer_snapshot
 6114                                    .anchor_after(search_range.start + match_range.start);
 6115                                let match_end = buffer_snapshot
 6116                                    .anchor_before(search_range.start + match_range.end);
 6117                                let match_anchor_range = Anchor::range_in_buffer(
 6118                                    excerpt_id,
 6119                                    buffer_snapshot.remote_id(),
 6120                                    match_start..match_end,
 6121                                );
 6122                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6123                            }),
 6124                    );
 6125                }
 6126                match_ranges
 6127            });
 6128            let match_ranges = match_task.await;
 6129            editor
 6130                .update_in(cx, |editor, _, cx| {
 6131                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6132                    if !match_ranges.is_empty() {
 6133                        editor.highlight_background::<SelectedTextHighlight>(
 6134                            &match_ranges,
 6135                            |theme| theme.editor_document_highlight_bracket_background,
 6136                            cx,
 6137                        )
 6138                    }
 6139                })
 6140                .log_err();
 6141        })
 6142    }
 6143
 6144    fn refresh_selected_text_highlights(
 6145        &mut self,
 6146        on_buffer_edit: bool,
 6147        window: &mut Window,
 6148        cx: &mut Context<Editor>,
 6149    ) {
 6150        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6151        else {
 6152            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6153            self.quick_selection_highlight_task.take();
 6154            self.debounced_selection_highlight_task.take();
 6155            return;
 6156        };
 6157        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6158        if on_buffer_edit
 6159            || self
 6160                .quick_selection_highlight_task
 6161                .as_ref()
 6162                .map_or(true, |(prev_anchor_range, _)| {
 6163                    prev_anchor_range != &query_range
 6164                })
 6165        {
 6166            let multi_buffer_visible_start = self
 6167                .scroll_manager
 6168                .anchor()
 6169                .anchor
 6170                .to_point(&multi_buffer_snapshot);
 6171            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6172                multi_buffer_visible_start
 6173                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6174                Bias::Left,
 6175            );
 6176            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6177            self.quick_selection_highlight_task = Some((
 6178                query_range.clone(),
 6179                self.update_selection_occurrence_highlights(
 6180                    query_text.clone(),
 6181                    query_range.clone(),
 6182                    multi_buffer_visible_range,
 6183                    false,
 6184                    window,
 6185                    cx,
 6186                ),
 6187            ));
 6188        }
 6189        if on_buffer_edit
 6190            || self
 6191                .debounced_selection_highlight_task
 6192                .as_ref()
 6193                .map_or(true, |(prev_anchor_range, _)| {
 6194                    prev_anchor_range != &query_range
 6195                })
 6196        {
 6197            let multi_buffer_start = multi_buffer_snapshot
 6198                .anchor_before(0)
 6199                .to_point(&multi_buffer_snapshot);
 6200            let multi_buffer_end = multi_buffer_snapshot
 6201                .anchor_after(multi_buffer_snapshot.len())
 6202                .to_point(&multi_buffer_snapshot);
 6203            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6204            self.debounced_selection_highlight_task = Some((
 6205                query_range.clone(),
 6206                self.update_selection_occurrence_highlights(
 6207                    query_text,
 6208                    query_range,
 6209                    multi_buffer_full_range,
 6210                    true,
 6211                    window,
 6212                    cx,
 6213                ),
 6214            ));
 6215        }
 6216    }
 6217
 6218    pub fn refresh_inline_completion(
 6219        &mut self,
 6220        debounce: bool,
 6221        user_requested: bool,
 6222        window: &mut Window,
 6223        cx: &mut Context<Self>,
 6224    ) -> Option<()> {
 6225        let provider = self.edit_prediction_provider()?;
 6226        let cursor = self.selections.newest_anchor().head();
 6227        let (buffer, cursor_buffer_position) =
 6228            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6229
 6230        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6231            self.discard_inline_completion(false, cx);
 6232            return None;
 6233        }
 6234
 6235        if !user_requested
 6236            && (!self.should_show_edit_predictions()
 6237                || !self.is_focused(window)
 6238                || buffer.read(cx).is_empty())
 6239        {
 6240            self.discard_inline_completion(false, cx);
 6241            return None;
 6242        }
 6243
 6244        self.update_visible_inline_completion(window, cx);
 6245        provider.refresh(
 6246            self.project.clone(),
 6247            buffer,
 6248            cursor_buffer_position,
 6249            debounce,
 6250            cx,
 6251        );
 6252        Some(())
 6253    }
 6254
 6255    fn show_edit_predictions_in_menu(&self) -> bool {
 6256        match self.edit_prediction_settings {
 6257            EditPredictionSettings::Disabled => false,
 6258            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6259        }
 6260    }
 6261
 6262    pub fn edit_predictions_enabled(&self) -> bool {
 6263        match self.edit_prediction_settings {
 6264            EditPredictionSettings::Disabled => false,
 6265            EditPredictionSettings::Enabled { .. } => true,
 6266        }
 6267    }
 6268
 6269    fn edit_prediction_requires_modifier(&self) -> bool {
 6270        match self.edit_prediction_settings {
 6271            EditPredictionSettings::Disabled => false,
 6272            EditPredictionSettings::Enabled {
 6273                preview_requires_modifier,
 6274                ..
 6275            } => preview_requires_modifier,
 6276        }
 6277    }
 6278
 6279    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6280        if self.edit_prediction_provider.is_none() {
 6281            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6282        } else {
 6283            let selection = self.selections.newest_anchor();
 6284            let cursor = selection.head();
 6285
 6286            if let Some((buffer, cursor_buffer_position)) =
 6287                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6288            {
 6289                self.edit_prediction_settings =
 6290                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6291            }
 6292        }
 6293    }
 6294
 6295    fn edit_prediction_settings_at_position(
 6296        &self,
 6297        buffer: &Entity<Buffer>,
 6298        buffer_position: language::Anchor,
 6299        cx: &App,
 6300    ) -> EditPredictionSettings {
 6301        if !self.mode.is_full()
 6302            || !self.show_inline_completions_override.unwrap_or(true)
 6303            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6304        {
 6305            return EditPredictionSettings::Disabled;
 6306        }
 6307
 6308        let buffer = buffer.read(cx);
 6309
 6310        let file = buffer.file();
 6311
 6312        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6313            return EditPredictionSettings::Disabled;
 6314        };
 6315
 6316        let by_provider = matches!(
 6317            self.menu_inline_completions_policy,
 6318            MenuInlineCompletionsPolicy::ByProvider
 6319        );
 6320
 6321        let show_in_menu = by_provider
 6322            && self
 6323                .edit_prediction_provider
 6324                .as_ref()
 6325                .map_or(false, |provider| {
 6326                    provider.provider.show_completions_in_menu()
 6327                });
 6328
 6329        let preview_requires_modifier =
 6330            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6331
 6332        EditPredictionSettings::Enabled {
 6333            show_in_menu,
 6334            preview_requires_modifier,
 6335        }
 6336    }
 6337
 6338    fn should_show_edit_predictions(&self) -> bool {
 6339        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6340    }
 6341
 6342    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6343        matches!(
 6344            self.edit_prediction_preview,
 6345            EditPredictionPreview::Active { .. }
 6346        )
 6347    }
 6348
 6349    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6350        let cursor = self.selections.newest_anchor().head();
 6351        if let Some((buffer, cursor_position)) =
 6352            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6353        {
 6354            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6355        } else {
 6356            false
 6357        }
 6358    }
 6359
 6360    pub fn supports_minimap(&self, cx: &App) -> bool {
 6361        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6362    }
 6363
 6364    fn edit_predictions_enabled_in_buffer(
 6365        &self,
 6366        buffer: &Entity<Buffer>,
 6367        buffer_position: language::Anchor,
 6368        cx: &App,
 6369    ) -> bool {
 6370        maybe!({
 6371            if self.read_only(cx) {
 6372                return Some(false);
 6373            }
 6374            let provider = self.edit_prediction_provider()?;
 6375            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6376                return Some(false);
 6377            }
 6378            let buffer = buffer.read(cx);
 6379            let Some(file) = buffer.file() else {
 6380                return Some(true);
 6381            };
 6382            let settings = all_language_settings(Some(file), cx);
 6383            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6384        })
 6385        .unwrap_or(false)
 6386    }
 6387
 6388    fn cycle_inline_completion(
 6389        &mut self,
 6390        direction: Direction,
 6391        window: &mut Window,
 6392        cx: &mut Context<Self>,
 6393    ) -> Option<()> {
 6394        let provider = self.edit_prediction_provider()?;
 6395        let cursor = self.selections.newest_anchor().head();
 6396        let (buffer, cursor_buffer_position) =
 6397            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6398        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6399            return None;
 6400        }
 6401
 6402        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6403        self.update_visible_inline_completion(window, cx);
 6404
 6405        Some(())
 6406    }
 6407
 6408    pub fn show_inline_completion(
 6409        &mut self,
 6410        _: &ShowEditPrediction,
 6411        window: &mut Window,
 6412        cx: &mut Context<Self>,
 6413    ) {
 6414        if !self.has_active_inline_completion() {
 6415            self.refresh_inline_completion(false, true, window, cx);
 6416            return;
 6417        }
 6418
 6419        self.update_visible_inline_completion(window, cx);
 6420    }
 6421
 6422    pub fn display_cursor_names(
 6423        &mut self,
 6424        _: &DisplayCursorNames,
 6425        window: &mut Window,
 6426        cx: &mut Context<Self>,
 6427    ) {
 6428        self.show_cursor_names(window, cx);
 6429    }
 6430
 6431    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6432        self.show_cursor_names = true;
 6433        cx.notify();
 6434        cx.spawn_in(window, async move |this, cx| {
 6435            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6436            this.update(cx, |this, cx| {
 6437                this.show_cursor_names = false;
 6438                cx.notify()
 6439            })
 6440            .ok()
 6441        })
 6442        .detach();
 6443    }
 6444
 6445    pub fn next_edit_prediction(
 6446        &mut self,
 6447        _: &NextEditPrediction,
 6448        window: &mut Window,
 6449        cx: &mut Context<Self>,
 6450    ) {
 6451        if self.has_active_inline_completion() {
 6452            self.cycle_inline_completion(Direction::Next, window, cx);
 6453        } else {
 6454            let is_copilot_disabled = self
 6455                .refresh_inline_completion(false, true, window, cx)
 6456                .is_none();
 6457            if is_copilot_disabled {
 6458                cx.propagate();
 6459            }
 6460        }
 6461    }
 6462
 6463    pub fn previous_edit_prediction(
 6464        &mut self,
 6465        _: &PreviousEditPrediction,
 6466        window: &mut Window,
 6467        cx: &mut Context<Self>,
 6468    ) {
 6469        if self.has_active_inline_completion() {
 6470            self.cycle_inline_completion(Direction::Prev, window, cx);
 6471        } else {
 6472            let is_copilot_disabled = self
 6473                .refresh_inline_completion(false, true, window, cx)
 6474                .is_none();
 6475            if is_copilot_disabled {
 6476                cx.propagate();
 6477            }
 6478        }
 6479    }
 6480
 6481    pub fn accept_edit_prediction(
 6482        &mut self,
 6483        _: &AcceptEditPrediction,
 6484        window: &mut Window,
 6485        cx: &mut Context<Self>,
 6486    ) {
 6487        if self.show_edit_predictions_in_menu() {
 6488            self.hide_context_menu(window, cx);
 6489        }
 6490
 6491        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6492            return;
 6493        };
 6494
 6495        self.report_inline_completion_event(
 6496            active_inline_completion.completion_id.clone(),
 6497            true,
 6498            cx,
 6499        );
 6500
 6501        match &active_inline_completion.completion {
 6502            InlineCompletion::Move { target, .. } => {
 6503                let target = *target;
 6504
 6505                if let Some(position_map) = &self.last_position_map {
 6506                    if position_map
 6507                        .visible_row_range
 6508                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6509                        || !self.edit_prediction_requires_modifier()
 6510                    {
 6511                        self.unfold_ranges(&[target..target], true, false, cx);
 6512                        // Note that this is also done in vim's handler of the Tab action.
 6513                        self.change_selections(
 6514                            Some(Autoscroll::newest()),
 6515                            window,
 6516                            cx,
 6517                            |selections| {
 6518                                selections.select_anchor_ranges([target..target]);
 6519                            },
 6520                        );
 6521                        self.clear_row_highlights::<EditPredictionPreview>();
 6522
 6523                        self.edit_prediction_preview
 6524                            .set_previous_scroll_position(None);
 6525                    } else {
 6526                        self.edit_prediction_preview
 6527                            .set_previous_scroll_position(Some(
 6528                                position_map.snapshot.scroll_anchor,
 6529                            ));
 6530
 6531                        self.highlight_rows::<EditPredictionPreview>(
 6532                            target..target,
 6533                            cx.theme().colors().editor_highlighted_line_background,
 6534                            RowHighlightOptions {
 6535                                autoscroll: true,
 6536                                ..Default::default()
 6537                            },
 6538                            cx,
 6539                        );
 6540                        self.request_autoscroll(Autoscroll::fit(), cx);
 6541                    }
 6542                }
 6543            }
 6544            InlineCompletion::Edit { edits, .. } => {
 6545                if let Some(provider) = self.edit_prediction_provider() {
 6546                    provider.accept(cx);
 6547                }
 6548
 6549                let snapshot = self.buffer.read(cx).snapshot(cx);
 6550                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6551
 6552                self.buffer.update(cx, |buffer, cx| {
 6553                    buffer.edit(edits.iter().cloned(), None, cx)
 6554                });
 6555
 6556                self.change_selections(None, window, cx, |s| {
 6557                    s.select_anchor_ranges([last_edit_end..last_edit_end])
 6558                });
 6559
 6560                self.update_visible_inline_completion(window, cx);
 6561                if self.active_inline_completion.is_none() {
 6562                    self.refresh_inline_completion(true, true, window, cx);
 6563                }
 6564
 6565                cx.notify();
 6566            }
 6567        }
 6568
 6569        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6570    }
 6571
 6572    pub fn accept_partial_inline_completion(
 6573        &mut self,
 6574        _: &AcceptPartialEditPrediction,
 6575        window: &mut Window,
 6576        cx: &mut Context<Self>,
 6577    ) {
 6578        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6579            return;
 6580        };
 6581        if self.selections.count() != 1 {
 6582            return;
 6583        }
 6584
 6585        self.report_inline_completion_event(
 6586            active_inline_completion.completion_id.clone(),
 6587            true,
 6588            cx,
 6589        );
 6590
 6591        match &active_inline_completion.completion {
 6592            InlineCompletion::Move { target, .. } => {
 6593                let target = *target;
 6594                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6595                    selections.select_anchor_ranges([target..target]);
 6596                });
 6597            }
 6598            InlineCompletion::Edit { edits, .. } => {
 6599                // Find an insertion that starts at the cursor position.
 6600                let snapshot = self.buffer.read(cx).snapshot(cx);
 6601                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6602                let insertion = edits.iter().find_map(|(range, text)| {
 6603                    let range = range.to_offset(&snapshot);
 6604                    if range.is_empty() && range.start == cursor_offset {
 6605                        Some(text)
 6606                    } else {
 6607                        None
 6608                    }
 6609                });
 6610
 6611                if let Some(text) = insertion {
 6612                    let mut partial_completion = text
 6613                        .chars()
 6614                        .by_ref()
 6615                        .take_while(|c| c.is_alphabetic())
 6616                        .collect::<String>();
 6617                    if partial_completion.is_empty() {
 6618                        partial_completion = text
 6619                            .chars()
 6620                            .by_ref()
 6621                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6622                            .collect::<String>();
 6623                    }
 6624
 6625                    cx.emit(EditorEvent::InputHandled {
 6626                        utf16_range_to_replace: None,
 6627                        text: partial_completion.clone().into(),
 6628                    });
 6629
 6630                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6631
 6632                    self.refresh_inline_completion(true, true, window, cx);
 6633                    cx.notify();
 6634                } else {
 6635                    self.accept_edit_prediction(&Default::default(), window, cx);
 6636                }
 6637            }
 6638        }
 6639    }
 6640
 6641    fn discard_inline_completion(
 6642        &mut self,
 6643        should_report_inline_completion_event: bool,
 6644        cx: &mut Context<Self>,
 6645    ) -> bool {
 6646        if should_report_inline_completion_event {
 6647            let completion_id = self
 6648                .active_inline_completion
 6649                .as_ref()
 6650                .and_then(|active_completion| active_completion.completion_id.clone());
 6651
 6652            self.report_inline_completion_event(completion_id, false, cx);
 6653        }
 6654
 6655        if let Some(provider) = self.edit_prediction_provider() {
 6656            provider.discard(cx);
 6657        }
 6658
 6659        self.take_active_inline_completion(cx)
 6660    }
 6661
 6662    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6663        let Some(provider) = self.edit_prediction_provider() else {
 6664            return;
 6665        };
 6666
 6667        let Some((_, buffer, _)) = self
 6668            .buffer
 6669            .read(cx)
 6670            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6671        else {
 6672            return;
 6673        };
 6674
 6675        let extension = buffer
 6676            .read(cx)
 6677            .file()
 6678            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6679
 6680        let event_type = match accepted {
 6681            true => "Edit Prediction Accepted",
 6682            false => "Edit Prediction Discarded",
 6683        };
 6684        telemetry::event!(
 6685            event_type,
 6686            provider = provider.name(),
 6687            prediction_id = id,
 6688            suggestion_accepted = accepted,
 6689            file_extension = extension,
 6690        );
 6691    }
 6692
 6693    pub fn has_active_inline_completion(&self) -> bool {
 6694        self.active_inline_completion.is_some()
 6695    }
 6696
 6697    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6698        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6699            return false;
 6700        };
 6701
 6702        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6703        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6704        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6705        true
 6706    }
 6707
 6708    /// Returns true when we're displaying the edit prediction popover below the cursor
 6709    /// like we are not previewing and the LSP autocomplete menu is visible
 6710    /// or we are in `when_holding_modifier` mode.
 6711    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6712        if self.edit_prediction_preview_is_active()
 6713            || !self.show_edit_predictions_in_menu()
 6714            || !self.edit_predictions_enabled()
 6715        {
 6716            return false;
 6717        }
 6718
 6719        if self.has_visible_completions_menu() {
 6720            return true;
 6721        }
 6722
 6723        has_completion && self.edit_prediction_requires_modifier()
 6724    }
 6725
 6726    fn handle_modifiers_changed(
 6727        &mut self,
 6728        modifiers: Modifiers,
 6729        position_map: &PositionMap,
 6730        window: &mut Window,
 6731        cx: &mut Context<Self>,
 6732    ) {
 6733        if self.show_edit_predictions_in_menu() {
 6734            self.update_edit_prediction_preview(&modifiers, window, cx);
 6735        }
 6736
 6737        self.update_selection_mode(&modifiers, position_map, window, cx);
 6738
 6739        let mouse_position = window.mouse_position();
 6740        if !position_map.text_hitbox.is_hovered(window) {
 6741            return;
 6742        }
 6743
 6744        self.update_hovered_link(
 6745            position_map.point_for_position(mouse_position),
 6746            &position_map.snapshot,
 6747            modifiers,
 6748            window,
 6749            cx,
 6750        )
 6751    }
 6752
 6753    fn update_selection_mode(
 6754        &mut self,
 6755        modifiers: &Modifiers,
 6756        position_map: &PositionMap,
 6757        window: &mut Window,
 6758        cx: &mut Context<Self>,
 6759    ) {
 6760        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6761            return;
 6762        }
 6763
 6764        let mouse_position = window.mouse_position();
 6765        let point_for_position = position_map.point_for_position(mouse_position);
 6766        let position = point_for_position.previous_valid;
 6767
 6768        self.select(
 6769            SelectPhase::BeginColumnar {
 6770                position,
 6771                reset: false,
 6772                goal_column: point_for_position.exact_unclipped.column(),
 6773            },
 6774            window,
 6775            cx,
 6776        );
 6777    }
 6778
 6779    fn update_edit_prediction_preview(
 6780        &mut self,
 6781        modifiers: &Modifiers,
 6782        window: &mut Window,
 6783        cx: &mut Context<Self>,
 6784    ) {
 6785        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6786        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6787            return;
 6788        };
 6789
 6790        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6791            if matches!(
 6792                self.edit_prediction_preview,
 6793                EditPredictionPreview::Inactive { .. }
 6794            ) {
 6795                self.edit_prediction_preview = EditPredictionPreview::Active {
 6796                    previous_scroll_position: None,
 6797                    since: Instant::now(),
 6798                };
 6799
 6800                self.update_visible_inline_completion(window, cx);
 6801                cx.notify();
 6802            }
 6803        } else if let EditPredictionPreview::Active {
 6804            previous_scroll_position,
 6805            since,
 6806        } = self.edit_prediction_preview
 6807        {
 6808            if let (Some(previous_scroll_position), Some(position_map)) =
 6809                (previous_scroll_position, self.last_position_map.as_ref())
 6810            {
 6811                self.set_scroll_position(
 6812                    previous_scroll_position
 6813                        .scroll_position(&position_map.snapshot.display_snapshot),
 6814                    window,
 6815                    cx,
 6816                );
 6817            }
 6818
 6819            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6820                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6821            };
 6822            self.clear_row_highlights::<EditPredictionPreview>();
 6823            self.update_visible_inline_completion(window, cx);
 6824            cx.notify();
 6825        }
 6826    }
 6827
 6828    fn update_visible_inline_completion(
 6829        &mut self,
 6830        _window: &mut Window,
 6831        cx: &mut Context<Self>,
 6832    ) -> Option<()> {
 6833        let selection = self.selections.newest_anchor();
 6834        let cursor = selection.head();
 6835        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6836        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6837        let excerpt_id = cursor.excerpt_id;
 6838
 6839        let show_in_menu = self.show_edit_predictions_in_menu();
 6840        let completions_menu_has_precedence = !show_in_menu
 6841            && (self.context_menu.borrow().is_some()
 6842                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6843
 6844        if completions_menu_has_precedence
 6845            || !offset_selection.is_empty()
 6846            || self
 6847                .active_inline_completion
 6848                .as_ref()
 6849                .map_or(false, |completion| {
 6850                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6851                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6852                    !invalidation_range.contains(&offset_selection.head())
 6853                })
 6854        {
 6855            self.discard_inline_completion(false, cx);
 6856            return None;
 6857        }
 6858
 6859        self.take_active_inline_completion(cx);
 6860        let Some(provider) = self.edit_prediction_provider() else {
 6861            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6862            return None;
 6863        };
 6864
 6865        let (buffer, cursor_buffer_position) =
 6866            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6867
 6868        self.edit_prediction_settings =
 6869            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6870
 6871        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6872
 6873        if self.edit_prediction_indent_conflict {
 6874            let cursor_point = cursor.to_point(&multibuffer);
 6875
 6876            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6877
 6878            if let Some((_, indent)) = indents.iter().next() {
 6879                if indent.len == cursor_point.column {
 6880                    self.edit_prediction_indent_conflict = false;
 6881                }
 6882            }
 6883        }
 6884
 6885        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6886        let edits = inline_completion
 6887            .edits
 6888            .into_iter()
 6889            .flat_map(|(range, new_text)| {
 6890                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6891                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6892                Some((start..end, new_text))
 6893            })
 6894            .collect::<Vec<_>>();
 6895        if edits.is_empty() {
 6896            return None;
 6897        }
 6898
 6899        let first_edit_start = edits.first().unwrap().0.start;
 6900        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6901        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6902
 6903        let last_edit_end = edits.last().unwrap().0.end;
 6904        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6905        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6906
 6907        let cursor_row = cursor.to_point(&multibuffer).row;
 6908
 6909        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6910
 6911        let mut inlay_ids = Vec::new();
 6912        let invalidation_row_range;
 6913        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6914            Some(cursor_row..edit_end_row)
 6915        } else if cursor_row > edit_end_row {
 6916            Some(edit_start_row..cursor_row)
 6917        } else {
 6918            None
 6919        };
 6920        let is_move =
 6921            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6922        let completion = if is_move {
 6923            invalidation_row_range =
 6924                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6925            let target = first_edit_start;
 6926            InlineCompletion::Move { target, snapshot }
 6927        } else {
 6928            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6929                && !self.inline_completions_hidden_for_vim_mode;
 6930
 6931            if show_completions_in_buffer {
 6932                if edits
 6933                    .iter()
 6934                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6935                {
 6936                    let mut inlays = Vec::new();
 6937                    for (range, new_text) in &edits {
 6938                        let inlay = Inlay::inline_completion(
 6939                            post_inc(&mut self.next_inlay_id),
 6940                            range.start,
 6941                            new_text.as_str(),
 6942                        );
 6943                        inlay_ids.push(inlay.id);
 6944                        inlays.push(inlay);
 6945                    }
 6946
 6947                    self.splice_inlays(&[], inlays, cx);
 6948                } else {
 6949                    let background_color = cx.theme().status().deleted_background;
 6950                    self.highlight_text::<InlineCompletionHighlight>(
 6951                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6952                        HighlightStyle {
 6953                            background_color: Some(background_color),
 6954                            ..Default::default()
 6955                        },
 6956                        cx,
 6957                    );
 6958                }
 6959            }
 6960
 6961            invalidation_row_range = edit_start_row..edit_end_row;
 6962
 6963            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6964                if provider.show_tab_accept_marker() {
 6965                    EditDisplayMode::TabAccept
 6966                } else {
 6967                    EditDisplayMode::Inline
 6968                }
 6969            } else {
 6970                EditDisplayMode::DiffPopover
 6971            };
 6972
 6973            InlineCompletion::Edit {
 6974                edits,
 6975                edit_preview: inline_completion.edit_preview,
 6976                display_mode,
 6977                snapshot,
 6978            }
 6979        };
 6980
 6981        let invalidation_range = multibuffer
 6982            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6983            ..multibuffer.anchor_after(Point::new(
 6984                invalidation_row_range.end,
 6985                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6986            ));
 6987
 6988        self.stale_inline_completion_in_menu = None;
 6989        self.active_inline_completion = Some(InlineCompletionState {
 6990            inlay_ids,
 6991            completion,
 6992            completion_id: inline_completion.id,
 6993            invalidation_range,
 6994        });
 6995
 6996        cx.notify();
 6997
 6998        Some(())
 6999    }
 7000
 7001    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7002        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7003    }
 7004
 7005    fn clear_tasks(&mut self) {
 7006        self.tasks.clear()
 7007    }
 7008
 7009    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7010        if self.tasks.insert(key, value).is_some() {
 7011            // This case should hopefully be rare, but just in case...
 7012            log::error!(
 7013                "multiple different run targets found on a single line, only the last target will be rendered"
 7014            )
 7015        }
 7016    }
 7017
 7018    /// Get all display points of breakpoints that will be rendered within editor
 7019    ///
 7020    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7021    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7022    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7023    fn active_breakpoints(
 7024        &self,
 7025        range: Range<DisplayRow>,
 7026        window: &mut Window,
 7027        cx: &mut Context<Self>,
 7028    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7029        let mut breakpoint_display_points = HashMap::default();
 7030
 7031        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7032            return breakpoint_display_points;
 7033        };
 7034
 7035        let snapshot = self.snapshot(window, cx);
 7036
 7037        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7038        let Some(project) = self.project.as_ref() else {
 7039            return breakpoint_display_points;
 7040        };
 7041
 7042        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7043            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7044
 7045        for (buffer_snapshot, range, excerpt_id) in
 7046            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7047        {
 7048            let Some(buffer) = project.read_with(cx, |this, cx| {
 7049                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7050            }) else {
 7051                continue;
 7052            };
 7053            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7054                &buffer,
 7055                Some(
 7056                    buffer_snapshot.anchor_before(range.start)
 7057                        ..buffer_snapshot.anchor_after(range.end),
 7058                ),
 7059                buffer_snapshot,
 7060                cx,
 7061            );
 7062            for (breakpoint, state) in breakpoints {
 7063                let multi_buffer_anchor =
 7064                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7065                let position = multi_buffer_anchor
 7066                    .to_point(&multi_buffer_snapshot)
 7067                    .to_display_point(&snapshot);
 7068
 7069                breakpoint_display_points.insert(
 7070                    position.row(),
 7071                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7072                );
 7073            }
 7074        }
 7075
 7076        breakpoint_display_points
 7077    }
 7078
 7079    fn breakpoint_context_menu(
 7080        &self,
 7081        anchor: Anchor,
 7082        window: &mut Window,
 7083        cx: &mut Context<Self>,
 7084    ) -> Entity<ui::ContextMenu> {
 7085        let weak_editor = cx.weak_entity();
 7086        let focus_handle = self.focus_handle(cx);
 7087
 7088        let row = self
 7089            .buffer
 7090            .read(cx)
 7091            .snapshot(cx)
 7092            .summary_for_anchor::<Point>(&anchor)
 7093            .row;
 7094
 7095        let breakpoint = self
 7096            .breakpoint_at_row(row, window, cx)
 7097            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7098
 7099        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7100            "Edit Log Breakpoint"
 7101        } else {
 7102            "Set Log Breakpoint"
 7103        };
 7104
 7105        let condition_breakpoint_msg = if breakpoint
 7106            .as_ref()
 7107            .is_some_and(|bp| bp.1.condition.is_some())
 7108        {
 7109            "Edit Condition Breakpoint"
 7110        } else {
 7111            "Set Condition Breakpoint"
 7112        };
 7113
 7114        let hit_condition_breakpoint_msg = if breakpoint
 7115            .as_ref()
 7116            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7117        {
 7118            "Edit Hit Condition Breakpoint"
 7119        } else {
 7120            "Set Hit Condition Breakpoint"
 7121        };
 7122
 7123        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7124            "Unset Breakpoint"
 7125        } else {
 7126            "Set Breakpoint"
 7127        };
 7128
 7129        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7130            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7131
 7132        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7133            BreakpointState::Enabled => Some("Disable"),
 7134            BreakpointState::Disabled => Some("Enable"),
 7135        });
 7136
 7137        let (anchor, breakpoint) =
 7138            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7139
 7140        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7141            menu.on_blur_subscription(Subscription::new(|| {}))
 7142                .context(focus_handle)
 7143                .when(run_to_cursor, |this| {
 7144                    let weak_editor = weak_editor.clone();
 7145                    this.entry("Run to cursor", None, move |window, cx| {
 7146                        weak_editor
 7147                            .update(cx, |editor, cx| {
 7148                                editor.change_selections(None, window, cx, |s| {
 7149                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7150                                });
 7151                            })
 7152                            .ok();
 7153
 7154                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7155                    })
 7156                    .separator()
 7157                })
 7158                .when_some(toggle_state_msg, |this, msg| {
 7159                    this.entry(msg, None, {
 7160                        let weak_editor = weak_editor.clone();
 7161                        let breakpoint = breakpoint.clone();
 7162                        move |_window, cx| {
 7163                            weak_editor
 7164                                .update(cx, |this, cx| {
 7165                                    this.edit_breakpoint_at_anchor(
 7166                                        anchor,
 7167                                        breakpoint.as_ref().clone(),
 7168                                        BreakpointEditAction::InvertState,
 7169                                        cx,
 7170                                    );
 7171                                })
 7172                                .log_err();
 7173                        }
 7174                    })
 7175                })
 7176                .entry(set_breakpoint_msg, None, {
 7177                    let weak_editor = weak_editor.clone();
 7178                    let breakpoint = breakpoint.clone();
 7179                    move |_window, cx| {
 7180                        weak_editor
 7181                            .update(cx, |this, cx| {
 7182                                this.edit_breakpoint_at_anchor(
 7183                                    anchor,
 7184                                    breakpoint.as_ref().clone(),
 7185                                    BreakpointEditAction::Toggle,
 7186                                    cx,
 7187                                );
 7188                            })
 7189                            .log_err();
 7190                    }
 7191                })
 7192                .entry(log_breakpoint_msg, None, {
 7193                    let breakpoint = breakpoint.clone();
 7194                    let weak_editor = weak_editor.clone();
 7195                    move |window, cx| {
 7196                        weak_editor
 7197                            .update(cx, |this, cx| {
 7198                                this.add_edit_breakpoint_block(
 7199                                    anchor,
 7200                                    breakpoint.as_ref(),
 7201                                    BreakpointPromptEditAction::Log,
 7202                                    window,
 7203                                    cx,
 7204                                );
 7205                            })
 7206                            .log_err();
 7207                    }
 7208                })
 7209                .entry(condition_breakpoint_msg, None, {
 7210                    let breakpoint = breakpoint.clone();
 7211                    let weak_editor = weak_editor.clone();
 7212                    move |window, cx| {
 7213                        weak_editor
 7214                            .update(cx, |this, cx| {
 7215                                this.add_edit_breakpoint_block(
 7216                                    anchor,
 7217                                    breakpoint.as_ref(),
 7218                                    BreakpointPromptEditAction::Condition,
 7219                                    window,
 7220                                    cx,
 7221                                );
 7222                            })
 7223                            .log_err();
 7224                    }
 7225                })
 7226                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7227                    weak_editor
 7228                        .update(cx, |this, cx| {
 7229                            this.add_edit_breakpoint_block(
 7230                                anchor,
 7231                                breakpoint.as_ref(),
 7232                                BreakpointPromptEditAction::HitCondition,
 7233                                window,
 7234                                cx,
 7235                            );
 7236                        })
 7237                        .log_err();
 7238                })
 7239        })
 7240    }
 7241
 7242    fn render_breakpoint(
 7243        &self,
 7244        position: Anchor,
 7245        row: DisplayRow,
 7246        breakpoint: &Breakpoint,
 7247        state: Option<BreakpointSessionState>,
 7248        cx: &mut Context<Self>,
 7249    ) -> IconButton {
 7250        let is_rejected = state.is_some_and(|s| !s.verified);
 7251        // Is it a breakpoint that shows up when hovering over gutter?
 7252        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7253            (false, false),
 7254            |PhantomBreakpointIndicator {
 7255                 is_active,
 7256                 display_row,
 7257                 collides_with_existing_breakpoint,
 7258             }| {
 7259                (
 7260                    is_active && display_row == row,
 7261                    collides_with_existing_breakpoint,
 7262                )
 7263            },
 7264        );
 7265
 7266        let (color, icon) = {
 7267            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7268                (false, false) => ui::IconName::DebugBreakpoint,
 7269                (true, false) => ui::IconName::DebugLogBreakpoint,
 7270                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7271                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7272            };
 7273
 7274            let color = if is_phantom {
 7275                Color::Hint
 7276            } else if is_rejected {
 7277                Color::Disabled
 7278            } else {
 7279                Color::Debugger
 7280            };
 7281
 7282            (color, icon)
 7283        };
 7284
 7285        let breakpoint = Arc::from(breakpoint.clone());
 7286
 7287        let alt_as_text = gpui::Keystroke {
 7288            modifiers: Modifiers::secondary_key(),
 7289            ..Default::default()
 7290        };
 7291        let primary_action_text = if breakpoint.is_disabled() {
 7292            "Enable breakpoint"
 7293        } else if is_phantom && !collides_with_existing {
 7294            "Set breakpoint"
 7295        } else {
 7296            "Unset breakpoint"
 7297        };
 7298        let focus_handle = self.focus_handle.clone();
 7299
 7300        let meta = if is_rejected {
 7301            SharedString::from("No executable code is associated with this line.")
 7302        } else if collides_with_existing && !breakpoint.is_disabled() {
 7303            SharedString::from(format!(
 7304                "{alt_as_text}-click to disable,\nright-click for more options."
 7305            ))
 7306        } else {
 7307            SharedString::from("Right-click for more options.")
 7308        };
 7309        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7310            .icon_size(IconSize::XSmall)
 7311            .size(ui::ButtonSize::None)
 7312            .when(is_rejected, |this| {
 7313                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7314            })
 7315            .icon_color(color)
 7316            .style(ButtonStyle::Transparent)
 7317            .on_click(cx.listener({
 7318                let breakpoint = breakpoint.clone();
 7319
 7320                move |editor, event: &ClickEvent, window, cx| {
 7321                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7322                        BreakpointEditAction::InvertState
 7323                    } else {
 7324                        BreakpointEditAction::Toggle
 7325                    };
 7326
 7327                    window.focus(&editor.focus_handle(cx));
 7328                    editor.edit_breakpoint_at_anchor(
 7329                        position,
 7330                        breakpoint.as_ref().clone(),
 7331                        edit_action,
 7332                        cx,
 7333                    );
 7334                }
 7335            }))
 7336            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7337                editor.set_breakpoint_context_menu(
 7338                    row,
 7339                    Some(position),
 7340                    event.down.position,
 7341                    window,
 7342                    cx,
 7343                );
 7344            }))
 7345            .tooltip(move |window, cx| {
 7346                Tooltip::with_meta_in(
 7347                    primary_action_text,
 7348                    Some(&ToggleBreakpoint),
 7349                    meta.clone(),
 7350                    &focus_handle,
 7351                    window,
 7352                    cx,
 7353                )
 7354            })
 7355    }
 7356
 7357    fn build_tasks_context(
 7358        project: &Entity<Project>,
 7359        buffer: &Entity<Buffer>,
 7360        buffer_row: u32,
 7361        tasks: &Arc<RunnableTasks>,
 7362        cx: &mut Context<Self>,
 7363    ) -> Task<Option<task::TaskContext>> {
 7364        let position = Point::new(buffer_row, tasks.column);
 7365        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7366        let location = Location {
 7367            buffer: buffer.clone(),
 7368            range: range_start..range_start,
 7369        };
 7370        // Fill in the environmental variables from the tree-sitter captures
 7371        let mut captured_task_variables = TaskVariables::default();
 7372        for (capture_name, value) in tasks.extra_variables.clone() {
 7373            captured_task_variables.insert(
 7374                task::VariableName::Custom(capture_name.into()),
 7375                value.clone(),
 7376            );
 7377        }
 7378        project.update(cx, |project, cx| {
 7379            project.task_store().update(cx, |task_store, cx| {
 7380                task_store.task_context_for_location(captured_task_variables, location, cx)
 7381            })
 7382        })
 7383    }
 7384
 7385    pub fn spawn_nearest_task(
 7386        &mut self,
 7387        action: &SpawnNearestTask,
 7388        window: &mut Window,
 7389        cx: &mut Context<Self>,
 7390    ) {
 7391        let Some((workspace, _)) = self.workspace.clone() else {
 7392            return;
 7393        };
 7394        let Some(project) = self.project.clone() else {
 7395            return;
 7396        };
 7397
 7398        // Try to find a closest, enclosing node using tree-sitter that has a
 7399        // task
 7400        let Some((buffer, buffer_row, tasks)) = self
 7401            .find_enclosing_node_task(cx)
 7402            // Or find the task that's closest in row-distance.
 7403            .or_else(|| self.find_closest_task(cx))
 7404        else {
 7405            return;
 7406        };
 7407
 7408        let reveal_strategy = action.reveal;
 7409        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7410        cx.spawn_in(window, async move |_, cx| {
 7411            let context = task_context.await?;
 7412            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7413
 7414            let resolved = &mut resolved_task.resolved;
 7415            resolved.reveal = reveal_strategy;
 7416
 7417            workspace
 7418                .update_in(cx, |workspace, window, cx| {
 7419                    workspace.schedule_resolved_task(
 7420                        task_source_kind,
 7421                        resolved_task,
 7422                        false,
 7423                        window,
 7424                        cx,
 7425                    );
 7426                })
 7427                .ok()
 7428        })
 7429        .detach();
 7430    }
 7431
 7432    fn find_closest_task(
 7433        &mut self,
 7434        cx: &mut Context<Self>,
 7435    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7436        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7437
 7438        let ((buffer_id, row), tasks) = self
 7439            .tasks
 7440            .iter()
 7441            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7442
 7443        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7444        let tasks = Arc::new(tasks.to_owned());
 7445        Some((buffer, *row, tasks))
 7446    }
 7447
 7448    fn find_enclosing_node_task(
 7449        &mut self,
 7450        cx: &mut Context<Self>,
 7451    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7452        let snapshot = self.buffer.read(cx).snapshot(cx);
 7453        let offset = self.selections.newest::<usize>(cx).head();
 7454        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7455        let buffer_id = excerpt.buffer().remote_id();
 7456
 7457        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7458        let mut cursor = layer.node().walk();
 7459
 7460        while cursor.goto_first_child_for_byte(offset).is_some() {
 7461            if cursor.node().end_byte() == offset {
 7462                cursor.goto_next_sibling();
 7463            }
 7464        }
 7465
 7466        // Ascend to the smallest ancestor that contains the range and has a task.
 7467        loop {
 7468            let node = cursor.node();
 7469            let node_range = node.byte_range();
 7470            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7471
 7472            // Check if this node contains our offset
 7473            if node_range.start <= offset && node_range.end >= offset {
 7474                // If it contains offset, check for task
 7475                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7476                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7477                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7478                }
 7479            }
 7480
 7481            if !cursor.goto_parent() {
 7482                break;
 7483            }
 7484        }
 7485        None
 7486    }
 7487
 7488    fn render_run_indicator(
 7489        &self,
 7490        _style: &EditorStyle,
 7491        is_active: bool,
 7492        row: DisplayRow,
 7493        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7494        cx: &mut Context<Self>,
 7495    ) -> IconButton {
 7496        let color = Color::Muted;
 7497        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7498
 7499        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7500            .shape(ui::IconButtonShape::Square)
 7501            .icon_size(IconSize::XSmall)
 7502            .icon_color(color)
 7503            .toggle_state(is_active)
 7504            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7505                let quick_launch = e.down.button == MouseButton::Left;
 7506                window.focus(&editor.focus_handle(cx));
 7507                editor.toggle_code_actions(
 7508                    &ToggleCodeActions {
 7509                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7510                        quick_launch,
 7511                    },
 7512                    window,
 7513                    cx,
 7514                );
 7515            }))
 7516            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7517                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7518            }))
 7519    }
 7520
 7521    pub fn context_menu_visible(&self) -> bool {
 7522        !self.edit_prediction_preview_is_active()
 7523            && self
 7524                .context_menu
 7525                .borrow()
 7526                .as_ref()
 7527                .map_or(false, |menu| menu.visible())
 7528    }
 7529
 7530    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7531        self.context_menu
 7532            .borrow()
 7533            .as_ref()
 7534            .map(|menu| menu.origin())
 7535    }
 7536
 7537    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7538        self.context_menu_options = Some(options);
 7539    }
 7540
 7541    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7542    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7543
 7544    fn render_edit_prediction_popover(
 7545        &mut self,
 7546        text_bounds: &Bounds<Pixels>,
 7547        content_origin: gpui::Point<Pixels>,
 7548        right_margin: Pixels,
 7549        editor_snapshot: &EditorSnapshot,
 7550        visible_row_range: Range<DisplayRow>,
 7551        scroll_top: f32,
 7552        scroll_bottom: f32,
 7553        line_layouts: &[LineWithInvisibles],
 7554        line_height: Pixels,
 7555        scroll_pixel_position: gpui::Point<Pixels>,
 7556        newest_selection_head: Option<DisplayPoint>,
 7557        editor_width: Pixels,
 7558        style: &EditorStyle,
 7559        window: &mut Window,
 7560        cx: &mut App,
 7561    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7562        if self.mode().is_minimap() {
 7563            return None;
 7564        }
 7565        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7566
 7567        if self.edit_prediction_visible_in_cursor_popover(true) {
 7568            return None;
 7569        }
 7570
 7571        match &active_inline_completion.completion {
 7572            InlineCompletion::Move { target, .. } => {
 7573                let target_display_point = target.to_display_point(editor_snapshot);
 7574
 7575                if self.edit_prediction_requires_modifier() {
 7576                    if !self.edit_prediction_preview_is_active() {
 7577                        return None;
 7578                    }
 7579
 7580                    self.render_edit_prediction_modifier_jump_popover(
 7581                        text_bounds,
 7582                        content_origin,
 7583                        visible_row_range,
 7584                        line_layouts,
 7585                        line_height,
 7586                        scroll_pixel_position,
 7587                        newest_selection_head,
 7588                        target_display_point,
 7589                        window,
 7590                        cx,
 7591                    )
 7592                } else {
 7593                    self.render_edit_prediction_eager_jump_popover(
 7594                        text_bounds,
 7595                        content_origin,
 7596                        editor_snapshot,
 7597                        visible_row_range,
 7598                        scroll_top,
 7599                        scroll_bottom,
 7600                        line_height,
 7601                        scroll_pixel_position,
 7602                        target_display_point,
 7603                        editor_width,
 7604                        window,
 7605                        cx,
 7606                    )
 7607                }
 7608            }
 7609            InlineCompletion::Edit {
 7610                display_mode: EditDisplayMode::Inline,
 7611                ..
 7612            } => None,
 7613            InlineCompletion::Edit {
 7614                display_mode: EditDisplayMode::TabAccept,
 7615                edits,
 7616                ..
 7617            } => {
 7618                let range = &edits.first()?.0;
 7619                let target_display_point = range.end.to_display_point(editor_snapshot);
 7620
 7621                self.render_edit_prediction_end_of_line_popover(
 7622                    "Accept",
 7623                    editor_snapshot,
 7624                    visible_row_range,
 7625                    target_display_point,
 7626                    line_height,
 7627                    scroll_pixel_position,
 7628                    content_origin,
 7629                    editor_width,
 7630                    window,
 7631                    cx,
 7632                )
 7633            }
 7634            InlineCompletion::Edit {
 7635                edits,
 7636                edit_preview,
 7637                display_mode: EditDisplayMode::DiffPopover,
 7638                snapshot,
 7639            } => self.render_edit_prediction_diff_popover(
 7640                text_bounds,
 7641                content_origin,
 7642                right_margin,
 7643                editor_snapshot,
 7644                visible_row_range,
 7645                line_layouts,
 7646                line_height,
 7647                scroll_pixel_position,
 7648                newest_selection_head,
 7649                editor_width,
 7650                style,
 7651                edits,
 7652                edit_preview,
 7653                snapshot,
 7654                window,
 7655                cx,
 7656            ),
 7657        }
 7658    }
 7659
 7660    fn render_edit_prediction_modifier_jump_popover(
 7661        &mut self,
 7662        text_bounds: &Bounds<Pixels>,
 7663        content_origin: gpui::Point<Pixels>,
 7664        visible_row_range: Range<DisplayRow>,
 7665        line_layouts: &[LineWithInvisibles],
 7666        line_height: Pixels,
 7667        scroll_pixel_position: gpui::Point<Pixels>,
 7668        newest_selection_head: Option<DisplayPoint>,
 7669        target_display_point: DisplayPoint,
 7670        window: &mut Window,
 7671        cx: &mut App,
 7672    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7673        let scrolled_content_origin =
 7674            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7675
 7676        const SCROLL_PADDING_Y: Pixels = px(12.);
 7677
 7678        if target_display_point.row() < visible_row_range.start {
 7679            return self.render_edit_prediction_scroll_popover(
 7680                |_| SCROLL_PADDING_Y,
 7681                IconName::ArrowUp,
 7682                visible_row_range,
 7683                line_layouts,
 7684                newest_selection_head,
 7685                scrolled_content_origin,
 7686                window,
 7687                cx,
 7688            );
 7689        } else if target_display_point.row() >= visible_row_range.end {
 7690            return self.render_edit_prediction_scroll_popover(
 7691                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7692                IconName::ArrowDown,
 7693                visible_row_range,
 7694                line_layouts,
 7695                newest_selection_head,
 7696                scrolled_content_origin,
 7697                window,
 7698                cx,
 7699            );
 7700        }
 7701
 7702        const POLE_WIDTH: Pixels = px(2.);
 7703
 7704        let line_layout =
 7705            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7706        let target_column = target_display_point.column() as usize;
 7707
 7708        let target_x = line_layout.x_for_index(target_column);
 7709        let target_y =
 7710            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7711
 7712        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7713
 7714        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7715        border_color.l += 0.001;
 7716
 7717        let mut element = v_flex()
 7718            .items_end()
 7719            .when(flag_on_right, |el| el.items_start())
 7720            .child(if flag_on_right {
 7721                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7722                    .rounded_bl(px(0.))
 7723                    .rounded_tl(px(0.))
 7724                    .border_l_2()
 7725                    .border_color(border_color)
 7726            } else {
 7727                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7728                    .rounded_br(px(0.))
 7729                    .rounded_tr(px(0.))
 7730                    .border_r_2()
 7731                    .border_color(border_color)
 7732            })
 7733            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7734            .into_any();
 7735
 7736        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7737
 7738        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7739            - point(
 7740                if flag_on_right {
 7741                    POLE_WIDTH
 7742                } else {
 7743                    size.width - POLE_WIDTH
 7744                },
 7745                size.height - line_height,
 7746            );
 7747
 7748        origin.x = origin.x.max(content_origin.x);
 7749
 7750        element.prepaint_at(origin, window, cx);
 7751
 7752        Some((element, origin))
 7753    }
 7754
 7755    fn render_edit_prediction_scroll_popover(
 7756        &mut self,
 7757        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7758        scroll_icon: IconName,
 7759        visible_row_range: Range<DisplayRow>,
 7760        line_layouts: &[LineWithInvisibles],
 7761        newest_selection_head: Option<DisplayPoint>,
 7762        scrolled_content_origin: gpui::Point<Pixels>,
 7763        window: &mut Window,
 7764        cx: &mut App,
 7765    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7766        let mut element = self
 7767            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7768            .into_any();
 7769
 7770        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7771
 7772        let cursor = newest_selection_head?;
 7773        let cursor_row_layout =
 7774            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7775        let cursor_column = cursor.column() as usize;
 7776
 7777        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7778
 7779        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7780
 7781        element.prepaint_at(origin, window, cx);
 7782        Some((element, origin))
 7783    }
 7784
 7785    fn render_edit_prediction_eager_jump_popover(
 7786        &mut self,
 7787        text_bounds: &Bounds<Pixels>,
 7788        content_origin: gpui::Point<Pixels>,
 7789        editor_snapshot: &EditorSnapshot,
 7790        visible_row_range: Range<DisplayRow>,
 7791        scroll_top: f32,
 7792        scroll_bottom: f32,
 7793        line_height: Pixels,
 7794        scroll_pixel_position: gpui::Point<Pixels>,
 7795        target_display_point: DisplayPoint,
 7796        editor_width: Pixels,
 7797        window: &mut Window,
 7798        cx: &mut App,
 7799    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7800        if target_display_point.row().as_f32() < scroll_top {
 7801            let mut element = self
 7802                .render_edit_prediction_line_popover(
 7803                    "Jump to Edit",
 7804                    Some(IconName::ArrowUp),
 7805                    window,
 7806                    cx,
 7807                )?
 7808                .into_any();
 7809
 7810            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7811            let offset = point(
 7812                (text_bounds.size.width - size.width) / 2.,
 7813                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7814            );
 7815
 7816            let origin = text_bounds.origin + offset;
 7817            element.prepaint_at(origin, window, cx);
 7818            Some((element, origin))
 7819        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7820            let mut element = self
 7821                .render_edit_prediction_line_popover(
 7822                    "Jump to Edit",
 7823                    Some(IconName::ArrowDown),
 7824                    window,
 7825                    cx,
 7826                )?
 7827                .into_any();
 7828
 7829            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7830            let offset = point(
 7831                (text_bounds.size.width - size.width) / 2.,
 7832                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7833            );
 7834
 7835            let origin = text_bounds.origin + offset;
 7836            element.prepaint_at(origin, window, cx);
 7837            Some((element, origin))
 7838        } else {
 7839            self.render_edit_prediction_end_of_line_popover(
 7840                "Jump to Edit",
 7841                editor_snapshot,
 7842                visible_row_range,
 7843                target_display_point,
 7844                line_height,
 7845                scroll_pixel_position,
 7846                content_origin,
 7847                editor_width,
 7848                window,
 7849                cx,
 7850            )
 7851        }
 7852    }
 7853
 7854    fn render_edit_prediction_end_of_line_popover(
 7855        self: &mut Editor,
 7856        label: &'static str,
 7857        editor_snapshot: &EditorSnapshot,
 7858        visible_row_range: Range<DisplayRow>,
 7859        target_display_point: DisplayPoint,
 7860        line_height: Pixels,
 7861        scroll_pixel_position: gpui::Point<Pixels>,
 7862        content_origin: gpui::Point<Pixels>,
 7863        editor_width: Pixels,
 7864        window: &mut Window,
 7865        cx: &mut App,
 7866    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7867        let target_line_end = DisplayPoint::new(
 7868            target_display_point.row(),
 7869            editor_snapshot.line_len(target_display_point.row()),
 7870        );
 7871
 7872        let mut element = self
 7873            .render_edit_prediction_line_popover(label, None, window, cx)?
 7874            .into_any();
 7875
 7876        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7877
 7878        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7879
 7880        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7881        let mut origin = start_point
 7882            + line_origin
 7883            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7884        origin.x = origin.x.max(content_origin.x);
 7885
 7886        let max_x = content_origin.x + editor_width - size.width;
 7887
 7888        if origin.x > max_x {
 7889            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7890
 7891            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7892                origin.y += offset;
 7893                IconName::ArrowUp
 7894            } else {
 7895                origin.y -= offset;
 7896                IconName::ArrowDown
 7897            };
 7898
 7899            element = self
 7900                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7901                .into_any();
 7902
 7903            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7904
 7905            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7906        }
 7907
 7908        element.prepaint_at(origin, window, cx);
 7909        Some((element, origin))
 7910    }
 7911
 7912    fn render_edit_prediction_diff_popover(
 7913        self: &Editor,
 7914        text_bounds: &Bounds<Pixels>,
 7915        content_origin: gpui::Point<Pixels>,
 7916        right_margin: Pixels,
 7917        editor_snapshot: &EditorSnapshot,
 7918        visible_row_range: Range<DisplayRow>,
 7919        line_layouts: &[LineWithInvisibles],
 7920        line_height: Pixels,
 7921        scroll_pixel_position: gpui::Point<Pixels>,
 7922        newest_selection_head: Option<DisplayPoint>,
 7923        editor_width: Pixels,
 7924        style: &EditorStyle,
 7925        edits: &Vec<(Range<Anchor>, String)>,
 7926        edit_preview: &Option<language::EditPreview>,
 7927        snapshot: &language::BufferSnapshot,
 7928        window: &mut Window,
 7929        cx: &mut App,
 7930    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7931        let edit_start = edits
 7932            .first()
 7933            .unwrap()
 7934            .0
 7935            .start
 7936            .to_display_point(editor_snapshot);
 7937        let edit_end = edits
 7938            .last()
 7939            .unwrap()
 7940            .0
 7941            .end
 7942            .to_display_point(editor_snapshot);
 7943
 7944        let is_visible = visible_row_range.contains(&edit_start.row())
 7945            || visible_row_range.contains(&edit_end.row());
 7946        if !is_visible {
 7947            return None;
 7948        }
 7949
 7950        let highlighted_edits =
 7951            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7952
 7953        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7954        let line_count = highlighted_edits.text.lines().count();
 7955
 7956        const BORDER_WIDTH: Pixels = px(1.);
 7957
 7958        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7959        let has_keybind = keybind.is_some();
 7960
 7961        let mut element = h_flex()
 7962            .items_start()
 7963            .child(
 7964                h_flex()
 7965                    .bg(cx.theme().colors().editor_background)
 7966                    .border(BORDER_WIDTH)
 7967                    .shadow_sm()
 7968                    .border_color(cx.theme().colors().border)
 7969                    .rounded_l_lg()
 7970                    .when(line_count > 1, |el| el.rounded_br_lg())
 7971                    .pr_1()
 7972                    .child(styled_text),
 7973            )
 7974            .child(
 7975                h_flex()
 7976                    .h(line_height + BORDER_WIDTH * 2.)
 7977                    .px_1p5()
 7978                    .gap_1()
 7979                    // Workaround: For some reason, there's a gap if we don't do this
 7980                    .ml(-BORDER_WIDTH)
 7981                    .shadow(smallvec![gpui::BoxShadow {
 7982                        color: gpui::black().opacity(0.05),
 7983                        offset: point(px(1.), px(1.)),
 7984                        blur_radius: px(2.),
 7985                        spread_radius: px(0.),
 7986                    }])
 7987                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7988                    .border(BORDER_WIDTH)
 7989                    .border_color(cx.theme().colors().border)
 7990                    .rounded_r_lg()
 7991                    .id("edit_prediction_diff_popover_keybind")
 7992                    .when(!has_keybind, |el| {
 7993                        let status_colors = cx.theme().status();
 7994
 7995                        el.bg(status_colors.error_background)
 7996                            .border_color(status_colors.error.opacity(0.6))
 7997                            .child(Icon::new(IconName::Info).color(Color::Error))
 7998                            .cursor_default()
 7999                            .hoverable_tooltip(move |_window, cx| {
 8000                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8001                            })
 8002                    })
 8003                    .children(keybind),
 8004            )
 8005            .into_any();
 8006
 8007        let longest_row =
 8008            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8009        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8010            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8011        } else {
 8012            layout_line(
 8013                longest_row,
 8014                editor_snapshot,
 8015                style,
 8016                editor_width,
 8017                |_| false,
 8018                window,
 8019                cx,
 8020            )
 8021            .width
 8022        };
 8023
 8024        let viewport_bounds =
 8025            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8026                right: -right_margin,
 8027                ..Default::default()
 8028            });
 8029
 8030        let x_after_longest =
 8031            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8032                - scroll_pixel_position.x;
 8033
 8034        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8035
 8036        // Fully visible if it can be displayed within the window (allow overlapping other
 8037        // panes). However, this is only allowed if the popover starts within text_bounds.
 8038        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8039            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8040
 8041        let mut origin = if can_position_to_the_right {
 8042            point(
 8043                x_after_longest,
 8044                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8045                    - scroll_pixel_position.y,
 8046            )
 8047        } else {
 8048            let cursor_row = newest_selection_head.map(|head| head.row());
 8049            let above_edit = edit_start
 8050                .row()
 8051                .0
 8052                .checked_sub(line_count as u32)
 8053                .map(DisplayRow);
 8054            let below_edit = Some(edit_end.row() + 1);
 8055            let above_cursor =
 8056                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8057            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8058
 8059            // Place the edit popover adjacent to the edit if there is a location
 8060            // available that is onscreen and does not obscure the cursor. Otherwise,
 8061            // place it adjacent to the cursor.
 8062            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8063                .into_iter()
 8064                .flatten()
 8065                .find(|&start_row| {
 8066                    let end_row = start_row + line_count as u32;
 8067                    visible_row_range.contains(&start_row)
 8068                        && visible_row_range.contains(&end_row)
 8069                        && cursor_row.map_or(true, |cursor_row| {
 8070                            !((start_row..end_row).contains(&cursor_row))
 8071                        })
 8072                })?;
 8073
 8074            content_origin
 8075                + point(
 8076                    -scroll_pixel_position.x,
 8077                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8078                )
 8079        };
 8080
 8081        origin.x -= BORDER_WIDTH;
 8082
 8083        window.defer_draw(element, origin, 1);
 8084
 8085        // Do not return an element, since it will already be drawn due to defer_draw.
 8086        None
 8087    }
 8088
 8089    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8090        px(30.)
 8091    }
 8092
 8093    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8094        if self.read_only(cx) {
 8095            cx.theme().players().read_only()
 8096        } else {
 8097            self.style.as_ref().unwrap().local_player
 8098        }
 8099    }
 8100
 8101    fn render_edit_prediction_accept_keybind(
 8102        &self,
 8103        window: &mut Window,
 8104        cx: &App,
 8105    ) -> Option<AnyElement> {
 8106        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8107        let accept_keystroke = accept_binding.keystroke()?;
 8108
 8109        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8110
 8111        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8112            Color::Accent
 8113        } else {
 8114            Color::Muted
 8115        };
 8116
 8117        h_flex()
 8118            .px_0p5()
 8119            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8120            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8121            .text_size(TextSize::XSmall.rems(cx))
 8122            .child(h_flex().children(ui::render_modifiers(
 8123                &accept_keystroke.modifiers,
 8124                PlatformStyle::platform(),
 8125                Some(modifiers_color),
 8126                Some(IconSize::XSmall.rems().into()),
 8127                true,
 8128            )))
 8129            .when(is_platform_style_mac, |parent| {
 8130                parent.child(accept_keystroke.key.clone())
 8131            })
 8132            .when(!is_platform_style_mac, |parent| {
 8133                parent.child(
 8134                    Key::new(
 8135                        util::capitalize(&accept_keystroke.key),
 8136                        Some(Color::Default),
 8137                    )
 8138                    .size(Some(IconSize::XSmall.rems().into())),
 8139                )
 8140            })
 8141            .into_any()
 8142            .into()
 8143    }
 8144
 8145    fn render_edit_prediction_line_popover(
 8146        &self,
 8147        label: impl Into<SharedString>,
 8148        icon: Option<IconName>,
 8149        window: &mut Window,
 8150        cx: &App,
 8151    ) -> Option<Stateful<Div>> {
 8152        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8153
 8154        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8155        let has_keybind = keybind.is_some();
 8156
 8157        let result = h_flex()
 8158            .id("ep-line-popover")
 8159            .py_0p5()
 8160            .pl_1()
 8161            .pr(padding_right)
 8162            .gap_1()
 8163            .rounded_md()
 8164            .border_1()
 8165            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8166            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8167            .shadow_sm()
 8168            .when(!has_keybind, |el| {
 8169                let status_colors = cx.theme().status();
 8170
 8171                el.bg(status_colors.error_background)
 8172                    .border_color(status_colors.error.opacity(0.6))
 8173                    .pl_2()
 8174                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8175                    .cursor_default()
 8176                    .hoverable_tooltip(move |_window, cx| {
 8177                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8178                    })
 8179            })
 8180            .children(keybind)
 8181            .child(
 8182                Label::new(label)
 8183                    .size(LabelSize::Small)
 8184                    .when(!has_keybind, |el| {
 8185                        el.color(cx.theme().status().error.into()).strikethrough()
 8186                    }),
 8187            )
 8188            .when(!has_keybind, |el| {
 8189                el.child(
 8190                    h_flex().ml_1().child(
 8191                        Icon::new(IconName::Info)
 8192                            .size(IconSize::Small)
 8193                            .color(cx.theme().status().error.into()),
 8194                    ),
 8195                )
 8196            })
 8197            .when_some(icon, |element, icon| {
 8198                element.child(
 8199                    div()
 8200                        .mt(px(1.5))
 8201                        .child(Icon::new(icon).size(IconSize::Small)),
 8202                )
 8203            });
 8204
 8205        Some(result)
 8206    }
 8207
 8208    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8209        let accent_color = cx.theme().colors().text_accent;
 8210        let editor_bg_color = cx.theme().colors().editor_background;
 8211        editor_bg_color.blend(accent_color.opacity(0.1))
 8212    }
 8213
 8214    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8215        let accent_color = cx.theme().colors().text_accent;
 8216        let editor_bg_color = cx.theme().colors().editor_background;
 8217        editor_bg_color.blend(accent_color.opacity(0.6))
 8218    }
 8219
 8220    fn render_edit_prediction_cursor_popover(
 8221        &self,
 8222        min_width: Pixels,
 8223        max_width: Pixels,
 8224        cursor_point: Point,
 8225        style: &EditorStyle,
 8226        accept_keystroke: Option<&gpui::Keystroke>,
 8227        _window: &Window,
 8228        cx: &mut Context<Editor>,
 8229    ) -> Option<AnyElement> {
 8230        let provider = self.edit_prediction_provider.as_ref()?;
 8231
 8232        if provider.provider.needs_terms_acceptance(cx) {
 8233            return Some(
 8234                h_flex()
 8235                    .min_w(min_width)
 8236                    .flex_1()
 8237                    .px_2()
 8238                    .py_1()
 8239                    .gap_3()
 8240                    .elevation_2(cx)
 8241                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8242                    .id("accept-terms")
 8243                    .cursor_pointer()
 8244                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8245                    .on_click(cx.listener(|this, _event, window, cx| {
 8246                        cx.stop_propagation();
 8247                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8248                        window.dispatch_action(
 8249                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8250                            cx,
 8251                        );
 8252                    }))
 8253                    .child(
 8254                        h_flex()
 8255                            .flex_1()
 8256                            .gap_2()
 8257                            .child(Icon::new(IconName::ZedPredict))
 8258                            .child(Label::new("Accept Terms of Service"))
 8259                            .child(div().w_full())
 8260                            .child(
 8261                                Icon::new(IconName::ArrowUpRight)
 8262                                    .color(Color::Muted)
 8263                                    .size(IconSize::Small),
 8264                            )
 8265                            .into_any_element(),
 8266                    )
 8267                    .into_any(),
 8268            );
 8269        }
 8270
 8271        let is_refreshing = provider.provider.is_refreshing(cx);
 8272
 8273        fn pending_completion_container() -> Div {
 8274            h_flex()
 8275                .h_full()
 8276                .flex_1()
 8277                .gap_2()
 8278                .child(Icon::new(IconName::ZedPredict))
 8279        }
 8280
 8281        let completion = match &self.active_inline_completion {
 8282            Some(prediction) => {
 8283                if !self.has_visible_completions_menu() {
 8284                    const RADIUS: Pixels = px(6.);
 8285                    const BORDER_WIDTH: Pixels = px(1.);
 8286
 8287                    return Some(
 8288                        h_flex()
 8289                            .elevation_2(cx)
 8290                            .border(BORDER_WIDTH)
 8291                            .border_color(cx.theme().colors().border)
 8292                            .when(accept_keystroke.is_none(), |el| {
 8293                                el.border_color(cx.theme().status().error)
 8294                            })
 8295                            .rounded(RADIUS)
 8296                            .rounded_tl(px(0.))
 8297                            .overflow_hidden()
 8298                            .child(div().px_1p5().child(match &prediction.completion {
 8299                                InlineCompletion::Move { target, snapshot } => {
 8300                                    use text::ToPoint as _;
 8301                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8302                                    {
 8303                                        Icon::new(IconName::ZedPredictDown)
 8304                                    } else {
 8305                                        Icon::new(IconName::ZedPredictUp)
 8306                                    }
 8307                                }
 8308                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8309                            }))
 8310                            .child(
 8311                                h_flex()
 8312                                    .gap_1()
 8313                                    .py_1()
 8314                                    .px_2()
 8315                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8316                                    .border_l_1()
 8317                                    .border_color(cx.theme().colors().border)
 8318                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8319                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8320                                        el.child(
 8321                                            Label::new("Hold")
 8322                                                .size(LabelSize::Small)
 8323                                                .when(accept_keystroke.is_none(), |el| {
 8324                                                    el.strikethrough()
 8325                                                })
 8326                                                .line_height_style(LineHeightStyle::UiLabel),
 8327                                        )
 8328                                    })
 8329                                    .id("edit_prediction_cursor_popover_keybind")
 8330                                    .when(accept_keystroke.is_none(), |el| {
 8331                                        let status_colors = cx.theme().status();
 8332
 8333                                        el.bg(status_colors.error_background)
 8334                                            .border_color(status_colors.error.opacity(0.6))
 8335                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8336                                            .cursor_default()
 8337                                            .hoverable_tooltip(move |_window, cx| {
 8338                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8339                                                    .into()
 8340                                            })
 8341                                    })
 8342                                    .when_some(
 8343                                        accept_keystroke.as_ref(),
 8344                                        |el, accept_keystroke| {
 8345                                            el.child(h_flex().children(ui::render_modifiers(
 8346                                                &accept_keystroke.modifiers,
 8347                                                PlatformStyle::platform(),
 8348                                                Some(Color::Default),
 8349                                                Some(IconSize::XSmall.rems().into()),
 8350                                                false,
 8351                                            )))
 8352                                        },
 8353                                    ),
 8354                            )
 8355                            .into_any(),
 8356                    );
 8357                }
 8358
 8359                self.render_edit_prediction_cursor_popover_preview(
 8360                    prediction,
 8361                    cursor_point,
 8362                    style,
 8363                    cx,
 8364                )?
 8365            }
 8366
 8367            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8368                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8369                    stale_completion,
 8370                    cursor_point,
 8371                    style,
 8372                    cx,
 8373                )?,
 8374
 8375                None => {
 8376                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8377                }
 8378            },
 8379
 8380            None => pending_completion_container().child(Label::new("No Prediction")),
 8381        };
 8382
 8383        let completion = if is_refreshing {
 8384            completion
 8385                .with_animation(
 8386                    "loading-completion",
 8387                    Animation::new(Duration::from_secs(2))
 8388                        .repeat()
 8389                        .with_easing(pulsating_between(0.4, 0.8)),
 8390                    |label, delta| label.opacity(delta),
 8391                )
 8392                .into_any_element()
 8393        } else {
 8394            completion.into_any_element()
 8395        };
 8396
 8397        let has_completion = self.active_inline_completion.is_some();
 8398
 8399        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8400        Some(
 8401            h_flex()
 8402                .min_w(min_width)
 8403                .max_w(max_width)
 8404                .flex_1()
 8405                .elevation_2(cx)
 8406                .border_color(cx.theme().colors().border)
 8407                .child(
 8408                    div()
 8409                        .flex_1()
 8410                        .py_1()
 8411                        .px_2()
 8412                        .overflow_hidden()
 8413                        .child(completion),
 8414                )
 8415                .when_some(accept_keystroke, |el, accept_keystroke| {
 8416                    if !accept_keystroke.modifiers.modified() {
 8417                        return el;
 8418                    }
 8419
 8420                    el.child(
 8421                        h_flex()
 8422                            .h_full()
 8423                            .border_l_1()
 8424                            .rounded_r_lg()
 8425                            .border_color(cx.theme().colors().border)
 8426                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8427                            .gap_1()
 8428                            .py_1()
 8429                            .px_2()
 8430                            .child(
 8431                                h_flex()
 8432                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8433                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8434                                    .child(h_flex().children(ui::render_modifiers(
 8435                                        &accept_keystroke.modifiers,
 8436                                        PlatformStyle::platform(),
 8437                                        Some(if !has_completion {
 8438                                            Color::Muted
 8439                                        } else {
 8440                                            Color::Default
 8441                                        }),
 8442                                        None,
 8443                                        false,
 8444                                    ))),
 8445                            )
 8446                            .child(Label::new("Preview").into_any_element())
 8447                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8448                    )
 8449                })
 8450                .into_any(),
 8451        )
 8452    }
 8453
 8454    fn render_edit_prediction_cursor_popover_preview(
 8455        &self,
 8456        completion: &InlineCompletionState,
 8457        cursor_point: Point,
 8458        style: &EditorStyle,
 8459        cx: &mut Context<Editor>,
 8460    ) -> Option<Div> {
 8461        use text::ToPoint as _;
 8462
 8463        fn render_relative_row_jump(
 8464            prefix: impl Into<String>,
 8465            current_row: u32,
 8466            target_row: u32,
 8467        ) -> Div {
 8468            let (row_diff, arrow) = if target_row < current_row {
 8469                (current_row - target_row, IconName::ArrowUp)
 8470            } else {
 8471                (target_row - current_row, IconName::ArrowDown)
 8472            };
 8473
 8474            h_flex()
 8475                .child(
 8476                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8477                        .color(Color::Muted)
 8478                        .size(LabelSize::Small),
 8479                )
 8480                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8481        }
 8482
 8483        match &completion.completion {
 8484            InlineCompletion::Move {
 8485                target, snapshot, ..
 8486            } => Some(
 8487                h_flex()
 8488                    .px_2()
 8489                    .gap_2()
 8490                    .flex_1()
 8491                    .child(
 8492                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8493                            Icon::new(IconName::ZedPredictDown)
 8494                        } else {
 8495                            Icon::new(IconName::ZedPredictUp)
 8496                        },
 8497                    )
 8498                    .child(Label::new("Jump to Edit")),
 8499            ),
 8500
 8501            InlineCompletion::Edit {
 8502                edits,
 8503                edit_preview,
 8504                snapshot,
 8505                display_mode: _,
 8506            } => {
 8507                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8508
 8509                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8510                    &snapshot,
 8511                    &edits,
 8512                    edit_preview.as_ref()?,
 8513                    true,
 8514                    cx,
 8515                )
 8516                .first_line_preview();
 8517
 8518                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8519                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8520
 8521                let preview = h_flex()
 8522                    .gap_1()
 8523                    .min_w_16()
 8524                    .child(styled_text)
 8525                    .when(has_more_lines, |parent| parent.child(""));
 8526
 8527                let left = if first_edit_row != cursor_point.row {
 8528                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8529                        .into_any_element()
 8530                } else {
 8531                    Icon::new(IconName::ZedPredict).into_any_element()
 8532                };
 8533
 8534                Some(
 8535                    h_flex()
 8536                        .h_full()
 8537                        .flex_1()
 8538                        .gap_2()
 8539                        .pr_1()
 8540                        .overflow_x_hidden()
 8541                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8542                        .child(left)
 8543                        .child(preview),
 8544                )
 8545            }
 8546        }
 8547    }
 8548
 8549    pub fn render_context_menu(
 8550        &self,
 8551        style: &EditorStyle,
 8552        max_height_in_lines: u32,
 8553        window: &mut Window,
 8554        cx: &mut Context<Editor>,
 8555    ) -> Option<AnyElement> {
 8556        let menu = self.context_menu.borrow();
 8557        let menu = menu.as_ref()?;
 8558        if !menu.visible() {
 8559            return None;
 8560        };
 8561        Some(menu.render(style, max_height_in_lines, window, cx))
 8562    }
 8563
 8564    fn render_context_menu_aside(
 8565        &mut self,
 8566        max_size: Size<Pixels>,
 8567        window: &mut Window,
 8568        cx: &mut Context<Editor>,
 8569    ) -> Option<AnyElement> {
 8570        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8571            if menu.visible() {
 8572                menu.render_aside(self, max_size, window, cx)
 8573            } else {
 8574                None
 8575            }
 8576        })
 8577    }
 8578
 8579    fn hide_context_menu(
 8580        &mut self,
 8581        window: &mut Window,
 8582        cx: &mut Context<Self>,
 8583    ) -> Option<CodeContextMenu> {
 8584        cx.notify();
 8585        self.completion_tasks.clear();
 8586        let context_menu = self.context_menu.borrow_mut().take();
 8587        self.stale_inline_completion_in_menu.take();
 8588        self.update_visible_inline_completion(window, cx);
 8589        context_menu
 8590    }
 8591
 8592    fn show_snippet_choices(
 8593        &mut self,
 8594        choices: &Vec<String>,
 8595        selection: Range<Anchor>,
 8596        cx: &mut Context<Self>,
 8597    ) {
 8598        if selection.start.buffer_id.is_none() {
 8599            return;
 8600        }
 8601        let buffer_id = selection.start.buffer_id.unwrap();
 8602        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8603        let id = post_inc(&mut self.next_completion_id);
 8604        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8605
 8606        if let Some(buffer) = buffer {
 8607            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8608                CompletionsMenu::new_snippet_choices(
 8609                    id,
 8610                    true,
 8611                    choices,
 8612                    selection,
 8613                    buffer,
 8614                    snippet_sort_order,
 8615                ),
 8616            ));
 8617        }
 8618    }
 8619
 8620    pub fn insert_snippet(
 8621        &mut self,
 8622        insertion_ranges: &[Range<usize>],
 8623        snippet: Snippet,
 8624        window: &mut Window,
 8625        cx: &mut Context<Self>,
 8626    ) -> Result<()> {
 8627        struct Tabstop<T> {
 8628            is_end_tabstop: bool,
 8629            ranges: Vec<Range<T>>,
 8630            choices: Option<Vec<String>>,
 8631        }
 8632
 8633        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8634            let snippet_text: Arc<str> = snippet.text.clone().into();
 8635            let edits = insertion_ranges
 8636                .iter()
 8637                .cloned()
 8638                .map(|range| (range, snippet_text.clone()));
 8639            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8640
 8641            let snapshot = &*buffer.read(cx);
 8642            let snippet = &snippet;
 8643            snippet
 8644                .tabstops
 8645                .iter()
 8646                .map(|tabstop| {
 8647                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8648                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8649                    });
 8650                    let mut tabstop_ranges = tabstop
 8651                        .ranges
 8652                        .iter()
 8653                        .flat_map(|tabstop_range| {
 8654                            let mut delta = 0_isize;
 8655                            insertion_ranges.iter().map(move |insertion_range| {
 8656                                let insertion_start = insertion_range.start as isize + delta;
 8657                                delta +=
 8658                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8659
 8660                                let start = ((insertion_start + tabstop_range.start) as usize)
 8661                                    .min(snapshot.len());
 8662                                let end = ((insertion_start + tabstop_range.end) as usize)
 8663                                    .min(snapshot.len());
 8664                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8665                            })
 8666                        })
 8667                        .collect::<Vec<_>>();
 8668                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8669
 8670                    Tabstop {
 8671                        is_end_tabstop,
 8672                        ranges: tabstop_ranges,
 8673                        choices: tabstop.choices.clone(),
 8674                    }
 8675                })
 8676                .collect::<Vec<_>>()
 8677        });
 8678        if let Some(tabstop) = tabstops.first() {
 8679            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8680                s.select_ranges(tabstop.ranges.iter().cloned());
 8681            });
 8682
 8683            if let Some(choices) = &tabstop.choices {
 8684                if let Some(selection) = tabstop.ranges.first() {
 8685                    self.show_snippet_choices(choices, selection.clone(), cx)
 8686                }
 8687            }
 8688
 8689            // If we're already at the last tabstop and it's at the end of the snippet,
 8690            // we're done, we don't need to keep the state around.
 8691            if !tabstop.is_end_tabstop {
 8692                let choices = tabstops
 8693                    .iter()
 8694                    .map(|tabstop| tabstop.choices.clone())
 8695                    .collect();
 8696
 8697                let ranges = tabstops
 8698                    .into_iter()
 8699                    .map(|tabstop| tabstop.ranges)
 8700                    .collect::<Vec<_>>();
 8701
 8702                self.snippet_stack.push(SnippetState {
 8703                    active_index: 0,
 8704                    ranges,
 8705                    choices,
 8706                });
 8707            }
 8708
 8709            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8710            if self.autoclose_regions.is_empty() {
 8711                let snapshot = self.buffer.read(cx).snapshot(cx);
 8712                for selection in &mut self.selections.all::<Point>(cx) {
 8713                    let selection_head = selection.head();
 8714                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8715                        continue;
 8716                    };
 8717
 8718                    let mut bracket_pair = None;
 8719                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8720                    let prev_chars = snapshot
 8721                        .reversed_chars_at(selection_head)
 8722                        .collect::<String>();
 8723                    for (pair, enabled) in scope.brackets() {
 8724                        if enabled
 8725                            && pair.close
 8726                            && prev_chars.starts_with(pair.start.as_str())
 8727                            && next_chars.starts_with(pair.end.as_str())
 8728                        {
 8729                            bracket_pair = Some(pair.clone());
 8730                            break;
 8731                        }
 8732                    }
 8733                    if let Some(pair) = bracket_pair {
 8734                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8735                        let autoclose_enabled =
 8736                            self.use_autoclose && snapshot_settings.use_autoclose;
 8737                        if autoclose_enabled {
 8738                            let start = snapshot.anchor_after(selection_head);
 8739                            let end = snapshot.anchor_after(selection_head);
 8740                            self.autoclose_regions.push(AutocloseRegion {
 8741                                selection_id: selection.id,
 8742                                range: start..end,
 8743                                pair,
 8744                            });
 8745                        }
 8746                    }
 8747                }
 8748            }
 8749        }
 8750        Ok(())
 8751    }
 8752
 8753    pub fn move_to_next_snippet_tabstop(
 8754        &mut self,
 8755        window: &mut Window,
 8756        cx: &mut Context<Self>,
 8757    ) -> bool {
 8758        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8759    }
 8760
 8761    pub fn move_to_prev_snippet_tabstop(
 8762        &mut self,
 8763        window: &mut Window,
 8764        cx: &mut Context<Self>,
 8765    ) -> bool {
 8766        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8767    }
 8768
 8769    pub fn move_to_snippet_tabstop(
 8770        &mut self,
 8771        bias: Bias,
 8772        window: &mut Window,
 8773        cx: &mut Context<Self>,
 8774    ) -> bool {
 8775        if let Some(mut snippet) = self.snippet_stack.pop() {
 8776            match bias {
 8777                Bias::Left => {
 8778                    if snippet.active_index > 0 {
 8779                        snippet.active_index -= 1;
 8780                    } else {
 8781                        self.snippet_stack.push(snippet);
 8782                        return false;
 8783                    }
 8784                }
 8785                Bias::Right => {
 8786                    if snippet.active_index + 1 < snippet.ranges.len() {
 8787                        snippet.active_index += 1;
 8788                    } else {
 8789                        self.snippet_stack.push(snippet);
 8790                        return false;
 8791                    }
 8792                }
 8793            }
 8794            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8795                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8796                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8797                });
 8798
 8799                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8800                    if let Some(selection) = current_ranges.first() {
 8801                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8802                    }
 8803                }
 8804
 8805                // If snippet state is not at the last tabstop, push it back on the stack
 8806                if snippet.active_index + 1 < snippet.ranges.len() {
 8807                    self.snippet_stack.push(snippet);
 8808                }
 8809                return true;
 8810            }
 8811        }
 8812
 8813        false
 8814    }
 8815
 8816    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8817        self.transact(window, cx, |this, window, cx| {
 8818            this.select_all(&SelectAll, window, cx);
 8819            this.insert("", window, cx);
 8820        });
 8821    }
 8822
 8823    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8824        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8825        self.transact(window, cx, |this, window, cx| {
 8826            this.select_autoclose_pair(window, cx);
 8827            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8828            if !this.linked_edit_ranges.is_empty() {
 8829                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8830                let snapshot = this.buffer.read(cx).snapshot(cx);
 8831
 8832                for selection in selections.iter() {
 8833                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8834                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8835                    if selection_start.buffer_id != selection_end.buffer_id {
 8836                        continue;
 8837                    }
 8838                    if let Some(ranges) =
 8839                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8840                    {
 8841                        for (buffer, entries) in ranges {
 8842                            linked_ranges.entry(buffer).or_default().extend(entries);
 8843                        }
 8844                    }
 8845                }
 8846            }
 8847
 8848            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8849            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8850            for selection in &mut selections {
 8851                if selection.is_empty() {
 8852                    let old_head = selection.head();
 8853                    let mut new_head =
 8854                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8855                            .to_point(&display_map);
 8856                    if let Some((buffer, line_buffer_range)) = display_map
 8857                        .buffer_snapshot
 8858                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8859                    {
 8860                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8861                        let indent_len = match indent_size.kind {
 8862                            IndentKind::Space => {
 8863                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8864                            }
 8865                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8866                        };
 8867                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8868                            let indent_len = indent_len.get();
 8869                            new_head = cmp::min(
 8870                                new_head,
 8871                                MultiBufferPoint::new(
 8872                                    old_head.row,
 8873                                    ((old_head.column - 1) / indent_len) * indent_len,
 8874                                ),
 8875                            );
 8876                        }
 8877                    }
 8878
 8879                    selection.set_head(new_head, SelectionGoal::None);
 8880                }
 8881            }
 8882
 8883            this.signature_help_state.set_backspace_pressed(true);
 8884            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8885                s.select(selections)
 8886            });
 8887            this.insert("", window, cx);
 8888            let empty_str: Arc<str> = Arc::from("");
 8889            for (buffer, edits) in linked_ranges {
 8890                let snapshot = buffer.read(cx).snapshot();
 8891                use text::ToPoint as TP;
 8892
 8893                let edits = edits
 8894                    .into_iter()
 8895                    .map(|range| {
 8896                        let end_point = TP::to_point(&range.end, &snapshot);
 8897                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8898
 8899                        if end_point == start_point {
 8900                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8901                                .saturating_sub(1);
 8902                            start_point =
 8903                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8904                        };
 8905
 8906                        (start_point..end_point, empty_str.clone())
 8907                    })
 8908                    .sorted_by_key(|(range, _)| range.start)
 8909                    .collect::<Vec<_>>();
 8910                buffer.update(cx, |this, cx| {
 8911                    this.edit(edits, None, cx);
 8912                })
 8913            }
 8914            this.refresh_inline_completion(true, false, window, cx);
 8915            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8916        });
 8917    }
 8918
 8919    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8920        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8921        self.transact(window, cx, |this, window, cx| {
 8922            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8923                s.move_with(|map, selection| {
 8924                    if selection.is_empty() {
 8925                        let cursor = movement::right(map, selection.head());
 8926                        selection.end = cursor;
 8927                        selection.reversed = true;
 8928                        selection.goal = SelectionGoal::None;
 8929                    }
 8930                })
 8931            });
 8932            this.insert("", window, cx);
 8933            this.refresh_inline_completion(true, false, window, cx);
 8934        });
 8935    }
 8936
 8937    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8938        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8939        if self.move_to_prev_snippet_tabstop(window, cx) {
 8940            return;
 8941        }
 8942        self.outdent(&Outdent, window, cx);
 8943    }
 8944
 8945    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8946        if self.move_to_next_snippet_tabstop(window, cx) {
 8947            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8948            return;
 8949        }
 8950        if self.read_only(cx) {
 8951            return;
 8952        }
 8953        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8954        let mut selections = self.selections.all_adjusted(cx);
 8955        let buffer = self.buffer.read(cx);
 8956        let snapshot = buffer.snapshot(cx);
 8957        let rows_iter = selections.iter().map(|s| s.head().row);
 8958        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8959
 8960        let has_some_cursor_in_whitespace = selections
 8961            .iter()
 8962            .filter(|selection| selection.is_empty())
 8963            .any(|selection| {
 8964                let cursor = selection.head();
 8965                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8966                cursor.column < current_indent.len
 8967            });
 8968
 8969        let mut edits = Vec::new();
 8970        let mut prev_edited_row = 0;
 8971        let mut row_delta = 0;
 8972        for selection in &mut selections {
 8973            if selection.start.row != prev_edited_row {
 8974                row_delta = 0;
 8975            }
 8976            prev_edited_row = selection.end.row;
 8977
 8978            // If the selection is non-empty, then increase the indentation of the selected lines.
 8979            if !selection.is_empty() {
 8980                row_delta =
 8981                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8982                continue;
 8983            }
 8984
 8985            let cursor = selection.head();
 8986            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8987            if let Some(suggested_indent) =
 8988                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8989            {
 8990                // Don't do anything if already at suggested indent
 8991                // and there is any other cursor which is not
 8992                if has_some_cursor_in_whitespace
 8993                    && cursor.column == current_indent.len
 8994                    && current_indent.len == suggested_indent.len
 8995                {
 8996                    continue;
 8997                }
 8998
 8999                // Adjust line and move cursor to suggested indent
 9000                // if cursor is not at suggested indent
 9001                if cursor.column < suggested_indent.len
 9002                    && cursor.column <= current_indent.len
 9003                    && current_indent.len <= suggested_indent.len
 9004                {
 9005                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9006                    selection.end = selection.start;
 9007                    if row_delta == 0 {
 9008                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9009                            cursor.row,
 9010                            current_indent,
 9011                            suggested_indent,
 9012                        ));
 9013                        row_delta = suggested_indent.len - current_indent.len;
 9014                    }
 9015                    continue;
 9016                }
 9017
 9018                // If current indent is more than suggested indent
 9019                // only move cursor to current indent and skip indent
 9020                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9021                    selection.start = Point::new(cursor.row, current_indent.len);
 9022                    selection.end = selection.start;
 9023                    continue;
 9024                }
 9025            }
 9026
 9027            // Otherwise, insert a hard or soft tab.
 9028            let settings = buffer.language_settings_at(cursor, cx);
 9029            let tab_size = if settings.hard_tabs {
 9030                IndentSize::tab()
 9031            } else {
 9032                let tab_size = settings.tab_size.get();
 9033                let indent_remainder = snapshot
 9034                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9035                    .flat_map(str::chars)
 9036                    .fold(row_delta % tab_size, |counter: u32, c| {
 9037                        if c == '\t' {
 9038                            0
 9039                        } else {
 9040                            (counter + 1) % tab_size
 9041                        }
 9042                    });
 9043
 9044                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9045                IndentSize::spaces(chars_to_next_tab_stop)
 9046            };
 9047            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9048            selection.end = selection.start;
 9049            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9050            row_delta += tab_size.len;
 9051        }
 9052
 9053        self.transact(window, cx, |this, window, cx| {
 9054            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9055            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9056                s.select(selections)
 9057            });
 9058            this.refresh_inline_completion(true, false, window, cx);
 9059        });
 9060    }
 9061
 9062    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9063        if self.read_only(cx) {
 9064            return;
 9065        }
 9066        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9067        let mut selections = self.selections.all::<Point>(cx);
 9068        let mut prev_edited_row = 0;
 9069        let mut row_delta = 0;
 9070        let mut edits = Vec::new();
 9071        let buffer = self.buffer.read(cx);
 9072        let snapshot = buffer.snapshot(cx);
 9073        for selection in &mut selections {
 9074            if selection.start.row != prev_edited_row {
 9075                row_delta = 0;
 9076            }
 9077            prev_edited_row = selection.end.row;
 9078
 9079            row_delta =
 9080                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9081        }
 9082
 9083        self.transact(window, cx, |this, window, cx| {
 9084            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9085            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9086                s.select(selections)
 9087            });
 9088        });
 9089    }
 9090
 9091    fn indent_selection(
 9092        buffer: &MultiBuffer,
 9093        snapshot: &MultiBufferSnapshot,
 9094        selection: &mut Selection<Point>,
 9095        edits: &mut Vec<(Range<Point>, String)>,
 9096        delta_for_start_row: u32,
 9097        cx: &App,
 9098    ) -> u32 {
 9099        let settings = buffer.language_settings_at(selection.start, cx);
 9100        let tab_size = settings.tab_size.get();
 9101        let indent_kind = if settings.hard_tabs {
 9102            IndentKind::Tab
 9103        } else {
 9104            IndentKind::Space
 9105        };
 9106        let mut start_row = selection.start.row;
 9107        let mut end_row = selection.end.row + 1;
 9108
 9109        // If a selection ends at the beginning of a line, don't indent
 9110        // that last line.
 9111        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9112            end_row -= 1;
 9113        }
 9114
 9115        // Avoid re-indenting a row that has already been indented by a
 9116        // previous selection, but still update this selection's column
 9117        // to reflect that indentation.
 9118        if delta_for_start_row > 0 {
 9119            start_row += 1;
 9120            selection.start.column += delta_for_start_row;
 9121            if selection.end.row == selection.start.row {
 9122                selection.end.column += delta_for_start_row;
 9123            }
 9124        }
 9125
 9126        let mut delta_for_end_row = 0;
 9127        let has_multiple_rows = start_row + 1 != end_row;
 9128        for row in start_row..end_row {
 9129            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9130            let indent_delta = match (current_indent.kind, indent_kind) {
 9131                (IndentKind::Space, IndentKind::Space) => {
 9132                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9133                    IndentSize::spaces(columns_to_next_tab_stop)
 9134                }
 9135                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9136                (_, IndentKind::Tab) => IndentSize::tab(),
 9137            };
 9138
 9139            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9140                0
 9141            } else {
 9142                selection.start.column
 9143            };
 9144            let row_start = Point::new(row, start);
 9145            edits.push((
 9146                row_start..row_start,
 9147                indent_delta.chars().collect::<String>(),
 9148            ));
 9149
 9150            // Update this selection's endpoints to reflect the indentation.
 9151            if row == selection.start.row {
 9152                selection.start.column += indent_delta.len;
 9153            }
 9154            if row == selection.end.row {
 9155                selection.end.column += indent_delta.len;
 9156                delta_for_end_row = indent_delta.len;
 9157            }
 9158        }
 9159
 9160        if selection.start.row == selection.end.row {
 9161            delta_for_start_row + delta_for_end_row
 9162        } else {
 9163            delta_for_end_row
 9164        }
 9165    }
 9166
 9167    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9168        if self.read_only(cx) {
 9169            return;
 9170        }
 9171        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9172        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9173        let selections = self.selections.all::<Point>(cx);
 9174        let mut deletion_ranges = Vec::new();
 9175        let mut last_outdent = None;
 9176        {
 9177            let buffer = self.buffer.read(cx);
 9178            let snapshot = buffer.snapshot(cx);
 9179            for selection in &selections {
 9180                let settings = buffer.language_settings_at(selection.start, cx);
 9181                let tab_size = settings.tab_size.get();
 9182                let mut rows = selection.spanned_rows(false, &display_map);
 9183
 9184                // Avoid re-outdenting a row that has already been outdented by a
 9185                // previous selection.
 9186                if let Some(last_row) = last_outdent {
 9187                    if last_row == rows.start {
 9188                        rows.start = rows.start.next_row();
 9189                    }
 9190                }
 9191                let has_multiple_rows = rows.len() > 1;
 9192                for row in rows.iter_rows() {
 9193                    let indent_size = snapshot.indent_size_for_line(row);
 9194                    if indent_size.len > 0 {
 9195                        let deletion_len = match indent_size.kind {
 9196                            IndentKind::Space => {
 9197                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9198                                if columns_to_prev_tab_stop == 0 {
 9199                                    tab_size
 9200                                } else {
 9201                                    columns_to_prev_tab_stop
 9202                                }
 9203                            }
 9204                            IndentKind::Tab => 1,
 9205                        };
 9206                        let start = if has_multiple_rows
 9207                            || deletion_len > selection.start.column
 9208                            || indent_size.len < selection.start.column
 9209                        {
 9210                            0
 9211                        } else {
 9212                            selection.start.column - deletion_len
 9213                        };
 9214                        deletion_ranges.push(
 9215                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9216                        );
 9217                        last_outdent = Some(row);
 9218                    }
 9219                }
 9220            }
 9221        }
 9222
 9223        self.transact(window, cx, |this, window, cx| {
 9224            this.buffer.update(cx, |buffer, cx| {
 9225                let empty_str: Arc<str> = Arc::default();
 9226                buffer.edit(
 9227                    deletion_ranges
 9228                        .into_iter()
 9229                        .map(|range| (range, empty_str.clone())),
 9230                    None,
 9231                    cx,
 9232                );
 9233            });
 9234            let selections = this.selections.all::<usize>(cx);
 9235            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9236                s.select(selections)
 9237            });
 9238        });
 9239    }
 9240
 9241    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9242        if self.read_only(cx) {
 9243            return;
 9244        }
 9245        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9246        let selections = self
 9247            .selections
 9248            .all::<usize>(cx)
 9249            .into_iter()
 9250            .map(|s| s.range());
 9251
 9252        self.transact(window, cx, |this, window, cx| {
 9253            this.buffer.update(cx, |buffer, cx| {
 9254                buffer.autoindent_ranges(selections, cx);
 9255            });
 9256            let selections = this.selections.all::<usize>(cx);
 9257            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9258                s.select(selections)
 9259            });
 9260        });
 9261    }
 9262
 9263    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9264        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9265        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9266        let selections = self.selections.all::<Point>(cx);
 9267
 9268        let mut new_cursors = Vec::new();
 9269        let mut edit_ranges = Vec::new();
 9270        let mut selections = selections.iter().peekable();
 9271        while let Some(selection) = selections.next() {
 9272            let mut rows = selection.spanned_rows(false, &display_map);
 9273            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9274
 9275            // Accumulate contiguous regions of rows that we want to delete.
 9276            while let Some(next_selection) = selections.peek() {
 9277                let next_rows = next_selection.spanned_rows(false, &display_map);
 9278                if next_rows.start <= rows.end {
 9279                    rows.end = next_rows.end;
 9280                    selections.next().unwrap();
 9281                } else {
 9282                    break;
 9283                }
 9284            }
 9285
 9286            let buffer = &display_map.buffer_snapshot;
 9287            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9288            let edit_end;
 9289            let cursor_buffer_row;
 9290            if buffer.max_point().row >= rows.end.0 {
 9291                // If there's a line after the range, delete the \n from the end of the row range
 9292                // and position the cursor on the next line.
 9293                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9294                cursor_buffer_row = rows.end;
 9295            } else {
 9296                // If there isn't a line after the range, delete the \n from the line before the
 9297                // start of the row range and position the cursor there.
 9298                edit_start = edit_start.saturating_sub(1);
 9299                edit_end = buffer.len();
 9300                cursor_buffer_row = rows.start.previous_row();
 9301            }
 9302
 9303            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9304            *cursor.column_mut() =
 9305                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9306
 9307            new_cursors.push((
 9308                selection.id,
 9309                buffer.anchor_after(cursor.to_point(&display_map)),
 9310            ));
 9311            edit_ranges.push(edit_start..edit_end);
 9312        }
 9313
 9314        self.transact(window, cx, |this, window, cx| {
 9315            let buffer = this.buffer.update(cx, |buffer, cx| {
 9316                let empty_str: Arc<str> = Arc::default();
 9317                buffer.edit(
 9318                    edit_ranges
 9319                        .into_iter()
 9320                        .map(|range| (range, empty_str.clone())),
 9321                    None,
 9322                    cx,
 9323                );
 9324                buffer.snapshot(cx)
 9325            });
 9326            let new_selections = new_cursors
 9327                .into_iter()
 9328                .map(|(id, cursor)| {
 9329                    let cursor = cursor.to_point(&buffer);
 9330                    Selection {
 9331                        id,
 9332                        start: cursor,
 9333                        end: cursor,
 9334                        reversed: false,
 9335                        goal: SelectionGoal::None,
 9336                    }
 9337                })
 9338                .collect();
 9339
 9340            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9341                s.select(new_selections);
 9342            });
 9343        });
 9344    }
 9345
 9346    pub fn join_lines_impl(
 9347        &mut self,
 9348        insert_whitespace: bool,
 9349        window: &mut Window,
 9350        cx: &mut Context<Self>,
 9351    ) {
 9352        if self.read_only(cx) {
 9353            return;
 9354        }
 9355        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9356        for selection in self.selections.all::<Point>(cx) {
 9357            let start = MultiBufferRow(selection.start.row);
 9358            // Treat single line selections as if they include the next line. Otherwise this action
 9359            // would do nothing for single line selections individual cursors.
 9360            let end = if selection.start.row == selection.end.row {
 9361                MultiBufferRow(selection.start.row + 1)
 9362            } else {
 9363                MultiBufferRow(selection.end.row)
 9364            };
 9365
 9366            if let Some(last_row_range) = row_ranges.last_mut() {
 9367                if start <= last_row_range.end {
 9368                    last_row_range.end = end;
 9369                    continue;
 9370                }
 9371            }
 9372            row_ranges.push(start..end);
 9373        }
 9374
 9375        let snapshot = self.buffer.read(cx).snapshot(cx);
 9376        let mut cursor_positions = Vec::new();
 9377        for row_range in &row_ranges {
 9378            let anchor = snapshot.anchor_before(Point::new(
 9379                row_range.end.previous_row().0,
 9380                snapshot.line_len(row_range.end.previous_row()),
 9381            ));
 9382            cursor_positions.push(anchor..anchor);
 9383        }
 9384
 9385        self.transact(window, cx, |this, window, cx| {
 9386            for row_range in row_ranges.into_iter().rev() {
 9387                for row in row_range.iter_rows().rev() {
 9388                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9389                    let next_line_row = row.next_row();
 9390                    let indent = snapshot.indent_size_for_line(next_line_row);
 9391                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9392
 9393                    let replace =
 9394                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9395                            " "
 9396                        } else {
 9397                            ""
 9398                        };
 9399
 9400                    this.buffer.update(cx, |buffer, cx| {
 9401                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9402                    });
 9403                }
 9404            }
 9405
 9406            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9407                s.select_anchor_ranges(cursor_positions)
 9408            });
 9409        });
 9410    }
 9411
 9412    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9413        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9414        self.join_lines_impl(true, window, cx);
 9415    }
 9416
 9417    pub fn sort_lines_case_sensitive(
 9418        &mut self,
 9419        _: &SortLinesCaseSensitive,
 9420        window: &mut Window,
 9421        cx: &mut Context<Self>,
 9422    ) {
 9423        self.manipulate_lines(window, cx, |lines| lines.sort())
 9424    }
 9425
 9426    pub fn sort_lines_case_insensitive(
 9427        &mut self,
 9428        _: &SortLinesCaseInsensitive,
 9429        window: &mut Window,
 9430        cx: &mut Context<Self>,
 9431    ) {
 9432        self.manipulate_lines(window, cx, |lines| {
 9433            lines.sort_by_key(|line| line.to_lowercase())
 9434        })
 9435    }
 9436
 9437    pub fn unique_lines_case_insensitive(
 9438        &mut self,
 9439        _: &UniqueLinesCaseInsensitive,
 9440        window: &mut Window,
 9441        cx: &mut Context<Self>,
 9442    ) {
 9443        self.manipulate_lines(window, cx, |lines| {
 9444            let mut seen = HashSet::default();
 9445            lines.retain(|line| seen.insert(line.to_lowercase()));
 9446        })
 9447    }
 9448
 9449    pub fn unique_lines_case_sensitive(
 9450        &mut self,
 9451        _: &UniqueLinesCaseSensitive,
 9452        window: &mut Window,
 9453        cx: &mut Context<Self>,
 9454    ) {
 9455        self.manipulate_lines(window, cx, |lines| {
 9456            let mut seen = HashSet::default();
 9457            lines.retain(|line| seen.insert(*line));
 9458        })
 9459    }
 9460
 9461    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9462        let Some(project) = self.project.clone() else {
 9463            return;
 9464        };
 9465        self.reload(project, window, cx)
 9466            .detach_and_notify_err(window, cx);
 9467    }
 9468
 9469    pub fn restore_file(
 9470        &mut self,
 9471        _: &::git::RestoreFile,
 9472        window: &mut Window,
 9473        cx: &mut Context<Self>,
 9474    ) {
 9475        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9476        let mut buffer_ids = HashSet::default();
 9477        let snapshot = self.buffer().read(cx).snapshot(cx);
 9478        for selection in self.selections.all::<usize>(cx) {
 9479            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9480        }
 9481
 9482        let buffer = self.buffer().read(cx);
 9483        let ranges = buffer_ids
 9484            .into_iter()
 9485            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9486            .collect::<Vec<_>>();
 9487
 9488        self.restore_hunks_in_ranges(ranges, window, cx);
 9489    }
 9490
 9491    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9492        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9493        let selections = self
 9494            .selections
 9495            .all(cx)
 9496            .into_iter()
 9497            .map(|s| s.range())
 9498            .collect();
 9499        self.restore_hunks_in_ranges(selections, window, cx);
 9500    }
 9501
 9502    pub fn restore_hunks_in_ranges(
 9503        &mut self,
 9504        ranges: Vec<Range<Point>>,
 9505        window: &mut Window,
 9506        cx: &mut Context<Editor>,
 9507    ) {
 9508        let mut revert_changes = HashMap::default();
 9509        let chunk_by = self
 9510            .snapshot(window, cx)
 9511            .hunks_for_ranges(ranges)
 9512            .into_iter()
 9513            .chunk_by(|hunk| hunk.buffer_id);
 9514        for (buffer_id, hunks) in &chunk_by {
 9515            let hunks = hunks.collect::<Vec<_>>();
 9516            for hunk in &hunks {
 9517                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9518            }
 9519            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9520        }
 9521        drop(chunk_by);
 9522        if !revert_changes.is_empty() {
 9523            self.transact(window, cx, |editor, window, cx| {
 9524                editor.restore(revert_changes, window, cx);
 9525            });
 9526        }
 9527    }
 9528
 9529    pub fn open_active_item_in_terminal(
 9530        &mut self,
 9531        _: &OpenInTerminal,
 9532        window: &mut Window,
 9533        cx: &mut Context<Self>,
 9534    ) {
 9535        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9536            let project_path = buffer.read(cx).project_path(cx)?;
 9537            let project = self.project.as_ref()?.read(cx);
 9538            let entry = project.entry_for_path(&project_path, cx)?;
 9539            let parent = match &entry.canonical_path {
 9540                Some(canonical_path) => canonical_path.to_path_buf(),
 9541                None => project.absolute_path(&project_path, cx)?,
 9542            }
 9543            .parent()?
 9544            .to_path_buf();
 9545            Some(parent)
 9546        }) {
 9547            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9548        }
 9549    }
 9550
 9551    fn set_breakpoint_context_menu(
 9552        &mut self,
 9553        display_row: DisplayRow,
 9554        position: Option<Anchor>,
 9555        clicked_point: gpui::Point<Pixels>,
 9556        window: &mut Window,
 9557        cx: &mut Context<Self>,
 9558    ) {
 9559        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9560            return;
 9561        }
 9562        let source = self
 9563            .buffer
 9564            .read(cx)
 9565            .snapshot(cx)
 9566            .anchor_before(Point::new(display_row.0, 0u32));
 9567
 9568        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9569
 9570        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9571            self,
 9572            source,
 9573            clicked_point,
 9574            context_menu,
 9575            window,
 9576            cx,
 9577        );
 9578    }
 9579
 9580    fn add_edit_breakpoint_block(
 9581        &mut self,
 9582        anchor: Anchor,
 9583        breakpoint: &Breakpoint,
 9584        edit_action: BreakpointPromptEditAction,
 9585        window: &mut Window,
 9586        cx: &mut Context<Self>,
 9587    ) {
 9588        let weak_editor = cx.weak_entity();
 9589        let bp_prompt = cx.new(|cx| {
 9590            BreakpointPromptEditor::new(
 9591                weak_editor,
 9592                anchor,
 9593                breakpoint.clone(),
 9594                edit_action,
 9595                window,
 9596                cx,
 9597            )
 9598        });
 9599
 9600        let height = bp_prompt.update(cx, |this, cx| {
 9601            this.prompt
 9602                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9603        });
 9604        let cloned_prompt = bp_prompt.clone();
 9605        let blocks = vec![BlockProperties {
 9606            style: BlockStyle::Sticky,
 9607            placement: BlockPlacement::Above(anchor),
 9608            height: Some(height),
 9609            render: Arc::new(move |cx| {
 9610                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9611                cloned_prompt.clone().into_any_element()
 9612            }),
 9613            priority: 0,
 9614            render_in_minimap: true,
 9615        }];
 9616
 9617        let focus_handle = bp_prompt.focus_handle(cx);
 9618        window.focus(&focus_handle);
 9619
 9620        let block_ids = self.insert_blocks(blocks, None, cx);
 9621        bp_prompt.update(cx, |prompt, _| {
 9622            prompt.add_block_ids(block_ids);
 9623        });
 9624    }
 9625
 9626    pub(crate) fn breakpoint_at_row(
 9627        &self,
 9628        row: u32,
 9629        window: &mut Window,
 9630        cx: &mut Context<Self>,
 9631    ) -> Option<(Anchor, Breakpoint)> {
 9632        let snapshot = self.snapshot(window, cx);
 9633        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9634
 9635        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9636    }
 9637
 9638    pub(crate) fn breakpoint_at_anchor(
 9639        &self,
 9640        breakpoint_position: Anchor,
 9641        snapshot: &EditorSnapshot,
 9642        cx: &mut Context<Self>,
 9643    ) -> Option<(Anchor, Breakpoint)> {
 9644        let project = self.project.clone()?;
 9645
 9646        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9647            snapshot
 9648                .buffer_snapshot
 9649                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9650        })?;
 9651
 9652        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9653        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9654        let buffer_snapshot = buffer.read(cx).snapshot();
 9655
 9656        let row = buffer_snapshot
 9657            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9658            .row;
 9659
 9660        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9661        let anchor_end = snapshot
 9662            .buffer_snapshot
 9663            .anchor_after(Point::new(row, line_len));
 9664
 9665        let bp = self
 9666            .breakpoint_store
 9667            .as_ref()?
 9668            .read_with(cx, |breakpoint_store, cx| {
 9669                breakpoint_store
 9670                    .breakpoints(
 9671                        &buffer,
 9672                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9673                        &buffer_snapshot,
 9674                        cx,
 9675                    )
 9676                    .next()
 9677                    .and_then(|(bp, _)| {
 9678                        let breakpoint_row = buffer_snapshot
 9679                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9680                            .row;
 9681
 9682                        if breakpoint_row == row {
 9683                            snapshot
 9684                                .buffer_snapshot
 9685                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9686                                .map(|position| (position, bp.bp.clone()))
 9687                        } else {
 9688                            None
 9689                        }
 9690                    })
 9691            });
 9692        bp
 9693    }
 9694
 9695    pub fn edit_log_breakpoint(
 9696        &mut self,
 9697        _: &EditLogBreakpoint,
 9698        window: &mut Window,
 9699        cx: &mut Context<Self>,
 9700    ) {
 9701        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9702            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9703                message: None,
 9704                state: BreakpointState::Enabled,
 9705                condition: None,
 9706                hit_condition: None,
 9707            });
 9708
 9709            self.add_edit_breakpoint_block(
 9710                anchor,
 9711                &breakpoint,
 9712                BreakpointPromptEditAction::Log,
 9713                window,
 9714                cx,
 9715            );
 9716        }
 9717    }
 9718
 9719    fn breakpoints_at_cursors(
 9720        &self,
 9721        window: &mut Window,
 9722        cx: &mut Context<Self>,
 9723    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9724        let snapshot = self.snapshot(window, cx);
 9725        let cursors = self
 9726            .selections
 9727            .disjoint_anchors()
 9728            .into_iter()
 9729            .map(|selection| {
 9730                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9731
 9732                let breakpoint_position = self
 9733                    .breakpoint_at_row(cursor_position.row, window, cx)
 9734                    .map(|bp| bp.0)
 9735                    .unwrap_or_else(|| {
 9736                        snapshot
 9737                            .display_snapshot
 9738                            .buffer_snapshot
 9739                            .anchor_after(Point::new(cursor_position.row, 0))
 9740                    });
 9741
 9742                let breakpoint = self
 9743                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9744                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9745
 9746                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9747            })
 9748            // 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.
 9749            .collect::<HashMap<Anchor, _>>();
 9750
 9751        cursors.into_iter().collect()
 9752    }
 9753
 9754    pub fn enable_breakpoint(
 9755        &mut self,
 9756        _: &crate::actions::EnableBreakpoint,
 9757        window: &mut Window,
 9758        cx: &mut Context<Self>,
 9759    ) {
 9760        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9761            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9762                continue;
 9763            };
 9764            self.edit_breakpoint_at_anchor(
 9765                anchor,
 9766                breakpoint,
 9767                BreakpointEditAction::InvertState,
 9768                cx,
 9769            );
 9770        }
 9771    }
 9772
 9773    pub fn disable_breakpoint(
 9774        &mut self,
 9775        _: &crate::actions::DisableBreakpoint,
 9776        window: &mut Window,
 9777        cx: &mut Context<Self>,
 9778    ) {
 9779        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9780            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9781                continue;
 9782            };
 9783            self.edit_breakpoint_at_anchor(
 9784                anchor,
 9785                breakpoint,
 9786                BreakpointEditAction::InvertState,
 9787                cx,
 9788            );
 9789        }
 9790    }
 9791
 9792    pub fn toggle_breakpoint(
 9793        &mut self,
 9794        _: &crate::actions::ToggleBreakpoint,
 9795        window: &mut Window,
 9796        cx: &mut Context<Self>,
 9797    ) {
 9798        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9799            if let Some(breakpoint) = breakpoint {
 9800                self.edit_breakpoint_at_anchor(
 9801                    anchor,
 9802                    breakpoint,
 9803                    BreakpointEditAction::Toggle,
 9804                    cx,
 9805                );
 9806            } else {
 9807                self.edit_breakpoint_at_anchor(
 9808                    anchor,
 9809                    Breakpoint::new_standard(),
 9810                    BreakpointEditAction::Toggle,
 9811                    cx,
 9812                );
 9813            }
 9814        }
 9815    }
 9816
 9817    pub fn edit_breakpoint_at_anchor(
 9818        &mut self,
 9819        breakpoint_position: Anchor,
 9820        breakpoint: Breakpoint,
 9821        edit_action: BreakpointEditAction,
 9822        cx: &mut Context<Self>,
 9823    ) {
 9824        let Some(breakpoint_store) = &self.breakpoint_store else {
 9825            return;
 9826        };
 9827
 9828        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9829            if breakpoint_position == Anchor::min() {
 9830                self.buffer()
 9831                    .read(cx)
 9832                    .excerpt_buffer_ids()
 9833                    .into_iter()
 9834                    .next()
 9835            } else {
 9836                None
 9837            }
 9838        }) else {
 9839            return;
 9840        };
 9841
 9842        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9843            return;
 9844        };
 9845
 9846        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9847            breakpoint_store.toggle_breakpoint(
 9848                buffer,
 9849                BreakpointWithPosition {
 9850                    position: breakpoint_position.text_anchor,
 9851                    bp: breakpoint,
 9852                },
 9853                edit_action,
 9854                cx,
 9855            );
 9856        });
 9857
 9858        cx.notify();
 9859    }
 9860
 9861    #[cfg(any(test, feature = "test-support"))]
 9862    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9863        self.breakpoint_store.clone()
 9864    }
 9865
 9866    pub fn prepare_restore_change(
 9867        &self,
 9868        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9869        hunk: &MultiBufferDiffHunk,
 9870        cx: &mut App,
 9871    ) -> Option<()> {
 9872        if hunk.is_created_file() {
 9873            return None;
 9874        }
 9875        let buffer = self.buffer.read(cx);
 9876        let diff = buffer.diff_for(hunk.buffer_id)?;
 9877        let buffer = buffer.buffer(hunk.buffer_id)?;
 9878        let buffer = buffer.read(cx);
 9879        let original_text = diff
 9880            .read(cx)
 9881            .base_text()
 9882            .as_rope()
 9883            .slice(hunk.diff_base_byte_range.clone());
 9884        let buffer_snapshot = buffer.snapshot();
 9885        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9886        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9887            probe
 9888                .0
 9889                .start
 9890                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9891                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9892        }) {
 9893            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9894            Some(())
 9895        } else {
 9896            None
 9897        }
 9898    }
 9899
 9900    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9901        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9902    }
 9903
 9904    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9905        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9906    }
 9907
 9908    fn manipulate_lines<Fn>(
 9909        &mut self,
 9910        window: &mut Window,
 9911        cx: &mut Context<Self>,
 9912        mut callback: Fn,
 9913    ) where
 9914        Fn: FnMut(&mut Vec<&str>),
 9915    {
 9916        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9917
 9918        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9919        let buffer = self.buffer.read(cx).snapshot(cx);
 9920
 9921        let mut edits = Vec::new();
 9922
 9923        let selections = self.selections.all::<Point>(cx);
 9924        let mut selections = selections.iter().peekable();
 9925        let mut contiguous_row_selections = Vec::new();
 9926        let mut new_selections = Vec::new();
 9927        let mut added_lines = 0;
 9928        let mut removed_lines = 0;
 9929
 9930        while let Some(selection) = selections.next() {
 9931            let (start_row, end_row) = consume_contiguous_rows(
 9932                &mut contiguous_row_selections,
 9933                selection,
 9934                &display_map,
 9935                &mut selections,
 9936            );
 9937
 9938            let start_point = Point::new(start_row.0, 0);
 9939            let end_point = Point::new(
 9940                end_row.previous_row().0,
 9941                buffer.line_len(end_row.previous_row()),
 9942            );
 9943            let text = buffer
 9944                .text_for_range(start_point..end_point)
 9945                .collect::<String>();
 9946
 9947            let mut lines = text.split('\n').collect_vec();
 9948
 9949            let lines_before = lines.len();
 9950            callback(&mut lines);
 9951            let lines_after = lines.len();
 9952
 9953            edits.push((start_point..end_point, lines.join("\n")));
 9954
 9955            // Selections must change based on added and removed line count
 9956            let start_row =
 9957                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9958            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9959            new_selections.push(Selection {
 9960                id: selection.id,
 9961                start: start_row,
 9962                end: end_row,
 9963                goal: SelectionGoal::None,
 9964                reversed: selection.reversed,
 9965            });
 9966
 9967            if lines_after > lines_before {
 9968                added_lines += lines_after - lines_before;
 9969            } else if lines_before > lines_after {
 9970                removed_lines += lines_before - lines_after;
 9971            }
 9972        }
 9973
 9974        self.transact(window, cx, |this, window, cx| {
 9975            let buffer = this.buffer.update(cx, |buffer, cx| {
 9976                buffer.edit(edits, None, cx);
 9977                buffer.snapshot(cx)
 9978            });
 9979
 9980            // Recalculate offsets on newly edited buffer
 9981            let new_selections = new_selections
 9982                .iter()
 9983                .map(|s| {
 9984                    let start_point = Point::new(s.start.0, 0);
 9985                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9986                    Selection {
 9987                        id: s.id,
 9988                        start: buffer.point_to_offset(start_point),
 9989                        end: buffer.point_to_offset(end_point),
 9990                        goal: s.goal,
 9991                        reversed: s.reversed,
 9992                    }
 9993                })
 9994                .collect();
 9995
 9996            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9997                s.select(new_selections);
 9998            });
 9999
10000            this.request_autoscroll(Autoscroll::fit(), cx);
10001        });
10002    }
10003
10004    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10005        self.manipulate_text(window, cx, |text| {
10006            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10007            if has_upper_case_characters {
10008                text.to_lowercase()
10009            } else {
10010                text.to_uppercase()
10011            }
10012        })
10013    }
10014
10015    pub fn convert_to_upper_case(
10016        &mut self,
10017        _: &ConvertToUpperCase,
10018        window: &mut Window,
10019        cx: &mut Context<Self>,
10020    ) {
10021        self.manipulate_text(window, cx, |text| text.to_uppercase())
10022    }
10023
10024    pub fn convert_to_lower_case(
10025        &mut self,
10026        _: &ConvertToLowerCase,
10027        window: &mut Window,
10028        cx: &mut Context<Self>,
10029    ) {
10030        self.manipulate_text(window, cx, |text| text.to_lowercase())
10031    }
10032
10033    pub fn convert_to_title_case(
10034        &mut self,
10035        _: &ConvertToTitleCase,
10036        window: &mut Window,
10037        cx: &mut Context<Self>,
10038    ) {
10039        self.manipulate_text(window, cx, |text| {
10040            text.split('\n')
10041                .map(|line| line.to_case(Case::Title))
10042                .join("\n")
10043        })
10044    }
10045
10046    pub fn convert_to_snake_case(
10047        &mut self,
10048        _: &ConvertToSnakeCase,
10049        window: &mut Window,
10050        cx: &mut Context<Self>,
10051    ) {
10052        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10053    }
10054
10055    pub fn convert_to_kebab_case(
10056        &mut self,
10057        _: &ConvertToKebabCase,
10058        window: &mut Window,
10059        cx: &mut Context<Self>,
10060    ) {
10061        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10062    }
10063
10064    pub fn convert_to_upper_camel_case(
10065        &mut self,
10066        _: &ConvertToUpperCamelCase,
10067        window: &mut Window,
10068        cx: &mut Context<Self>,
10069    ) {
10070        self.manipulate_text(window, cx, |text| {
10071            text.split('\n')
10072                .map(|line| line.to_case(Case::UpperCamel))
10073                .join("\n")
10074        })
10075    }
10076
10077    pub fn convert_to_lower_camel_case(
10078        &mut self,
10079        _: &ConvertToLowerCamelCase,
10080        window: &mut Window,
10081        cx: &mut Context<Self>,
10082    ) {
10083        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10084    }
10085
10086    pub fn convert_to_opposite_case(
10087        &mut self,
10088        _: &ConvertToOppositeCase,
10089        window: &mut Window,
10090        cx: &mut Context<Self>,
10091    ) {
10092        self.manipulate_text(window, cx, |text| {
10093            text.chars()
10094                .fold(String::with_capacity(text.len()), |mut t, c| {
10095                    if c.is_uppercase() {
10096                        t.extend(c.to_lowercase());
10097                    } else {
10098                        t.extend(c.to_uppercase());
10099                    }
10100                    t
10101                })
10102        })
10103    }
10104
10105    pub fn convert_to_rot13(
10106        &mut self,
10107        _: &ConvertToRot13,
10108        window: &mut Window,
10109        cx: &mut Context<Self>,
10110    ) {
10111        self.manipulate_text(window, cx, |text| {
10112            text.chars()
10113                .map(|c| match c {
10114                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10115                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10116                    _ => c,
10117                })
10118                .collect()
10119        })
10120    }
10121
10122    pub fn convert_to_rot47(
10123        &mut self,
10124        _: &ConvertToRot47,
10125        window: &mut Window,
10126        cx: &mut Context<Self>,
10127    ) {
10128        self.manipulate_text(window, cx, |text| {
10129            text.chars()
10130                .map(|c| {
10131                    let code_point = c as u32;
10132                    if code_point >= 33 && code_point <= 126 {
10133                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10134                    }
10135                    c
10136                })
10137                .collect()
10138        })
10139    }
10140
10141    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10142    where
10143        Fn: FnMut(&str) -> String,
10144    {
10145        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10146        let buffer = self.buffer.read(cx).snapshot(cx);
10147
10148        let mut new_selections = Vec::new();
10149        let mut edits = Vec::new();
10150        let mut selection_adjustment = 0i32;
10151
10152        for selection in self.selections.all::<usize>(cx) {
10153            let selection_is_empty = selection.is_empty();
10154
10155            let (start, end) = if selection_is_empty {
10156                let word_range = movement::surrounding_word(
10157                    &display_map,
10158                    selection.start.to_display_point(&display_map),
10159                );
10160                let start = word_range.start.to_offset(&display_map, Bias::Left);
10161                let end = word_range.end.to_offset(&display_map, Bias::Left);
10162                (start, end)
10163            } else {
10164                (selection.start, selection.end)
10165            };
10166
10167            let text = buffer.text_for_range(start..end).collect::<String>();
10168            let old_length = text.len() as i32;
10169            let text = callback(&text);
10170
10171            new_selections.push(Selection {
10172                start: (start as i32 - selection_adjustment) as usize,
10173                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10174                goal: SelectionGoal::None,
10175                ..selection
10176            });
10177
10178            selection_adjustment += old_length - text.len() as i32;
10179
10180            edits.push((start..end, text));
10181        }
10182
10183        self.transact(window, cx, |this, window, cx| {
10184            this.buffer.update(cx, |buffer, cx| {
10185                buffer.edit(edits, None, cx);
10186            });
10187
10188            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10189                s.select(new_selections);
10190            });
10191
10192            this.request_autoscroll(Autoscroll::fit(), cx);
10193        });
10194    }
10195
10196    pub fn duplicate(
10197        &mut self,
10198        upwards: bool,
10199        whole_lines: bool,
10200        window: &mut Window,
10201        cx: &mut Context<Self>,
10202    ) {
10203        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10204
10205        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10206        let buffer = &display_map.buffer_snapshot;
10207        let selections = self.selections.all::<Point>(cx);
10208
10209        let mut edits = Vec::new();
10210        let mut selections_iter = selections.iter().peekable();
10211        while let Some(selection) = selections_iter.next() {
10212            let mut rows = selection.spanned_rows(false, &display_map);
10213            // duplicate line-wise
10214            if whole_lines || selection.start == selection.end {
10215                // Avoid duplicating the same lines twice.
10216                while let Some(next_selection) = selections_iter.peek() {
10217                    let next_rows = next_selection.spanned_rows(false, &display_map);
10218                    if next_rows.start < rows.end {
10219                        rows.end = next_rows.end;
10220                        selections_iter.next().unwrap();
10221                    } else {
10222                        break;
10223                    }
10224                }
10225
10226                // Copy the text from the selected row region and splice it either at the start
10227                // or end of the region.
10228                let start = Point::new(rows.start.0, 0);
10229                let end = Point::new(
10230                    rows.end.previous_row().0,
10231                    buffer.line_len(rows.end.previous_row()),
10232                );
10233                let text = buffer
10234                    .text_for_range(start..end)
10235                    .chain(Some("\n"))
10236                    .collect::<String>();
10237                let insert_location = if upwards {
10238                    Point::new(rows.end.0, 0)
10239                } else {
10240                    start
10241                };
10242                edits.push((insert_location..insert_location, text));
10243            } else {
10244                // duplicate character-wise
10245                let start = selection.start;
10246                let end = selection.end;
10247                let text = buffer.text_for_range(start..end).collect::<String>();
10248                edits.push((selection.end..selection.end, text));
10249            }
10250        }
10251
10252        self.transact(window, cx, |this, _, cx| {
10253            this.buffer.update(cx, |buffer, cx| {
10254                buffer.edit(edits, None, cx);
10255            });
10256
10257            this.request_autoscroll(Autoscroll::fit(), cx);
10258        });
10259    }
10260
10261    pub fn duplicate_line_up(
10262        &mut self,
10263        _: &DuplicateLineUp,
10264        window: &mut Window,
10265        cx: &mut Context<Self>,
10266    ) {
10267        self.duplicate(true, true, window, cx);
10268    }
10269
10270    pub fn duplicate_line_down(
10271        &mut self,
10272        _: &DuplicateLineDown,
10273        window: &mut Window,
10274        cx: &mut Context<Self>,
10275    ) {
10276        self.duplicate(false, true, window, cx);
10277    }
10278
10279    pub fn duplicate_selection(
10280        &mut self,
10281        _: &DuplicateSelection,
10282        window: &mut Window,
10283        cx: &mut Context<Self>,
10284    ) {
10285        self.duplicate(false, false, window, cx);
10286    }
10287
10288    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10289        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10290
10291        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10292        let buffer = self.buffer.read(cx).snapshot(cx);
10293
10294        let mut edits = Vec::new();
10295        let mut unfold_ranges = Vec::new();
10296        let mut refold_creases = Vec::new();
10297
10298        let selections = self.selections.all::<Point>(cx);
10299        let mut selections = selections.iter().peekable();
10300        let mut contiguous_row_selections = Vec::new();
10301        let mut new_selections = Vec::new();
10302
10303        while let Some(selection) = selections.next() {
10304            // Find all the selections that span a contiguous row range
10305            let (start_row, end_row) = consume_contiguous_rows(
10306                &mut contiguous_row_selections,
10307                selection,
10308                &display_map,
10309                &mut selections,
10310            );
10311
10312            // Move the text spanned by the row range to be before the line preceding the row range
10313            if start_row.0 > 0 {
10314                let range_to_move = Point::new(
10315                    start_row.previous_row().0,
10316                    buffer.line_len(start_row.previous_row()),
10317                )
10318                    ..Point::new(
10319                        end_row.previous_row().0,
10320                        buffer.line_len(end_row.previous_row()),
10321                    );
10322                let insertion_point = display_map
10323                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10324                    .0;
10325
10326                // Don't move lines across excerpts
10327                if buffer
10328                    .excerpt_containing(insertion_point..range_to_move.end)
10329                    .is_some()
10330                {
10331                    let text = buffer
10332                        .text_for_range(range_to_move.clone())
10333                        .flat_map(|s| s.chars())
10334                        .skip(1)
10335                        .chain(['\n'])
10336                        .collect::<String>();
10337
10338                    edits.push((
10339                        buffer.anchor_after(range_to_move.start)
10340                            ..buffer.anchor_before(range_to_move.end),
10341                        String::new(),
10342                    ));
10343                    let insertion_anchor = buffer.anchor_after(insertion_point);
10344                    edits.push((insertion_anchor..insertion_anchor, text));
10345
10346                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10347
10348                    // Move selections up
10349                    new_selections.extend(contiguous_row_selections.drain(..).map(
10350                        |mut selection| {
10351                            selection.start.row -= row_delta;
10352                            selection.end.row -= row_delta;
10353                            selection
10354                        },
10355                    ));
10356
10357                    // Move folds up
10358                    unfold_ranges.push(range_to_move.clone());
10359                    for fold in display_map.folds_in_range(
10360                        buffer.anchor_before(range_to_move.start)
10361                            ..buffer.anchor_after(range_to_move.end),
10362                    ) {
10363                        let mut start = fold.range.start.to_point(&buffer);
10364                        let mut end = fold.range.end.to_point(&buffer);
10365                        start.row -= row_delta;
10366                        end.row -= row_delta;
10367                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10368                    }
10369                }
10370            }
10371
10372            // If we didn't move line(s), preserve the existing selections
10373            new_selections.append(&mut contiguous_row_selections);
10374        }
10375
10376        self.transact(window, cx, |this, window, cx| {
10377            this.unfold_ranges(&unfold_ranges, true, true, cx);
10378            this.buffer.update(cx, |buffer, cx| {
10379                for (range, text) in edits {
10380                    buffer.edit([(range, text)], None, cx);
10381                }
10382            });
10383            this.fold_creases(refold_creases, true, window, cx);
10384            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10385                s.select(new_selections);
10386            })
10387        });
10388    }
10389
10390    pub fn move_line_down(
10391        &mut self,
10392        _: &MoveLineDown,
10393        window: &mut Window,
10394        cx: &mut Context<Self>,
10395    ) {
10396        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10397
10398        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10399        let buffer = self.buffer.read(cx).snapshot(cx);
10400
10401        let mut edits = Vec::new();
10402        let mut unfold_ranges = Vec::new();
10403        let mut refold_creases = Vec::new();
10404
10405        let selections = self.selections.all::<Point>(cx);
10406        let mut selections = selections.iter().peekable();
10407        let mut contiguous_row_selections = Vec::new();
10408        let mut new_selections = Vec::new();
10409
10410        while let Some(selection) = selections.next() {
10411            // Find all the selections that span a contiguous row range
10412            let (start_row, end_row) = consume_contiguous_rows(
10413                &mut contiguous_row_selections,
10414                selection,
10415                &display_map,
10416                &mut selections,
10417            );
10418
10419            // Move the text spanned by the row range to be after the last line of the row range
10420            if end_row.0 <= buffer.max_point().row {
10421                let range_to_move =
10422                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10423                let insertion_point = display_map
10424                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10425                    .0;
10426
10427                // Don't move lines across excerpt boundaries
10428                if buffer
10429                    .excerpt_containing(range_to_move.start..insertion_point)
10430                    .is_some()
10431                {
10432                    let mut text = String::from("\n");
10433                    text.extend(buffer.text_for_range(range_to_move.clone()));
10434                    text.pop(); // Drop trailing newline
10435                    edits.push((
10436                        buffer.anchor_after(range_to_move.start)
10437                            ..buffer.anchor_before(range_to_move.end),
10438                        String::new(),
10439                    ));
10440                    let insertion_anchor = buffer.anchor_after(insertion_point);
10441                    edits.push((insertion_anchor..insertion_anchor, text));
10442
10443                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10444
10445                    // Move selections down
10446                    new_selections.extend(contiguous_row_selections.drain(..).map(
10447                        |mut selection| {
10448                            selection.start.row += row_delta;
10449                            selection.end.row += row_delta;
10450                            selection
10451                        },
10452                    ));
10453
10454                    // Move folds down
10455                    unfold_ranges.push(range_to_move.clone());
10456                    for fold in display_map.folds_in_range(
10457                        buffer.anchor_before(range_to_move.start)
10458                            ..buffer.anchor_after(range_to_move.end),
10459                    ) {
10460                        let mut start = fold.range.start.to_point(&buffer);
10461                        let mut end = fold.range.end.to_point(&buffer);
10462                        start.row += row_delta;
10463                        end.row += row_delta;
10464                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10465                    }
10466                }
10467            }
10468
10469            // If we didn't move line(s), preserve the existing selections
10470            new_selections.append(&mut contiguous_row_selections);
10471        }
10472
10473        self.transact(window, cx, |this, window, cx| {
10474            this.unfold_ranges(&unfold_ranges, true, true, cx);
10475            this.buffer.update(cx, |buffer, cx| {
10476                for (range, text) in edits {
10477                    buffer.edit([(range, text)], None, cx);
10478                }
10479            });
10480            this.fold_creases(refold_creases, true, window, cx);
10481            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10482                s.select(new_selections)
10483            });
10484        });
10485    }
10486
10487    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10488        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10489        let text_layout_details = &self.text_layout_details(window);
10490        self.transact(window, cx, |this, window, cx| {
10491            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10492                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10493                s.move_with(|display_map, selection| {
10494                    if !selection.is_empty() {
10495                        return;
10496                    }
10497
10498                    let mut head = selection.head();
10499                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10500                    if head.column() == display_map.line_len(head.row()) {
10501                        transpose_offset = display_map
10502                            .buffer_snapshot
10503                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10504                    }
10505
10506                    if transpose_offset == 0 {
10507                        return;
10508                    }
10509
10510                    *head.column_mut() += 1;
10511                    head = display_map.clip_point(head, Bias::Right);
10512                    let goal = SelectionGoal::HorizontalPosition(
10513                        display_map
10514                            .x_for_display_point(head, text_layout_details)
10515                            .into(),
10516                    );
10517                    selection.collapse_to(head, goal);
10518
10519                    let transpose_start = display_map
10520                        .buffer_snapshot
10521                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10522                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10523                        let transpose_end = display_map
10524                            .buffer_snapshot
10525                            .clip_offset(transpose_offset + 1, Bias::Right);
10526                        if let Some(ch) =
10527                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10528                        {
10529                            edits.push((transpose_start..transpose_offset, String::new()));
10530                            edits.push((transpose_end..transpose_end, ch.to_string()));
10531                        }
10532                    }
10533                });
10534                edits
10535            });
10536            this.buffer
10537                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10538            let selections = this.selections.all::<usize>(cx);
10539            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10540                s.select(selections);
10541            });
10542        });
10543    }
10544
10545    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10546        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10547        self.rewrap_impl(RewrapOptions::default(), cx)
10548    }
10549
10550    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10551        let buffer = self.buffer.read(cx).snapshot(cx);
10552        let selections = self.selections.all::<Point>(cx);
10553        let mut selections = selections.iter().peekable();
10554
10555        let mut edits = Vec::new();
10556        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10557
10558        while let Some(selection) = selections.next() {
10559            let mut start_row = selection.start.row;
10560            let mut end_row = selection.end.row;
10561
10562            // Skip selections that overlap with a range that has already been rewrapped.
10563            let selection_range = start_row..end_row;
10564            if rewrapped_row_ranges
10565                .iter()
10566                .any(|range| range.overlaps(&selection_range))
10567            {
10568                continue;
10569            }
10570
10571            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10572
10573            // Since not all lines in the selection may be at the same indent
10574            // level, choose the indent size that is the most common between all
10575            // of the lines.
10576            //
10577            // If there is a tie, we use the deepest indent.
10578            let (indent_size, indent_end) = {
10579                let mut indent_size_occurrences = HashMap::default();
10580                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10581
10582                for row in start_row..=end_row {
10583                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10584                    rows_by_indent_size.entry(indent).or_default().push(row);
10585                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10586                }
10587
10588                let indent_size = indent_size_occurrences
10589                    .into_iter()
10590                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10591                    .map(|(indent, _)| indent)
10592                    .unwrap_or_default();
10593                let row = rows_by_indent_size[&indent_size][0];
10594                let indent_end = Point::new(row, indent_size.len);
10595
10596                (indent_size, indent_end)
10597            };
10598
10599            let mut line_prefix = indent_size.chars().collect::<String>();
10600
10601            let mut inside_comment = false;
10602            if let Some(comment_prefix) =
10603                buffer
10604                    .language_scope_at(selection.head())
10605                    .and_then(|language| {
10606                        language
10607                            .line_comment_prefixes()
10608                            .iter()
10609                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10610                            .cloned()
10611                    })
10612            {
10613                line_prefix.push_str(&comment_prefix);
10614                inside_comment = true;
10615            }
10616
10617            let language_settings = buffer.language_settings_at(selection.head(), cx);
10618            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10619                RewrapBehavior::InComments => inside_comment,
10620                RewrapBehavior::InSelections => !selection.is_empty(),
10621                RewrapBehavior::Anywhere => true,
10622            };
10623
10624            let should_rewrap = options.override_language_settings
10625                || allow_rewrap_based_on_language
10626                || self.hard_wrap.is_some();
10627            if !should_rewrap {
10628                continue;
10629            }
10630
10631            if selection.is_empty() {
10632                'expand_upwards: while start_row > 0 {
10633                    let prev_row = start_row - 1;
10634                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10635                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10636                    {
10637                        start_row = prev_row;
10638                    } else {
10639                        break 'expand_upwards;
10640                    }
10641                }
10642
10643                'expand_downwards: while end_row < buffer.max_point().row {
10644                    let next_row = end_row + 1;
10645                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10646                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10647                    {
10648                        end_row = next_row;
10649                    } else {
10650                        break 'expand_downwards;
10651                    }
10652                }
10653            }
10654
10655            let start = Point::new(start_row, 0);
10656            let start_offset = start.to_offset(&buffer);
10657            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10658            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10659            let Some(lines_without_prefixes) = selection_text
10660                .lines()
10661                .map(|line| {
10662                    line.strip_prefix(&line_prefix)
10663                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10664                        .with_context(|| {
10665                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10666                        })
10667                })
10668                .collect::<Result<Vec<_>, _>>()
10669                .log_err()
10670            else {
10671                continue;
10672            };
10673
10674            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10675                buffer
10676                    .language_settings_at(Point::new(start_row, 0), cx)
10677                    .preferred_line_length as usize
10678            });
10679            let wrapped_text = wrap_with_prefix(
10680                line_prefix,
10681                lines_without_prefixes.join("\n"),
10682                wrap_column,
10683                tab_size,
10684                options.preserve_existing_whitespace,
10685            );
10686
10687            // TODO: should always use char-based diff while still supporting cursor behavior that
10688            // matches vim.
10689            let mut diff_options = DiffOptions::default();
10690            if options.override_language_settings {
10691                diff_options.max_word_diff_len = 0;
10692                diff_options.max_word_diff_line_count = 0;
10693            } else {
10694                diff_options.max_word_diff_len = usize::MAX;
10695                diff_options.max_word_diff_line_count = usize::MAX;
10696            }
10697
10698            for (old_range, new_text) in
10699                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10700            {
10701                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10702                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10703                edits.push((edit_start..edit_end, new_text));
10704            }
10705
10706            rewrapped_row_ranges.push(start_row..=end_row);
10707        }
10708
10709        self.buffer
10710            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10711    }
10712
10713    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10714        let mut text = String::new();
10715        let buffer = self.buffer.read(cx).snapshot(cx);
10716        let mut selections = self.selections.all::<Point>(cx);
10717        let mut clipboard_selections = Vec::with_capacity(selections.len());
10718        {
10719            let max_point = buffer.max_point();
10720            let mut is_first = true;
10721            for selection in &mut selections {
10722                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10723                if is_entire_line {
10724                    selection.start = Point::new(selection.start.row, 0);
10725                    if !selection.is_empty() && selection.end.column == 0 {
10726                        selection.end = cmp::min(max_point, selection.end);
10727                    } else {
10728                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10729                    }
10730                    selection.goal = SelectionGoal::None;
10731                }
10732                if is_first {
10733                    is_first = false;
10734                } else {
10735                    text += "\n";
10736                }
10737                let mut len = 0;
10738                for chunk in buffer.text_for_range(selection.start..selection.end) {
10739                    text.push_str(chunk);
10740                    len += chunk.len();
10741                }
10742                clipboard_selections.push(ClipboardSelection {
10743                    len,
10744                    is_entire_line,
10745                    first_line_indent: buffer
10746                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10747                        .len,
10748                });
10749            }
10750        }
10751
10752        self.transact(window, cx, |this, window, cx| {
10753            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10754                s.select(selections);
10755            });
10756            this.insert("", window, cx);
10757        });
10758        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10759    }
10760
10761    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10762        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10763        let item = self.cut_common(window, cx);
10764        cx.write_to_clipboard(item);
10765    }
10766
10767    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10768        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10769        self.change_selections(None, window, cx, |s| {
10770            s.move_with(|snapshot, sel| {
10771                if sel.is_empty() {
10772                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10773                }
10774            });
10775        });
10776        let item = self.cut_common(window, cx);
10777        cx.set_global(KillRing(item))
10778    }
10779
10780    pub fn kill_ring_yank(
10781        &mut self,
10782        _: &KillRingYank,
10783        window: &mut Window,
10784        cx: &mut Context<Self>,
10785    ) {
10786        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10787        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10788            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10789                (kill_ring.text().to_string(), kill_ring.metadata_json())
10790            } else {
10791                return;
10792            }
10793        } else {
10794            return;
10795        };
10796        self.do_paste(&text, metadata, false, window, cx);
10797    }
10798
10799    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10800        self.do_copy(true, cx);
10801    }
10802
10803    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10804        self.do_copy(false, cx);
10805    }
10806
10807    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10808        let selections = self.selections.all::<Point>(cx);
10809        let buffer = self.buffer.read(cx).read(cx);
10810        let mut text = String::new();
10811
10812        let mut clipboard_selections = Vec::with_capacity(selections.len());
10813        {
10814            let max_point = buffer.max_point();
10815            let mut is_first = true;
10816            for selection in &selections {
10817                let mut start = selection.start;
10818                let mut end = selection.end;
10819                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10820                if is_entire_line {
10821                    start = Point::new(start.row, 0);
10822                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10823                }
10824
10825                let mut trimmed_selections = Vec::new();
10826                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10827                    let row = MultiBufferRow(start.row);
10828                    let first_indent = buffer.indent_size_for_line(row);
10829                    if first_indent.len == 0 || start.column > first_indent.len {
10830                        trimmed_selections.push(start..end);
10831                    } else {
10832                        trimmed_selections.push(
10833                            Point::new(row.0, first_indent.len)
10834                                ..Point::new(row.0, buffer.line_len(row)),
10835                        );
10836                        for row in start.row + 1..=end.row {
10837                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10838                            if row == end.row {
10839                                line_len = end.column;
10840                            }
10841                            if line_len == 0 {
10842                                trimmed_selections
10843                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10844                                continue;
10845                            }
10846                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10847                            if row_indent_size.len >= first_indent.len {
10848                                trimmed_selections.push(
10849                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10850                                );
10851                            } else {
10852                                trimmed_selections.clear();
10853                                trimmed_selections.push(start..end);
10854                                break;
10855                            }
10856                        }
10857                    }
10858                } else {
10859                    trimmed_selections.push(start..end);
10860                }
10861
10862                for trimmed_range in trimmed_selections {
10863                    if is_first {
10864                        is_first = false;
10865                    } else {
10866                        text += "\n";
10867                    }
10868                    let mut len = 0;
10869                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10870                        text.push_str(chunk);
10871                        len += chunk.len();
10872                    }
10873                    clipboard_selections.push(ClipboardSelection {
10874                        len,
10875                        is_entire_line,
10876                        first_line_indent: buffer
10877                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10878                            .len,
10879                    });
10880                }
10881            }
10882        }
10883
10884        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10885            text,
10886            clipboard_selections,
10887        ));
10888    }
10889
10890    pub fn do_paste(
10891        &mut self,
10892        text: &String,
10893        clipboard_selections: Option<Vec<ClipboardSelection>>,
10894        handle_entire_lines: bool,
10895        window: &mut Window,
10896        cx: &mut Context<Self>,
10897    ) {
10898        if self.read_only(cx) {
10899            return;
10900        }
10901
10902        let clipboard_text = Cow::Borrowed(text);
10903
10904        self.transact(window, cx, |this, window, cx| {
10905            if let Some(mut clipboard_selections) = clipboard_selections {
10906                let old_selections = this.selections.all::<usize>(cx);
10907                let all_selections_were_entire_line =
10908                    clipboard_selections.iter().all(|s| s.is_entire_line);
10909                let first_selection_indent_column =
10910                    clipboard_selections.first().map(|s| s.first_line_indent);
10911                if clipboard_selections.len() != old_selections.len() {
10912                    clipboard_selections.drain(..);
10913                }
10914                let cursor_offset = this.selections.last::<usize>(cx).head();
10915                let mut auto_indent_on_paste = true;
10916
10917                this.buffer.update(cx, |buffer, cx| {
10918                    let snapshot = buffer.read(cx);
10919                    auto_indent_on_paste = snapshot
10920                        .language_settings_at(cursor_offset, cx)
10921                        .auto_indent_on_paste;
10922
10923                    let mut start_offset = 0;
10924                    let mut edits = Vec::new();
10925                    let mut original_indent_columns = Vec::new();
10926                    for (ix, selection) in old_selections.iter().enumerate() {
10927                        let to_insert;
10928                        let entire_line;
10929                        let original_indent_column;
10930                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10931                            let end_offset = start_offset + clipboard_selection.len;
10932                            to_insert = &clipboard_text[start_offset..end_offset];
10933                            entire_line = clipboard_selection.is_entire_line;
10934                            start_offset = end_offset + 1;
10935                            original_indent_column = Some(clipboard_selection.first_line_indent);
10936                        } else {
10937                            to_insert = clipboard_text.as_str();
10938                            entire_line = all_selections_were_entire_line;
10939                            original_indent_column = first_selection_indent_column
10940                        }
10941
10942                        // If the corresponding selection was empty when this slice of the
10943                        // clipboard text was written, then the entire line containing the
10944                        // selection was copied. If this selection is also currently empty,
10945                        // then paste the line before the current line of the buffer.
10946                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10947                            let column = selection.start.to_point(&snapshot).column as usize;
10948                            let line_start = selection.start - column;
10949                            line_start..line_start
10950                        } else {
10951                            selection.range()
10952                        };
10953
10954                        edits.push((range, to_insert));
10955                        original_indent_columns.push(original_indent_column);
10956                    }
10957                    drop(snapshot);
10958
10959                    buffer.edit(
10960                        edits,
10961                        if auto_indent_on_paste {
10962                            Some(AutoindentMode::Block {
10963                                original_indent_columns,
10964                            })
10965                        } else {
10966                            None
10967                        },
10968                        cx,
10969                    );
10970                });
10971
10972                let selections = this.selections.all::<usize>(cx);
10973                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10974                    s.select(selections)
10975                });
10976            } else {
10977                this.insert(&clipboard_text, window, cx);
10978            }
10979        });
10980    }
10981
10982    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10983        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10984        if let Some(item) = cx.read_from_clipboard() {
10985            let entries = item.entries();
10986
10987            match entries.first() {
10988                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10989                // of all the pasted entries.
10990                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10991                    .do_paste(
10992                        clipboard_string.text(),
10993                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10994                        true,
10995                        window,
10996                        cx,
10997                    ),
10998                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10999            }
11000        }
11001    }
11002
11003    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11004        if self.read_only(cx) {
11005            return;
11006        }
11007
11008        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11009
11010        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11011            if let Some((selections, _)) =
11012                self.selection_history.transaction(transaction_id).cloned()
11013            {
11014                self.change_selections(None, window, cx, |s| {
11015                    s.select_anchors(selections.to_vec());
11016                });
11017            } else {
11018                log::error!(
11019                    "No entry in selection_history found for undo. \
11020                     This may correspond to a bug where undo does not update the selection. \
11021                     If this is occurring, please add details to \
11022                     https://github.com/zed-industries/zed/issues/22692"
11023                );
11024            }
11025            self.request_autoscroll(Autoscroll::fit(), cx);
11026            self.unmark_text(window, cx);
11027            self.refresh_inline_completion(true, false, window, cx);
11028            cx.emit(EditorEvent::Edited { transaction_id });
11029            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11030        }
11031    }
11032
11033    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11034        if self.read_only(cx) {
11035            return;
11036        }
11037
11038        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11039
11040        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11041            if let Some((_, Some(selections))) =
11042                self.selection_history.transaction(transaction_id).cloned()
11043            {
11044                self.change_selections(None, window, cx, |s| {
11045                    s.select_anchors(selections.to_vec());
11046                });
11047            } else {
11048                log::error!(
11049                    "No entry in selection_history found for redo. \
11050                     This may correspond to a bug where undo does not update the selection. \
11051                     If this is occurring, please add details to \
11052                     https://github.com/zed-industries/zed/issues/22692"
11053                );
11054            }
11055            self.request_autoscroll(Autoscroll::fit(), cx);
11056            self.unmark_text(window, cx);
11057            self.refresh_inline_completion(true, false, window, cx);
11058            cx.emit(EditorEvent::Edited { transaction_id });
11059        }
11060    }
11061
11062    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11063        self.buffer
11064            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11065    }
11066
11067    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11068        self.buffer
11069            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11070    }
11071
11072    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11073        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11074        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11075            s.move_with(|map, selection| {
11076                let cursor = if selection.is_empty() {
11077                    movement::left(map, selection.start)
11078                } else {
11079                    selection.start
11080                };
11081                selection.collapse_to(cursor, SelectionGoal::None);
11082            });
11083        })
11084    }
11085
11086    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11087        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11088        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11089            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11090        })
11091    }
11092
11093    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11094        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11095        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11096            s.move_with(|map, selection| {
11097                let cursor = if selection.is_empty() {
11098                    movement::right(map, selection.end)
11099                } else {
11100                    selection.end
11101                };
11102                selection.collapse_to(cursor, SelectionGoal::None)
11103            });
11104        })
11105    }
11106
11107    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11108        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11109        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11110            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11111        })
11112    }
11113
11114    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11115        if self.take_rename(true, window, cx).is_some() {
11116            return;
11117        }
11118
11119        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11120            cx.propagate();
11121            return;
11122        }
11123
11124        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11125
11126        let text_layout_details = &self.text_layout_details(window);
11127        let selection_count = self.selections.count();
11128        let first_selection = self.selections.first_anchor();
11129
11130        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11131            s.move_with(|map, selection| {
11132                if !selection.is_empty() {
11133                    selection.goal = SelectionGoal::None;
11134                }
11135                let (cursor, goal) = movement::up(
11136                    map,
11137                    selection.start,
11138                    selection.goal,
11139                    false,
11140                    text_layout_details,
11141                );
11142                selection.collapse_to(cursor, goal);
11143            });
11144        });
11145
11146        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11147        {
11148            cx.propagate();
11149        }
11150    }
11151
11152    pub fn move_up_by_lines(
11153        &mut self,
11154        action: &MoveUpByLines,
11155        window: &mut Window,
11156        cx: &mut Context<Self>,
11157    ) {
11158        if self.take_rename(true, window, cx).is_some() {
11159            return;
11160        }
11161
11162        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11163            cx.propagate();
11164            return;
11165        }
11166
11167        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11168
11169        let text_layout_details = &self.text_layout_details(window);
11170
11171        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11172            s.move_with(|map, selection| {
11173                if !selection.is_empty() {
11174                    selection.goal = SelectionGoal::None;
11175                }
11176                let (cursor, goal) = movement::up_by_rows(
11177                    map,
11178                    selection.start,
11179                    action.lines,
11180                    selection.goal,
11181                    false,
11182                    text_layout_details,
11183                );
11184                selection.collapse_to(cursor, goal);
11185            });
11186        })
11187    }
11188
11189    pub fn move_down_by_lines(
11190        &mut self,
11191        action: &MoveDownByLines,
11192        window: &mut Window,
11193        cx: &mut Context<Self>,
11194    ) {
11195        if self.take_rename(true, window, cx).is_some() {
11196            return;
11197        }
11198
11199        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11200            cx.propagate();
11201            return;
11202        }
11203
11204        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11205
11206        let text_layout_details = &self.text_layout_details(window);
11207
11208        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11209            s.move_with(|map, selection| {
11210                if !selection.is_empty() {
11211                    selection.goal = SelectionGoal::None;
11212                }
11213                let (cursor, goal) = movement::down_by_rows(
11214                    map,
11215                    selection.start,
11216                    action.lines,
11217                    selection.goal,
11218                    false,
11219                    text_layout_details,
11220                );
11221                selection.collapse_to(cursor, goal);
11222            });
11223        })
11224    }
11225
11226    pub fn select_down_by_lines(
11227        &mut self,
11228        action: &SelectDownByLines,
11229        window: &mut Window,
11230        cx: &mut Context<Self>,
11231    ) {
11232        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11233        let text_layout_details = &self.text_layout_details(window);
11234        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11235            s.move_heads_with(|map, head, goal| {
11236                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11237            })
11238        })
11239    }
11240
11241    pub fn select_up_by_lines(
11242        &mut self,
11243        action: &SelectUpByLines,
11244        window: &mut Window,
11245        cx: &mut Context<Self>,
11246    ) {
11247        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11248        let text_layout_details = &self.text_layout_details(window);
11249        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11250            s.move_heads_with(|map, head, goal| {
11251                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11252            })
11253        })
11254    }
11255
11256    pub fn select_page_up(
11257        &mut self,
11258        _: &SelectPageUp,
11259        window: &mut Window,
11260        cx: &mut Context<Self>,
11261    ) {
11262        let Some(row_count) = self.visible_row_count() else {
11263            return;
11264        };
11265
11266        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11267
11268        let text_layout_details = &self.text_layout_details(window);
11269
11270        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11271            s.move_heads_with(|map, head, goal| {
11272                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11273            })
11274        })
11275    }
11276
11277    pub fn move_page_up(
11278        &mut self,
11279        action: &MovePageUp,
11280        window: &mut Window,
11281        cx: &mut Context<Self>,
11282    ) {
11283        if self.take_rename(true, window, cx).is_some() {
11284            return;
11285        }
11286
11287        if self
11288            .context_menu
11289            .borrow_mut()
11290            .as_mut()
11291            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11292            .unwrap_or(false)
11293        {
11294            return;
11295        }
11296
11297        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11298            cx.propagate();
11299            return;
11300        }
11301
11302        let Some(row_count) = self.visible_row_count() else {
11303            return;
11304        };
11305
11306        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11307
11308        let autoscroll = if action.center_cursor {
11309            Autoscroll::center()
11310        } else {
11311            Autoscroll::fit()
11312        };
11313
11314        let text_layout_details = &self.text_layout_details(window);
11315
11316        self.change_selections(Some(autoscroll), window, cx, |s| {
11317            s.move_with(|map, selection| {
11318                if !selection.is_empty() {
11319                    selection.goal = SelectionGoal::None;
11320                }
11321                let (cursor, goal) = movement::up_by_rows(
11322                    map,
11323                    selection.end,
11324                    row_count,
11325                    selection.goal,
11326                    false,
11327                    text_layout_details,
11328                );
11329                selection.collapse_to(cursor, goal);
11330            });
11331        });
11332    }
11333
11334    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11335        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11336        let text_layout_details = &self.text_layout_details(window);
11337        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11338            s.move_heads_with(|map, head, goal| {
11339                movement::up(map, head, goal, false, text_layout_details)
11340            })
11341        })
11342    }
11343
11344    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11345        self.take_rename(true, window, cx);
11346
11347        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11348            cx.propagate();
11349            return;
11350        }
11351
11352        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11353
11354        let text_layout_details = &self.text_layout_details(window);
11355        let selection_count = self.selections.count();
11356        let first_selection = self.selections.first_anchor();
11357
11358        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11359            s.move_with(|map, selection| {
11360                if !selection.is_empty() {
11361                    selection.goal = SelectionGoal::None;
11362                }
11363                let (cursor, goal) = movement::down(
11364                    map,
11365                    selection.end,
11366                    selection.goal,
11367                    false,
11368                    text_layout_details,
11369                );
11370                selection.collapse_to(cursor, goal);
11371            });
11372        });
11373
11374        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11375        {
11376            cx.propagate();
11377        }
11378    }
11379
11380    pub fn select_page_down(
11381        &mut self,
11382        _: &SelectPageDown,
11383        window: &mut Window,
11384        cx: &mut Context<Self>,
11385    ) {
11386        let Some(row_count) = self.visible_row_count() else {
11387            return;
11388        };
11389
11390        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11391
11392        let text_layout_details = &self.text_layout_details(window);
11393
11394        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11395            s.move_heads_with(|map, head, goal| {
11396                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11397            })
11398        })
11399    }
11400
11401    pub fn move_page_down(
11402        &mut self,
11403        action: &MovePageDown,
11404        window: &mut Window,
11405        cx: &mut Context<Self>,
11406    ) {
11407        if self.take_rename(true, window, cx).is_some() {
11408            return;
11409        }
11410
11411        if self
11412            .context_menu
11413            .borrow_mut()
11414            .as_mut()
11415            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11416            .unwrap_or(false)
11417        {
11418            return;
11419        }
11420
11421        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11422            cx.propagate();
11423            return;
11424        }
11425
11426        let Some(row_count) = self.visible_row_count() else {
11427            return;
11428        };
11429
11430        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11431
11432        let autoscroll = if action.center_cursor {
11433            Autoscroll::center()
11434        } else {
11435            Autoscroll::fit()
11436        };
11437
11438        let text_layout_details = &self.text_layout_details(window);
11439        self.change_selections(Some(autoscroll), window, cx, |s| {
11440            s.move_with(|map, selection| {
11441                if !selection.is_empty() {
11442                    selection.goal = SelectionGoal::None;
11443                }
11444                let (cursor, goal) = movement::down_by_rows(
11445                    map,
11446                    selection.end,
11447                    row_count,
11448                    selection.goal,
11449                    false,
11450                    text_layout_details,
11451                );
11452                selection.collapse_to(cursor, goal);
11453            });
11454        });
11455    }
11456
11457    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11458        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11459        let text_layout_details = &self.text_layout_details(window);
11460        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11461            s.move_heads_with(|map, head, goal| {
11462                movement::down(map, head, goal, false, text_layout_details)
11463            })
11464        });
11465    }
11466
11467    pub fn context_menu_first(
11468        &mut self,
11469        _: &ContextMenuFirst,
11470        _window: &mut Window,
11471        cx: &mut Context<Self>,
11472    ) {
11473        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11474            context_menu.select_first(self.completion_provider.as_deref(), cx);
11475        }
11476    }
11477
11478    pub fn context_menu_prev(
11479        &mut self,
11480        _: &ContextMenuPrevious,
11481        _window: &mut Window,
11482        cx: &mut Context<Self>,
11483    ) {
11484        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11485            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11486        }
11487    }
11488
11489    pub fn context_menu_next(
11490        &mut self,
11491        _: &ContextMenuNext,
11492        _window: &mut Window,
11493        cx: &mut Context<Self>,
11494    ) {
11495        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11496            context_menu.select_next(self.completion_provider.as_deref(), cx);
11497        }
11498    }
11499
11500    pub fn context_menu_last(
11501        &mut self,
11502        _: &ContextMenuLast,
11503        _window: &mut Window,
11504        cx: &mut Context<Self>,
11505    ) {
11506        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11507            context_menu.select_last(self.completion_provider.as_deref(), cx);
11508        }
11509    }
11510
11511    pub fn move_to_previous_word_start(
11512        &mut self,
11513        _: &MoveToPreviousWordStart,
11514        window: &mut Window,
11515        cx: &mut Context<Self>,
11516    ) {
11517        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11518        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11519            s.move_cursors_with(|map, head, _| {
11520                (
11521                    movement::previous_word_start(map, head),
11522                    SelectionGoal::None,
11523                )
11524            });
11525        })
11526    }
11527
11528    pub fn move_to_previous_subword_start(
11529        &mut self,
11530        _: &MoveToPreviousSubwordStart,
11531        window: &mut Window,
11532        cx: &mut Context<Self>,
11533    ) {
11534        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11535        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11536            s.move_cursors_with(|map, head, _| {
11537                (
11538                    movement::previous_subword_start(map, head),
11539                    SelectionGoal::None,
11540                )
11541            });
11542        })
11543    }
11544
11545    pub fn select_to_previous_word_start(
11546        &mut self,
11547        _: &SelectToPreviousWordStart,
11548        window: &mut Window,
11549        cx: &mut Context<Self>,
11550    ) {
11551        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11552        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11553            s.move_heads_with(|map, head, _| {
11554                (
11555                    movement::previous_word_start(map, head),
11556                    SelectionGoal::None,
11557                )
11558            });
11559        })
11560    }
11561
11562    pub fn select_to_previous_subword_start(
11563        &mut self,
11564        _: &SelectToPreviousSubwordStart,
11565        window: &mut Window,
11566        cx: &mut Context<Self>,
11567    ) {
11568        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11569        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11570            s.move_heads_with(|map, head, _| {
11571                (
11572                    movement::previous_subword_start(map, head),
11573                    SelectionGoal::None,
11574                )
11575            });
11576        })
11577    }
11578
11579    pub fn delete_to_previous_word_start(
11580        &mut self,
11581        action: &DeleteToPreviousWordStart,
11582        window: &mut Window,
11583        cx: &mut Context<Self>,
11584    ) {
11585        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11586        self.transact(window, cx, |this, window, cx| {
11587            this.select_autoclose_pair(window, cx);
11588            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11589                s.move_with(|map, selection| {
11590                    if selection.is_empty() {
11591                        let cursor = if action.ignore_newlines {
11592                            movement::previous_word_start(map, selection.head())
11593                        } else {
11594                            movement::previous_word_start_or_newline(map, selection.head())
11595                        };
11596                        selection.set_head(cursor, SelectionGoal::None);
11597                    }
11598                });
11599            });
11600            this.insert("", window, cx);
11601        });
11602    }
11603
11604    pub fn delete_to_previous_subword_start(
11605        &mut self,
11606        _: &DeleteToPreviousSubwordStart,
11607        window: &mut Window,
11608        cx: &mut Context<Self>,
11609    ) {
11610        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11611        self.transact(window, cx, |this, window, cx| {
11612            this.select_autoclose_pair(window, cx);
11613            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11614                s.move_with(|map, selection| {
11615                    if selection.is_empty() {
11616                        let cursor = movement::previous_subword_start(map, selection.head());
11617                        selection.set_head(cursor, SelectionGoal::None);
11618                    }
11619                });
11620            });
11621            this.insert("", window, cx);
11622        });
11623    }
11624
11625    pub fn move_to_next_word_end(
11626        &mut self,
11627        _: &MoveToNextWordEnd,
11628        window: &mut Window,
11629        cx: &mut Context<Self>,
11630    ) {
11631        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11632        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11633            s.move_cursors_with(|map, head, _| {
11634                (movement::next_word_end(map, head), SelectionGoal::None)
11635            });
11636        })
11637    }
11638
11639    pub fn move_to_next_subword_end(
11640        &mut self,
11641        _: &MoveToNextSubwordEnd,
11642        window: &mut Window,
11643        cx: &mut Context<Self>,
11644    ) {
11645        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11646        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11647            s.move_cursors_with(|map, head, _| {
11648                (movement::next_subword_end(map, head), SelectionGoal::None)
11649            });
11650        })
11651    }
11652
11653    pub fn select_to_next_word_end(
11654        &mut self,
11655        _: &SelectToNextWordEnd,
11656        window: &mut Window,
11657        cx: &mut Context<Self>,
11658    ) {
11659        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11660        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11661            s.move_heads_with(|map, head, _| {
11662                (movement::next_word_end(map, head), SelectionGoal::None)
11663            });
11664        })
11665    }
11666
11667    pub fn select_to_next_subword_end(
11668        &mut self,
11669        _: &SelectToNextSubwordEnd,
11670        window: &mut Window,
11671        cx: &mut Context<Self>,
11672    ) {
11673        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11674        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11675            s.move_heads_with(|map, head, _| {
11676                (movement::next_subword_end(map, head), SelectionGoal::None)
11677            });
11678        })
11679    }
11680
11681    pub fn delete_to_next_word_end(
11682        &mut self,
11683        action: &DeleteToNextWordEnd,
11684        window: &mut Window,
11685        cx: &mut Context<Self>,
11686    ) {
11687        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11688        self.transact(window, cx, |this, window, cx| {
11689            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11690                s.move_with(|map, selection| {
11691                    if selection.is_empty() {
11692                        let cursor = if action.ignore_newlines {
11693                            movement::next_word_end(map, selection.head())
11694                        } else {
11695                            movement::next_word_end_or_newline(map, selection.head())
11696                        };
11697                        selection.set_head(cursor, SelectionGoal::None);
11698                    }
11699                });
11700            });
11701            this.insert("", window, cx);
11702        });
11703    }
11704
11705    pub fn delete_to_next_subword_end(
11706        &mut self,
11707        _: &DeleteToNextSubwordEnd,
11708        window: &mut Window,
11709        cx: &mut Context<Self>,
11710    ) {
11711        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11712        self.transact(window, cx, |this, window, cx| {
11713            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11714                s.move_with(|map, selection| {
11715                    if selection.is_empty() {
11716                        let cursor = movement::next_subword_end(map, selection.head());
11717                        selection.set_head(cursor, SelectionGoal::None);
11718                    }
11719                });
11720            });
11721            this.insert("", window, cx);
11722        });
11723    }
11724
11725    pub fn move_to_beginning_of_line(
11726        &mut self,
11727        action: &MoveToBeginningOfLine,
11728        window: &mut Window,
11729        cx: &mut Context<Self>,
11730    ) {
11731        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11732        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11733            s.move_cursors_with(|map, head, _| {
11734                (
11735                    movement::indented_line_beginning(
11736                        map,
11737                        head,
11738                        action.stop_at_soft_wraps,
11739                        action.stop_at_indent,
11740                    ),
11741                    SelectionGoal::None,
11742                )
11743            });
11744        })
11745    }
11746
11747    pub fn select_to_beginning_of_line(
11748        &mut self,
11749        action: &SelectToBeginningOfLine,
11750        window: &mut Window,
11751        cx: &mut Context<Self>,
11752    ) {
11753        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11754        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11755            s.move_heads_with(|map, head, _| {
11756                (
11757                    movement::indented_line_beginning(
11758                        map,
11759                        head,
11760                        action.stop_at_soft_wraps,
11761                        action.stop_at_indent,
11762                    ),
11763                    SelectionGoal::None,
11764                )
11765            });
11766        });
11767    }
11768
11769    pub fn delete_to_beginning_of_line(
11770        &mut self,
11771        action: &DeleteToBeginningOfLine,
11772        window: &mut Window,
11773        cx: &mut Context<Self>,
11774    ) {
11775        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11776        self.transact(window, cx, |this, window, cx| {
11777            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11778                s.move_with(|_, selection| {
11779                    selection.reversed = true;
11780                });
11781            });
11782
11783            this.select_to_beginning_of_line(
11784                &SelectToBeginningOfLine {
11785                    stop_at_soft_wraps: false,
11786                    stop_at_indent: action.stop_at_indent,
11787                },
11788                window,
11789                cx,
11790            );
11791            this.backspace(&Backspace, window, cx);
11792        });
11793    }
11794
11795    pub fn move_to_end_of_line(
11796        &mut self,
11797        action: &MoveToEndOfLine,
11798        window: &mut Window,
11799        cx: &mut Context<Self>,
11800    ) {
11801        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11802        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11803            s.move_cursors_with(|map, head, _| {
11804                (
11805                    movement::line_end(map, head, action.stop_at_soft_wraps),
11806                    SelectionGoal::None,
11807                )
11808            });
11809        })
11810    }
11811
11812    pub fn select_to_end_of_line(
11813        &mut self,
11814        action: &SelectToEndOfLine,
11815        window: &mut Window,
11816        cx: &mut Context<Self>,
11817    ) {
11818        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11819        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11820            s.move_heads_with(|map, head, _| {
11821                (
11822                    movement::line_end(map, head, action.stop_at_soft_wraps),
11823                    SelectionGoal::None,
11824                )
11825            });
11826        })
11827    }
11828
11829    pub fn delete_to_end_of_line(
11830        &mut self,
11831        _: &DeleteToEndOfLine,
11832        window: &mut Window,
11833        cx: &mut Context<Self>,
11834    ) {
11835        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11836        self.transact(window, cx, |this, window, cx| {
11837            this.select_to_end_of_line(
11838                &SelectToEndOfLine {
11839                    stop_at_soft_wraps: false,
11840                },
11841                window,
11842                cx,
11843            );
11844            this.delete(&Delete, window, cx);
11845        });
11846    }
11847
11848    pub fn cut_to_end_of_line(
11849        &mut self,
11850        _: &CutToEndOfLine,
11851        window: &mut Window,
11852        cx: &mut Context<Self>,
11853    ) {
11854        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11855        self.transact(window, cx, |this, window, cx| {
11856            this.select_to_end_of_line(
11857                &SelectToEndOfLine {
11858                    stop_at_soft_wraps: false,
11859                },
11860                window,
11861                cx,
11862            );
11863            this.cut(&Cut, window, cx);
11864        });
11865    }
11866
11867    pub fn move_to_start_of_paragraph(
11868        &mut self,
11869        _: &MoveToStartOfParagraph,
11870        window: &mut Window,
11871        cx: &mut Context<Self>,
11872    ) {
11873        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11874            cx.propagate();
11875            return;
11876        }
11877        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11878        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11879            s.move_with(|map, selection| {
11880                selection.collapse_to(
11881                    movement::start_of_paragraph(map, selection.head(), 1),
11882                    SelectionGoal::None,
11883                )
11884            });
11885        })
11886    }
11887
11888    pub fn move_to_end_of_paragraph(
11889        &mut self,
11890        _: &MoveToEndOfParagraph,
11891        window: &mut Window,
11892        cx: &mut Context<Self>,
11893    ) {
11894        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11895            cx.propagate();
11896            return;
11897        }
11898        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11899        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11900            s.move_with(|map, selection| {
11901                selection.collapse_to(
11902                    movement::end_of_paragraph(map, selection.head(), 1),
11903                    SelectionGoal::None,
11904                )
11905            });
11906        })
11907    }
11908
11909    pub fn select_to_start_of_paragraph(
11910        &mut self,
11911        _: &SelectToStartOfParagraph,
11912        window: &mut Window,
11913        cx: &mut Context<Self>,
11914    ) {
11915        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11916            cx.propagate();
11917            return;
11918        }
11919        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11920        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11921            s.move_heads_with(|map, head, _| {
11922                (
11923                    movement::start_of_paragraph(map, head, 1),
11924                    SelectionGoal::None,
11925                )
11926            });
11927        })
11928    }
11929
11930    pub fn select_to_end_of_paragraph(
11931        &mut self,
11932        _: &SelectToEndOfParagraph,
11933        window: &mut Window,
11934        cx: &mut Context<Self>,
11935    ) {
11936        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11937            cx.propagate();
11938            return;
11939        }
11940        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11941        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11942            s.move_heads_with(|map, head, _| {
11943                (
11944                    movement::end_of_paragraph(map, head, 1),
11945                    SelectionGoal::None,
11946                )
11947            });
11948        })
11949    }
11950
11951    pub fn move_to_start_of_excerpt(
11952        &mut self,
11953        _: &MoveToStartOfExcerpt,
11954        window: &mut Window,
11955        cx: &mut Context<Self>,
11956    ) {
11957        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11958            cx.propagate();
11959            return;
11960        }
11961        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11962        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11963            s.move_with(|map, selection| {
11964                selection.collapse_to(
11965                    movement::start_of_excerpt(
11966                        map,
11967                        selection.head(),
11968                        workspace::searchable::Direction::Prev,
11969                    ),
11970                    SelectionGoal::None,
11971                )
11972            });
11973        })
11974    }
11975
11976    pub fn move_to_start_of_next_excerpt(
11977        &mut self,
11978        _: &MoveToStartOfNextExcerpt,
11979        window: &mut Window,
11980        cx: &mut Context<Self>,
11981    ) {
11982        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11983            cx.propagate();
11984            return;
11985        }
11986
11987        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11988            s.move_with(|map, selection| {
11989                selection.collapse_to(
11990                    movement::start_of_excerpt(
11991                        map,
11992                        selection.head(),
11993                        workspace::searchable::Direction::Next,
11994                    ),
11995                    SelectionGoal::None,
11996                )
11997            });
11998        })
11999    }
12000
12001    pub fn move_to_end_of_excerpt(
12002        &mut self,
12003        _: &MoveToEndOfExcerpt,
12004        window: &mut Window,
12005        cx: &mut Context<Self>,
12006    ) {
12007        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12008            cx.propagate();
12009            return;
12010        }
12011        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12012        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12013            s.move_with(|map, selection| {
12014                selection.collapse_to(
12015                    movement::end_of_excerpt(
12016                        map,
12017                        selection.head(),
12018                        workspace::searchable::Direction::Next,
12019                    ),
12020                    SelectionGoal::None,
12021                )
12022            });
12023        })
12024    }
12025
12026    pub fn move_to_end_of_previous_excerpt(
12027        &mut self,
12028        _: &MoveToEndOfPreviousExcerpt,
12029        window: &mut Window,
12030        cx: &mut Context<Self>,
12031    ) {
12032        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12033            cx.propagate();
12034            return;
12035        }
12036        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12037        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12038            s.move_with(|map, selection| {
12039                selection.collapse_to(
12040                    movement::end_of_excerpt(
12041                        map,
12042                        selection.head(),
12043                        workspace::searchable::Direction::Prev,
12044                    ),
12045                    SelectionGoal::None,
12046                )
12047            });
12048        })
12049    }
12050
12051    pub fn select_to_start_of_excerpt(
12052        &mut self,
12053        _: &SelectToStartOfExcerpt,
12054        window: &mut Window,
12055        cx: &mut Context<Self>,
12056    ) {
12057        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12058            cx.propagate();
12059            return;
12060        }
12061        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12062        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12063            s.move_heads_with(|map, head, _| {
12064                (
12065                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12066                    SelectionGoal::None,
12067                )
12068            });
12069        })
12070    }
12071
12072    pub fn select_to_start_of_next_excerpt(
12073        &mut self,
12074        _: &SelectToStartOfNextExcerpt,
12075        window: &mut Window,
12076        cx: &mut Context<Self>,
12077    ) {
12078        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12079            cx.propagate();
12080            return;
12081        }
12082        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12083        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12084            s.move_heads_with(|map, head, _| {
12085                (
12086                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12087                    SelectionGoal::None,
12088                )
12089            });
12090        })
12091    }
12092
12093    pub fn select_to_end_of_excerpt(
12094        &mut self,
12095        _: &SelectToEndOfExcerpt,
12096        window: &mut Window,
12097        cx: &mut Context<Self>,
12098    ) {
12099        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12100            cx.propagate();
12101            return;
12102        }
12103        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12104        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12105            s.move_heads_with(|map, head, _| {
12106                (
12107                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12108                    SelectionGoal::None,
12109                )
12110            });
12111        })
12112    }
12113
12114    pub fn select_to_end_of_previous_excerpt(
12115        &mut self,
12116        _: &SelectToEndOfPreviousExcerpt,
12117        window: &mut Window,
12118        cx: &mut Context<Self>,
12119    ) {
12120        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12121            cx.propagate();
12122            return;
12123        }
12124        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12125        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12126            s.move_heads_with(|map, head, _| {
12127                (
12128                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12129                    SelectionGoal::None,
12130                )
12131            });
12132        })
12133    }
12134
12135    pub fn move_to_beginning(
12136        &mut self,
12137        _: &MoveToBeginning,
12138        window: &mut Window,
12139        cx: &mut Context<Self>,
12140    ) {
12141        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12142            cx.propagate();
12143            return;
12144        }
12145        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12146        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12147            s.select_ranges(vec![0..0]);
12148        });
12149    }
12150
12151    pub fn select_to_beginning(
12152        &mut self,
12153        _: &SelectToBeginning,
12154        window: &mut Window,
12155        cx: &mut Context<Self>,
12156    ) {
12157        let mut selection = self.selections.last::<Point>(cx);
12158        selection.set_head(Point::zero(), SelectionGoal::None);
12159        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12160        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12161            s.select(vec![selection]);
12162        });
12163    }
12164
12165    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12166        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12167            cx.propagate();
12168            return;
12169        }
12170        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12171        let cursor = self.buffer.read(cx).read(cx).len();
12172        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12173            s.select_ranges(vec![cursor..cursor])
12174        });
12175    }
12176
12177    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12178        self.nav_history = nav_history;
12179    }
12180
12181    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12182        self.nav_history.as_ref()
12183    }
12184
12185    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12186        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12187    }
12188
12189    fn push_to_nav_history(
12190        &mut self,
12191        cursor_anchor: Anchor,
12192        new_position: Option<Point>,
12193        is_deactivate: bool,
12194        cx: &mut Context<Self>,
12195    ) {
12196        if let Some(nav_history) = self.nav_history.as_mut() {
12197            let buffer = self.buffer.read(cx).read(cx);
12198            let cursor_position = cursor_anchor.to_point(&buffer);
12199            let scroll_state = self.scroll_manager.anchor();
12200            let scroll_top_row = scroll_state.top_row(&buffer);
12201            drop(buffer);
12202
12203            if let Some(new_position) = new_position {
12204                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12205                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12206                    return;
12207                }
12208            }
12209
12210            nav_history.push(
12211                Some(NavigationData {
12212                    cursor_anchor,
12213                    cursor_position,
12214                    scroll_anchor: scroll_state,
12215                    scroll_top_row,
12216                }),
12217                cx,
12218            );
12219            cx.emit(EditorEvent::PushedToNavHistory {
12220                anchor: cursor_anchor,
12221                is_deactivate,
12222            })
12223        }
12224    }
12225
12226    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12227        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12228        let buffer = self.buffer.read(cx).snapshot(cx);
12229        let mut selection = self.selections.first::<usize>(cx);
12230        selection.set_head(buffer.len(), SelectionGoal::None);
12231        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12232            s.select(vec![selection]);
12233        });
12234    }
12235
12236    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12237        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12238        let end = self.buffer.read(cx).read(cx).len();
12239        self.change_selections(None, window, cx, |s| {
12240            s.select_ranges(vec![0..end]);
12241        });
12242    }
12243
12244    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12245        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12246        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12247        let mut selections = self.selections.all::<Point>(cx);
12248        let max_point = display_map.buffer_snapshot.max_point();
12249        for selection in &mut selections {
12250            let rows = selection.spanned_rows(true, &display_map);
12251            selection.start = Point::new(rows.start.0, 0);
12252            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12253            selection.reversed = false;
12254        }
12255        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12256            s.select(selections);
12257        });
12258    }
12259
12260    pub fn split_selection_into_lines(
12261        &mut self,
12262        _: &SplitSelectionIntoLines,
12263        window: &mut Window,
12264        cx: &mut Context<Self>,
12265    ) {
12266        let selections = self
12267            .selections
12268            .all::<Point>(cx)
12269            .into_iter()
12270            .map(|selection| selection.start..selection.end)
12271            .collect::<Vec<_>>();
12272        self.unfold_ranges(&selections, true, true, cx);
12273
12274        let mut new_selection_ranges = Vec::new();
12275        {
12276            let buffer = self.buffer.read(cx).read(cx);
12277            for selection in selections {
12278                for row in selection.start.row..selection.end.row {
12279                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12280                    new_selection_ranges.push(cursor..cursor);
12281                }
12282
12283                let is_multiline_selection = selection.start.row != selection.end.row;
12284                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12285                // so this action feels more ergonomic when paired with other selection operations
12286                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12287                if !should_skip_last {
12288                    new_selection_ranges.push(selection.end..selection.end);
12289                }
12290            }
12291        }
12292        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12293            s.select_ranges(new_selection_ranges);
12294        });
12295    }
12296
12297    pub fn add_selection_above(
12298        &mut self,
12299        _: &AddSelectionAbove,
12300        window: &mut Window,
12301        cx: &mut Context<Self>,
12302    ) {
12303        self.add_selection(true, window, cx);
12304    }
12305
12306    pub fn add_selection_below(
12307        &mut self,
12308        _: &AddSelectionBelow,
12309        window: &mut Window,
12310        cx: &mut Context<Self>,
12311    ) {
12312        self.add_selection(false, window, cx);
12313    }
12314
12315    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12316        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12317
12318        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12319        let mut selections = self.selections.all::<Point>(cx);
12320        let text_layout_details = self.text_layout_details(window);
12321        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12322            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12323            let range = oldest_selection.display_range(&display_map).sorted();
12324
12325            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12326            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12327            let positions = start_x.min(end_x)..start_x.max(end_x);
12328
12329            selections.clear();
12330            let mut stack = Vec::new();
12331            for row in range.start.row().0..=range.end.row().0 {
12332                if let Some(selection) = self.selections.build_columnar_selection(
12333                    &display_map,
12334                    DisplayRow(row),
12335                    &positions,
12336                    oldest_selection.reversed,
12337                    &text_layout_details,
12338                ) {
12339                    stack.push(selection.id);
12340                    selections.push(selection);
12341                }
12342            }
12343
12344            if above {
12345                stack.reverse();
12346            }
12347
12348            AddSelectionsState { above, stack }
12349        });
12350
12351        let last_added_selection = *state.stack.last().unwrap();
12352        let mut new_selections = Vec::new();
12353        if above == state.above {
12354            let end_row = if above {
12355                DisplayRow(0)
12356            } else {
12357                display_map.max_point().row()
12358            };
12359
12360            'outer: for selection in selections {
12361                if selection.id == last_added_selection {
12362                    let range = selection.display_range(&display_map).sorted();
12363                    debug_assert_eq!(range.start.row(), range.end.row());
12364                    let mut row = range.start.row();
12365                    let positions =
12366                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12367                            px(start)..px(end)
12368                        } else {
12369                            let start_x =
12370                                display_map.x_for_display_point(range.start, &text_layout_details);
12371                            let end_x =
12372                                display_map.x_for_display_point(range.end, &text_layout_details);
12373                            start_x.min(end_x)..start_x.max(end_x)
12374                        };
12375
12376                    while row != end_row {
12377                        if above {
12378                            row.0 -= 1;
12379                        } else {
12380                            row.0 += 1;
12381                        }
12382
12383                        if let Some(new_selection) = self.selections.build_columnar_selection(
12384                            &display_map,
12385                            row,
12386                            &positions,
12387                            selection.reversed,
12388                            &text_layout_details,
12389                        ) {
12390                            state.stack.push(new_selection.id);
12391                            if above {
12392                                new_selections.push(new_selection);
12393                                new_selections.push(selection);
12394                            } else {
12395                                new_selections.push(selection);
12396                                new_selections.push(new_selection);
12397                            }
12398
12399                            continue 'outer;
12400                        }
12401                    }
12402                }
12403
12404                new_selections.push(selection);
12405            }
12406        } else {
12407            new_selections = selections;
12408            new_selections.retain(|s| s.id != last_added_selection);
12409            state.stack.pop();
12410        }
12411
12412        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12413            s.select(new_selections);
12414        });
12415        if state.stack.len() > 1 {
12416            self.add_selections_state = Some(state);
12417        }
12418    }
12419
12420    fn select_match_ranges(
12421        &mut self,
12422        range: Range<usize>,
12423        reversed: bool,
12424        replace_newest: bool,
12425        auto_scroll: Option<Autoscroll>,
12426        window: &mut Window,
12427        cx: &mut Context<Editor>,
12428    ) {
12429        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12430        self.change_selections(auto_scroll, window, cx, |s| {
12431            if replace_newest {
12432                s.delete(s.newest_anchor().id);
12433            }
12434            if reversed {
12435                s.insert_range(range.end..range.start);
12436            } else {
12437                s.insert_range(range);
12438            }
12439        });
12440    }
12441
12442    pub fn select_next_match_internal(
12443        &mut self,
12444        display_map: &DisplaySnapshot,
12445        replace_newest: bool,
12446        autoscroll: Option<Autoscroll>,
12447        window: &mut Window,
12448        cx: &mut Context<Self>,
12449    ) -> Result<()> {
12450        let buffer = &display_map.buffer_snapshot;
12451        let mut selections = self.selections.all::<usize>(cx);
12452        if let Some(mut select_next_state) = self.select_next_state.take() {
12453            let query = &select_next_state.query;
12454            if !select_next_state.done {
12455                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12456                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12457                let mut next_selected_range = None;
12458
12459                let bytes_after_last_selection =
12460                    buffer.bytes_in_range(last_selection.end..buffer.len());
12461                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12462                let query_matches = query
12463                    .stream_find_iter(bytes_after_last_selection)
12464                    .map(|result| (last_selection.end, result))
12465                    .chain(
12466                        query
12467                            .stream_find_iter(bytes_before_first_selection)
12468                            .map(|result| (0, result)),
12469                    );
12470
12471                for (start_offset, query_match) in query_matches {
12472                    let query_match = query_match.unwrap(); // can only fail due to I/O
12473                    let offset_range =
12474                        start_offset + query_match.start()..start_offset + query_match.end();
12475                    let display_range = offset_range.start.to_display_point(display_map)
12476                        ..offset_range.end.to_display_point(display_map);
12477
12478                    if !select_next_state.wordwise
12479                        || (!movement::is_inside_word(display_map, display_range.start)
12480                            && !movement::is_inside_word(display_map, display_range.end))
12481                    {
12482                        // TODO: This is n^2, because we might check all the selections
12483                        if !selections
12484                            .iter()
12485                            .any(|selection| selection.range().overlaps(&offset_range))
12486                        {
12487                            next_selected_range = Some(offset_range);
12488                            break;
12489                        }
12490                    }
12491                }
12492
12493                if let Some(next_selected_range) = next_selected_range {
12494                    self.select_match_ranges(
12495                        next_selected_range,
12496                        last_selection.reversed,
12497                        replace_newest,
12498                        autoscroll,
12499                        window,
12500                        cx,
12501                    );
12502                } else {
12503                    select_next_state.done = true;
12504                }
12505            }
12506
12507            self.select_next_state = Some(select_next_state);
12508        } else {
12509            let mut only_carets = true;
12510            let mut same_text_selected = true;
12511            let mut selected_text = None;
12512
12513            let mut selections_iter = selections.iter().peekable();
12514            while let Some(selection) = selections_iter.next() {
12515                if selection.start != selection.end {
12516                    only_carets = false;
12517                }
12518
12519                if same_text_selected {
12520                    if selected_text.is_none() {
12521                        selected_text =
12522                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12523                    }
12524
12525                    if let Some(next_selection) = selections_iter.peek() {
12526                        if next_selection.range().len() == selection.range().len() {
12527                            let next_selected_text = buffer
12528                                .text_for_range(next_selection.range())
12529                                .collect::<String>();
12530                            if Some(next_selected_text) != selected_text {
12531                                same_text_selected = false;
12532                                selected_text = None;
12533                            }
12534                        } else {
12535                            same_text_selected = false;
12536                            selected_text = None;
12537                        }
12538                    }
12539                }
12540            }
12541
12542            if only_carets {
12543                for selection in &mut selections {
12544                    let word_range = movement::surrounding_word(
12545                        display_map,
12546                        selection.start.to_display_point(display_map),
12547                    );
12548                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12549                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12550                    selection.goal = SelectionGoal::None;
12551                    selection.reversed = false;
12552                    self.select_match_ranges(
12553                        selection.start..selection.end,
12554                        selection.reversed,
12555                        replace_newest,
12556                        autoscroll,
12557                        window,
12558                        cx,
12559                    );
12560                }
12561
12562                if selections.len() == 1 {
12563                    let selection = selections
12564                        .last()
12565                        .expect("ensured that there's only one selection");
12566                    let query = buffer
12567                        .text_for_range(selection.start..selection.end)
12568                        .collect::<String>();
12569                    let is_empty = query.is_empty();
12570                    let select_state = SelectNextState {
12571                        query: AhoCorasick::new(&[query])?,
12572                        wordwise: true,
12573                        done: is_empty,
12574                    };
12575                    self.select_next_state = Some(select_state);
12576                } else {
12577                    self.select_next_state = None;
12578                }
12579            } else if let Some(selected_text) = selected_text {
12580                self.select_next_state = Some(SelectNextState {
12581                    query: AhoCorasick::new(&[selected_text])?,
12582                    wordwise: false,
12583                    done: false,
12584                });
12585                self.select_next_match_internal(
12586                    display_map,
12587                    replace_newest,
12588                    autoscroll,
12589                    window,
12590                    cx,
12591                )?;
12592            }
12593        }
12594        Ok(())
12595    }
12596
12597    pub fn select_all_matches(
12598        &mut self,
12599        _action: &SelectAllMatches,
12600        window: &mut Window,
12601        cx: &mut Context<Self>,
12602    ) -> Result<()> {
12603        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12604
12605        self.push_to_selection_history();
12606        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12607
12608        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12609        let Some(select_next_state) = self.select_next_state.as_mut() else {
12610            return Ok(());
12611        };
12612        if select_next_state.done {
12613            return Ok(());
12614        }
12615
12616        let mut new_selections = Vec::new();
12617
12618        let reversed = self.selections.oldest::<usize>(cx).reversed;
12619        let buffer = &display_map.buffer_snapshot;
12620        let query_matches = select_next_state
12621            .query
12622            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12623
12624        for query_match in query_matches.into_iter() {
12625            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12626            let offset_range = if reversed {
12627                query_match.end()..query_match.start()
12628            } else {
12629                query_match.start()..query_match.end()
12630            };
12631            let display_range = offset_range.start.to_display_point(&display_map)
12632                ..offset_range.end.to_display_point(&display_map);
12633
12634            if !select_next_state.wordwise
12635                || (!movement::is_inside_word(&display_map, display_range.start)
12636                    && !movement::is_inside_word(&display_map, display_range.end))
12637            {
12638                new_selections.push(offset_range.start..offset_range.end);
12639            }
12640        }
12641
12642        select_next_state.done = true;
12643        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12644        self.change_selections(None, window, cx, |selections| {
12645            selections.select_ranges(new_selections)
12646        });
12647
12648        Ok(())
12649    }
12650
12651    pub fn select_next(
12652        &mut self,
12653        action: &SelectNext,
12654        window: &mut Window,
12655        cx: &mut Context<Self>,
12656    ) -> Result<()> {
12657        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12658        self.push_to_selection_history();
12659        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12660        self.select_next_match_internal(
12661            &display_map,
12662            action.replace_newest,
12663            Some(Autoscroll::newest()),
12664            window,
12665            cx,
12666        )?;
12667        Ok(())
12668    }
12669
12670    pub fn select_previous(
12671        &mut self,
12672        action: &SelectPrevious,
12673        window: &mut Window,
12674        cx: &mut Context<Self>,
12675    ) -> Result<()> {
12676        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12677        self.push_to_selection_history();
12678        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12679        let buffer = &display_map.buffer_snapshot;
12680        let mut selections = self.selections.all::<usize>(cx);
12681        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12682            let query = &select_prev_state.query;
12683            if !select_prev_state.done {
12684                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12685                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12686                let mut next_selected_range = None;
12687                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12688                let bytes_before_last_selection =
12689                    buffer.reversed_bytes_in_range(0..last_selection.start);
12690                let bytes_after_first_selection =
12691                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12692                let query_matches = query
12693                    .stream_find_iter(bytes_before_last_selection)
12694                    .map(|result| (last_selection.start, result))
12695                    .chain(
12696                        query
12697                            .stream_find_iter(bytes_after_first_selection)
12698                            .map(|result| (buffer.len(), result)),
12699                    );
12700                for (end_offset, query_match) in query_matches {
12701                    let query_match = query_match.unwrap(); // can only fail due to I/O
12702                    let offset_range =
12703                        end_offset - query_match.end()..end_offset - query_match.start();
12704                    let display_range = offset_range.start.to_display_point(&display_map)
12705                        ..offset_range.end.to_display_point(&display_map);
12706
12707                    if !select_prev_state.wordwise
12708                        || (!movement::is_inside_word(&display_map, display_range.start)
12709                            && !movement::is_inside_word(&display_map, display_range.end))
12710                    {
12711                        next_selected_range = Some(offset_range);
12712                        break;
12713                    }
12714                }
12715
12716                if let Some(next_selected_range) = next_selected_range {
12717                    self.select_match_ranges(
12718                        next_selected_range,
12719                        last_selection.reversed,
12720                        action.replace_newest,
12721                        Some(Autoscroll::newest()),
12722                        window,
12723                        cx,
12724                    );
12725                } else {
12726                    select_prev_state.done = true;
12727                }
12728            }
12729
12730            self.select_prev_state = Some(select_prev_state);
12731        } else {
12732            let mut only_carets = true;
12733            let mut same_text_selected = true;
12734            let mut selected_text = None;
12735
12736            let mut selections_iter = selections.iter().peekable();
12737            while let Some(selection) = selections_iter.next() {
12738                if selection.start != selection.end {
12739                    only_carets = false;
12740                }
12741
12742                if same_text_selected {
12743                    if selected_text.is_none() {
12744                        selected_text =
12745                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12746                    }
12747
12748                    if let Some(next_selection) = selections_iter.peek() {
12749                        if next_selection.range().len() == selection.range().len() {
12750                            let next_selected_text = buffer
12751                                .text_for_range(next_selection.range())
12752                                .collect::<String>();
12753                            if Some(next_selected_text) != selected_text {
12754                                same_text_selected = false;
12755                                selected_text = None;
12756                            }
12757                        } else {
12758                            same_text_selected = false;
12759                            selected_text = None;
12760                        }
12761                    }
12762                }
12763            }
12764
12765            if only_carets {
12766                for selection in &mut selections {
12767                    let word_range = movement::surrounding_word(
12768                        &display_map,
12769                        selection.start.to_display_point(&display_map),
12770                    );
12771                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12772                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12773                    selection.goal = SelectionGoal::None;
12774                    selection.reversed = false;
12775                    self.select_match_ranges(
12776                        selection.start..selection.end,
12777                        selection.reversed,
12778                        action.replace_newest,
12779                        Some(Autoscroll::newest()),
12780                        window,
12781                        cx,
12782                    );
12783                }
12784                if selections.len() == 1 {
12785                    let selection = selections
12786                        .last()
12787                        .expect("ensured that there's only one selection");
12788                    let query = buffer
12789                        .text_for_range(selection.start..selection.end)
12790                        .collect::<String>();
12791                    let is_empty = query.is_empty();
12792                    let select_state = SelectNextState {
12793                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12794                        wordwise: true,
12795                        done: is_empty,
12796                    };
12797                    self.select_prev_state = Some(select_state);
12798                } else {
12799                    self.select_prev_state = None;
12800                }
12801            } else if let Some(selected_text) = selected_text {
12802                self.select_prev_state = Some(SelectNextState {
12803                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12804                    wordwise: false,
12805                    done: false,
12806                });
12807                self.select_previous(action, window, cx)?;
12808            }
12809        }
12810        Ok(())
12811    }
12812
12813    pub fn find_next_match(
12814        &mut self,
12815        _: &FindNextMatch,
12816        window: &mut Window,
12817        cx: &mut Context<Self>,
12818    ) -> Result<()> {
12819        let selections = self.selections.disjoint_anchors();
12820        match selections.first() {
12821            Some(first) if selections.len() >= 2 => {
12822                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12823                    s.select_ranges([first.range()]);
12824                });
12825            }
12826            _ => self.select_next(
12827                &SelectNext {
12828                    replace_newest: true,
12829                },
12830                window,
12831                cx,
12832            )?,
12833        }
12834        Ok(())
12835    }
12836
12837    pub fn find_previous_match(
12838        &mut self,
12839        _: &FindPreviousMatch,
12840        window: &mut Window,
12841        cx: &mut Context<Self>,
12842    ) -> Result<()> {
12843        let selections = self.selections.disjoint_anchors();
12844        match selections.last() {
12845            Some(last) if selections.len() >= 2 => {
12846                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12847                    s.select_ranges([last.range()]);
12848                });
12849            }
12850            _ => self.select_previous(
12851                &SelectPrevious {
12852                    replace_newest: true,
12853                },
12854                window,
12855                cx,
12856            )?,
12857        }
12858        Ok(())
12859    }
12860
12861    pub fn toggle_comments(
12862        &mut self,
12863        action: &ToggleComments,
12864        window: &mut Window,
12865        cx: &mut Context<Self>,
12866    ) {
12867        if self.read_only(cx) {
12868            return;
12869        }
12870        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12871        let text_layout_details = &self.text_layout_details(window);
12872        self.transact(window, cx, |this, window, cx| {
12873            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12874            let mut edits = Vec::new();
12875            let mut selection_edit_ranges = Vec::new();
12876            let mut last_toggled_row = None;
12877            let snapshot = this.buffer.read(cx).read(cx);
12878            let empty_str: Arc<str> = Arc::default();
12879            let mut suffixes_inserted = Vec::new();
12880            let ignore_indent = action.ignore_indent;
12881
12882            fn comment_prefix_range(
12883                snapshot: &MultiBufferSnapshot,
12884                row: MultiBufferRow,
12885                comment_prefix: &str,
12886                comment_prefix_whitespace: &str,
12887                ignore_indent: bool,
12888            ) -> Range<Point> {
12889                let indent_size = if ignore_indent {
12890                    0
12891                } else {
12892                    snapshot.indent_size_for_line(row).len
12893                };
12894
12895                let start = Point::new(row.0, indent_size);
12896
12897                let mut line_bytes = snapshot
12898                    .bytes_in_range(start..snapshot.max_point())
12899                    .flatten()
12900                    .copied();
12901
12902                // If this line currently begins with the line comment prefix, then record
12903                // the range containing the prefix.
12904                if line_bytes
12905                    .by_ref()
12906                    .take(comment_prefix.len())
12907                    .eq(comment_prefix.bytes())
12908                {
12909                    // Include any whitespace that matches the comment prefix.
12910                    let matching_whitespace_len = line_bytes
12911                        .zip(comment_prefix_whitespace.bytes())
12912                        .take_while(|(a, b)| a == b)
12913                        .count() as u32;
12914                    let end = Point::new(
12915                        start.row,
12916                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12917                    );
12918                    start..end
12919                } else {
12920                    start..start
12921                }
12922            }
12923
12924            fn comment_suffix_range(
12925                snapshot: &MultiBufferSnapshot,
12926                row: MultiBufferRow,
12927                comment_suffix: &str,
12928                comment_suffix_has_leading_space: bool,
12929            ) -> Range<Point> {
12930                let end = Point::new(row.0, snapshot.line_len(row));
12931                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12932
12933                let mut line_end_bytes = snapshot
12934                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12935                    .flatten()
12936                    .copied();
12937
12938                let leading_space_len = if suffix_start_column > 0
12939                    && line_end_bytes.next() == Some(b' ')
12940                    && comment_suffix_has_leading_space
12941                {
12942                    1
12943                } else {
12944                    0
12945                };
12946
12947                // If this line currently begins with the line comment prefix, then record
12948                // the range containing the prefix.
12949                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12950                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12951                    start..end
12952                } else {
12953                    end..end
12954                }
12955            }
12956
12957            // TODO: Handle selections that cross excerpts
12958            for selection in &mut selections {
12959                let start_column = snapshot
12960                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12961                    .len;
12962                let language = if let Some(language) =
12963                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12964                {
12965                    language
12966                } else {
12967                    continue;
12968                };
12969
12970                selection_edit_ranges.clear();
12971
12972                // If multiple selections contain a given row, avoid processing that
12973                // row more than once.
12974                let mut start_row = MultiBufferRow(selection.start.row);
12975                if last_toggled_row == Some(start_row) {
12976                    start_row = start_row.next_row();
12977                }
12978                let end_row =
12979                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12980                        MultiBufferRow(selection.end.row - 1)
12981                    } else {
12982                        MultiBufferRow(selection.end.row)
12983                    };
12984                last_toggled_row = Some(end_row);
12985
12986                if start_row > end_row {
12987                    continue;
12988                }
12989
12990                // If the language has line comments, toggle those.
12991                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12992
12993                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12994                if ignore_indent {
12995                    full_comment_prefixes = full_comment_prefixes
12996                        .into_iter()
12997                        .map(|s| Arc::from(s.trim_end()))
12998                        .collect();
12999                }
13000
13001                if !full_comment_prefixes.is_empty() {
13002                    let first_prefix = full_comment_prefixes
13003                        .first()
13004                        .expect("prefixes is non-empty");
13005                    let prefix_trimmed_lengths = full_comment_prefixes
13006                        .iter()
13007                        .map(|p| p.trim_end_matches(' ').len())
13008                        .collect::<SmallVec<[usize; 4]>>();
13009
13010                    let mut all_selection_lines_are_comments = true;
13011
13012                    for row in start_row.0..=end_row.0 {
13013                        let row = MultiBufferRow(row);
13014                        if start_row < end_row && snapshot.is_line_blank(row) {
13015                            continue;
13016                        }
13017
13018                        let prefix_range = full_comment_prefixes
13019                            .iter()
13020                            .zip(prefix_trimmed_lengths.iter().copied())
13021                            .map(|(prefix, trimmed_prefix_len)| {
13022                                comment_prefix_range(
13023                                    snapshot.deref(),
13024                                    row,
13025                                    &prefix[..trimmed_prefix_len],
13026                                    &prefix[trimmed_prefix_len..],
13027                                    ignore_indent,
13028                                )
13029                            })
13030                            .max_by_key(|range| range.end.column - range.start.column)
13031                            .expect("prefixes is non-empty");
13032
13033                        if prefix_range.is_empty() {
13034                            all_selection_lines_are_comments = false;
13035                        }
13036
13037                        selection_edit_ranges.push(prefix_range);
13038                    }
13039
13040                    if all_selection_lines_are_comments {
13041                        edits.extend(
13042                            selection_edit_ranges
13043                                .iter()
13044                                .cloned()
13045                                .map(|range| (range, empty_str.clone())),
13046                        );
13047                    } else {
13048                        let min_column = selection_edit_ranges
13049                            .iter()
13050                            .map(|range| range.start.column)
13051                            .min()
13052                            .unwrap_or(0);
13053                        edits.extend(selection_edit_ranges.iter().map(|range| {
13054                            let position = Point::new(range.start.row, min_column);
13055                            (position..position, first_prefix.clone())
13056                        }));
13057                    }
13058                } else if let Some((full_comment_prefix, comment_suffix)) =
13059                    language.block_comment_delimiters()
13060                {
13061                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13062                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13063                    let prefix_range = comment_prefix_range(
13064                        snapshot.deref(),
13065                        start_row,
13066                        comment_prefix,
13067                        comment_prefix_whitespace,
13068                        ignore_indent,
13069                    );
13070                    let suffix_range = comment_suffix_range(
13071                        snapshot.deref(),
13072                        end_row,
13073                        comment_suffix.trim_start_matches(' '),
13074                        comment_suffix.starts_with(' '),
13075                    );
13076
13077                    if prefix_range.is_empty() || suffix_range.is_empty() {
13078                        edits.push((
13079                            prefix_range.start..prefix_range.start,
13080                            full_comment_prefix.clone(),
13081                        ));
13082                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13083                        suffixes_inserted.push((end_row, comment_suffix.len()));
13084                    } else {
13085                        edits.push((prefix_range, empty_str.clone()));
13086                        edits.push((suffix_range, empty_str.clone()));
13087                    }
13088                } else {
13089                    continue;
13090                }
13091            }
13092
13093            drop(snapshot);
13094            this.buffer.update(cx, |buffer, cx| {
13095                buffer.edit(edits, None, cx);
13096            });
13097
13098            // Adjust selections so that they end before any comment suffixes that
13099            // were inserted.
13100            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13101            let mut selections = this.selections.all::<Point>(cx);
13102            let snapshot = this.buffer.read(cx).read(cx);
13103            for selection in &mut selections {
13104                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13105                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13106                        Ordering::Less => {
13107                            suffixes_inserted.next();
13108                            continue;
13109                        }
13110                        Ordering::Greater => break,
13111                        Ordering::Equal => {
13112                            if selection.end.column == snapshot.line_len(row) {
13113                                if selection.is_empty() {
13114                                    selection.start.column -= suffix_len as u32;
13115                                }
13116                                selection.end.column -= suffix_len as u32;
13117                            }
13118                            break;
13119                        }
13120                    }
13121                }
13122            }
13123
13124            drop(snapshot);
13125            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13126                s.select(selections)
13127            });
13128
13129            let selections = this.selections.all::<Point>(cx);
13130            let selections_on_single_row = selections.windows(2).all(|selections| {
13131                selections[0].start.row == selections[1].start.row
13132                    && selections[0].end.row == selections[1].end.row
13133                    && selections[0].start.row == selections[0].end.row
13134            });
13135            let selections_selecting = selections
13136                .iter()
13137                .any(|selection| selection.start != selection.end);
13138            let advance_downwards = action.advance_downwards
13139                && selections_on_single_row
13140                && !selections_selecting
13141                && !matches!(this.mode, EditorMode::SingleLine { .. });
13142
13143            if advance_downwards {
13144                let snapshot = this.buffer.read(cx).snapshot(cx);
13145
13146                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13147                    s.move_cursors_with(|display_snapshot, display_point, _| {
13148                        let mut point = display_point.to_point(display_snapshot);
13149                        point.row += 1;
13150                        point = snapshot.clip_point(point, Bias::Left);
13151                        let display_point = point.to_display_point(display_snapshot);
13152                        let goal = SelectionGoal::HorizontalPosition(
13153                            display_snapshot
13154                                .x_for_display_point(display_point, text_layout_details)
13155                                .into(),
13156                        );
13157                        (display_point, goal)
13158                    })
13159                });
13160            }
13161        });
13162    }
13163
13164    pub fn select_enclosing_symbol(
13165        &mut self,
13166        _: &SelectEnclosingSymbol,
13167        window: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13171
13172        let buffer = self.buffer.read(cx).snapshot(cx);
13173        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13174
13175        fn update_selection(
13176            selection: &Selection<usize>,
13177            buffer_snap: &MultiBufferSnapshot,
13178        ) -> Option<Selection<usize>> {
13179            let cursor = selection.head();
13180            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13181            for symbol in symbols.iter().rev() {
13182                let start = symbol.range.start.to_offset(buffer_snap);
13183                let end = symbol.range.end.to_offset(buffer_snap);
13184                let new_range = start..end;
13185                if start < selection.start || end > selection.end {
13186                    return Some(Selection {
13187                        id: selection.id,
13188                        start: new_range.start,
13189                        end: new_range.end,
13190                        goal: SelectionGoal::None,
13191                        reversed: selection.reversed,
13192                    });
13193                }
13194            }
13195            None
13196        }
13197
13198        let mut selected_larger_symbol = false;
13199        let new_selections = old_selections
13200            .iter()
13201            .map(|selection| match update_selection(selection, &buffer) {
13202                Some(new_selection) => {
13203                    if new_selection.range() != selection.range() {
13204                        selected_larger_symbol = true;
13205                    }
13206                    new_selection
13207                }
13208                None => selection.clone(),
13209            })
13210            .collect::<Vec<_>>();
13211
13212        if selected_larger_symbol {
13213            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13214                s.select(new_selections);
13215            });
13216        }
13217    }
13218
13219    pub fn select_larger_syntax_node(
13220        &mut self,
13221        _: &SelectLargerSyntaxNode,
13222        window: &mut Window,
13223        cx: &mut Context<Self>,
13224    ) {
13225        let Some(visible_row_count) = self.visible_row_count() else {
13226            return;
13227        };
13228        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13229        if old_selections.is_empty() {
13230            return;
13231        }
13232
13233        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13234
13235        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13236        let buffer = self.buffer.read(cx).snapshot(cx);
13237
13238        let mut selected_larger_node = false;
13239        let mut new_selections = old_selections
13240            .iter()
13241            .map(|selection| {
13242                let old_range = selection.start..selection.end;
13243
13244                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13245                    // manually select word at selection
13246                    if ["string_content", "inline"].contains(&node.kind()) {
13247                        let word_range = {
13248                            let display_point = buffer
13249                                .offset_to_point(old_range.start)
13250                                .to_display_point(&display_map);
13251                            let Range { start, end } =
13252                                movement::surrounding_word(&display_map, display_point);
13253                            start.to_point(&display_map).to_offset(&buffer)
13254                                ..end.to_point(&display_map).to_offset(&buffer)
13255                        };
13256                        // ignore if word is already selected
13257                        if !word_range.is_empty() && old_range != word_range {
13258                            let last_word_range = {
13259                                let display_point = buffer
13260                                    .offset_to_point(old_range.end)
13261                                    .to_display_point(&display_map);
13262                                let Range { start, end } =
13263                                    movement::surrounding_word(&display_map, display_point);
13264                                start.to_point(&display_map).to_offset(&buffer)
13265                                    ..end.to_point(&display_map).to_offset(&buffer)
13266                            };
13267                            // only select word if start and end point belongs to same word
13268                            if word_range == last_word_range {
13269                                selected_larger_node = true;
13270                                return Selection {
13271                                    id: selection.id,
13272                                    start: word_range.start,
13273                                    end: word_range.end,
13274                                    goal: SelectionGoal::None,
13275                                    reversed: selection.reversed,
13276                                };
13277                            }
13278                        }
13279                    }
13280                }
13281
13282                let mut new_range = old_range.clone();
13283                while let Some((_node, containing_range)) =
13284                    buffer.syntax_ancestor(new_range.clone())
13285                {
13286                    new_range = match containing_range {
13287                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13288                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13289                    };
13290                    if !display_map.intersects_fold(new_range.start)
13291                        && !display_map.intersects_fold(new_range.end)
13292                    {
13293                        break;
13294                    }
13295                }
13296
13297                selected_larger_node |= new_range != old_range;
13298                Selection {
13299                    id: selection.id,
13300                    start: new_range.start,
13301                    end: new_range.end,
13302                    goal: SelectionGoal::None,
13303                    reversed: selection.reversed,
13304                }
13305            })
13306            .collect::<Vec<_>>();
13307
13308        if !selected_larger_node {
13309            return; // don't put this call in the history
13310        }
13311
13312        // scroll based on transformation done to the last selection created by the user
13313        let (last_old, last_new) = old_selections
13314            .last()
13315            .zip(new_selections.last().cloned())
13316            .expect("old_selections isn't empty");
13317
13318        // revert selection
13319        let is_selection_reversed = {
13320            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13321            new_selections.last_mut().expect("checked above").reversed =
13322                should_newest_selection_be_reversed;
13323            should_newest_selection_be_reversed
13324        };
13325
13326        if selected_larger_node {
13327            self.select_syntax_node_history.disable_clearing = true;
13328            self.change_selections(None, window, cx, |s| {
13329                s.select(new_selections.clone());
13330            });
13331            self.select_syntax_node_history.disable_clearing = false;
13332        }
13333
13334        let start_row = last_new.start.to_display_point(&display_map).row().0;
13335        let end_row = last_new.end.to_display_point(&display_map).row().0;
13336        let selection_height = end_row - start_row + 1;
13337        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13338
13339        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13340        let scroll_behavior = if fits_on_the_screen {
13341            self.request_autoscroll(Autoscroll::fit(), cx);
13342            SelectSyntaxNodeScrollBehavior::FitSelection
13343        } else if is_selection_reversed {
13344            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13345            SelectSyntaxNodeScrollBehavior::CursorTop
13346        } else {
13347            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13348            SelectSyntaxNodeScrollBehavior::CursorBottom
13349        };
13350
13351        self.select_syntax_node_history.push((
13352            old_selections,
13353            scroll_behavior,
13354            is_selection_reversed,
13355        ));
13356    }
13357
13358    pub fn select_smaller_syntax_node(
13359        &mut self,
13360        _: &SelectSmallerSyntaxNode,
13361        window: &mut Window,
13362        cx: &mut Context<Self>,
13363    ) {
13364        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13365
13366        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13367            self.select_syntax_node_history.pop()
13368        {
13369            if let Some(selection) = selections.last_mut() {
13370                selection.reversed = is_selection_reversed;
13371            }
13372
13373            self.select_syntax_node_history.disable_clearing = true;
13374            self.change_selections(None, window, cx, |s| {
13375                s.select(selections.to_vec());
13376            });
13377            self.select_syntax_node_history.disable_clearing = false;
13378
13379            match scroll_behavior {
13380                SelectSyntaxNodeScrollBehavior::CursorTop => {
13381                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13382                }
13383                SelectSyntaxNodeScrollBehavior::FitSelection => {
13384                    self.request_autoscroll(Autoscroll::fit(), cx);
13385                }
13386                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13387                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13388                }
13389            }
13390        }
13391    }
13392
13393    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13394        if !EditorSettings::get_global(cx).gutter.runnables {
13395            self.clear_tasks();
13396            return Task::ready(());
13397        }
13398        let project = self.project.as_ref().map(Entity::downgrade);
13399        let task_sources = self.lsp_task_sources(cx);
13400        cx.spawn_in(window, async move |editor, cx| {
13401            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13402            let Some(project) = project.and_then(|p| p.upgrade()) else {
13403                return;
13404            };
13405            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13406                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13407            }) else {
13408                return;
13409            };
13410
13411            let hide_runnables = project
13412                .update(cx, |project, cx| {
13413                    // Do not display any test indicators in non-dev server remote projects.
13414                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13415                })
13416                .unwrap_or(true);
13417            if hide_runnables {
13418                return;
13419            }
13420            let new_rows =
13421                cx.background_spawn({
13422                    let snapshot = display_snapshot.clone();
13423                    async move {
13424                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13425                    }
13426                })
13427                    .await;
13428            let Ok(lsp_tasks) =
13429                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13430            else {
13431                return;
13432            };
13433            let lsp_tasks = lsp_tasks.await;
13434
13435            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13436                lsp_tasks
13437                    .into_iter()
13438                    .flat_map(|(kind, tasks)| {
13439                        tasks.into_iter().filter_map(move |(location, task)| {
13440                            Some((kind.clone(), location?, task))
13441                        })
13442                    })
13443                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13444                        let buffer = location.target.buffer;
13445                        let buffer_snapshot = buffer.read(cx).snapshot();
13446                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13447                            |(excerpt_id, snapshot, _)| {
13448                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13449                                    display_snapshot
13450                                        .buffer_snapshot
13451                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13452                                } else {
13453                                    None
13454                                }
13455                            },
13456                        );
13457                        if let Some(offset) = offset {
13458                            let task_buffer_range =
13459                                location.target.range.to_point(&buffer_snapshot);
13460                            let context_buffer_range =
13461                                task_buffer_range.to_offset(&buffer_snapshot);
13462                            let context_range = BufferOffset(context_buffer_range.start)
13463                                ..BufferOffset(context_buffer_range.end);
13464
13465                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13466                                .or_insert_with(|| RunnableTasks {
13467                                    templates: Vec::new(),
13468                                    offset,
13469                                    column: task_buffer_range.start.column,
13470                                    extra_variables: HashMap::default(),
13471                                    context_range,
13472                                })
13473                                .templates
13474                                .push((kind, task.original_task().clone()));
13475                        }
13476
13477                        acc
13478                    })
13479            }) else {
13480                return;
13481            };
13482
13483            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13484            editor
13485                .update(cx, |editor, _| {
13486                    editor.clear_tasks();
13487                    for (key, mut value) in rows {
13488                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13489                            value.templates.extend(lsp_tasks.templates);
13490                        }
13491
13492                        editor.insert_tasks(key, value);
13493                    }
13494                    for (key, value) in lsp_tasks_by_rows {
13495                        editor.insert_tasks(key, value);
13496                    }
13497                })
13498                .ok();
13499        })
13500    }
13501    fn fetch_runnable_ranges(
13502        snapshot: &DisplaySnapshot,
13503        range: Range<Anchor>,
13504    ) -> Vec<language::RunnableRange> {
13505        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13506    }
13507
13508    fn runnable_rows(
13509        project: Entity<Project>,
13510        snapshot: DisplaySnapshot,
13511        runnable_ranges: Vec<RunnableRange>,
13512        mut cx: AsyncWindowContext,
13513    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13514        runnable_ranges
13515            .into_iter()
13516            .filter_map(|mut runnable| {
13517                let tasks = cx
13518                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13519                    .ok()?;
13520                if tasks.is_empty() {
13521                    return None;
13522                }
13523
13524                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13525
13526                let row = snapshot
13527                    .buffer_snapshot
13528                    .buffer_line_for_row(MultiBufferRow(point.row))?
13529                    .1
13530                    .start
13531                    .row;
13532
13533                let context_range =
13534                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13535                Some((
13536                    (runnable.buffer_id, row),
13537                    RunnableTasks {
13538                        templates: tasks,
13539                        offset: snapshot
13540                            .buffer_snapshot
13541                            .anchor_before(runnable.run_range.start),
13542                        context_range,
13543                        column: point.column,
13544                        extra_variables: runnable.extra_captures,
13545                    },
13546                ))
13547            })
13548            .collect()
13549    }
13550
13551    fn templates_with_tags(
13552        project: &Entity<Project>,
13553        runnable: &mut Runnable,
13554        cx: &mut App,
13555    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13556        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13557            let (worktree_id, file) = project
13558                .buffer_for_id(runnable.buffer, cx)
13559                .and_then(|buffer| buffer.read(cx).file())
13560                .map(|file| (file.worktree_id(cx), file.clone()))
13561                .unzip();
13562
13563            (
13564                project.task_store().read(cx).task_inventory().cloned(),
13565                worktree_id,
13566                file,
13567            )
13568        });
13569
13570        let mut templates_with_tags = mem::take(&mut runnable.tags)
13571            .into_iter()
13572            .flat_map(|RunnableTag(tag)| {
13573                inventory
13574                    .as_ref()
13575                    .into_iter()
13576                    .flat_map(|inventory| {
13577                        inventory.read(cx).list_tasks(
13578                            file.clone(),
13579                            Some(runnable.language.clone()),
13580                            worktree_id,
13581                            cx,
13582                        )
13583                    })
13584                    .filter(move |(_, template)| {
13585                        template.tags.iter().any(|source_tag| source_tag == &tag)
13586                    })
13587            })
13588            .sorted_by_key(|(kind, _)| kind.to_owned())
13589            .collect::<Vec<_>>();
13590        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13591            // Strongest source wins; if we have worktree tag binding, prefer that to
13592            // global and language bindings;
13593            // if we have a global binding, prefer that to language binding.
13594            let first_mismatch = templates_with_tags
13595                .iter()
13596                .position(|(tag_source, _)| tag_source != leading_tag_source);
13597            if let Some(index) = first_mismatch {
13598                templates_with_tags.truncate(index);
13599            }
13600        }
13601
13602        templates_with_tags
13603    }
13604
13605    pub fn move_to_enclosing_bracket(
13606        &mut self,
13607        _: &MoveToEnclosingBracket,
13608        window: &mut Window,
13609        cx: &mut Context<Self>,
13610    ) {
13611        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13612        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13613            s.move_offsets_with(|snapshot, selection| {
13614                let Some(enclosing_bracket_ranges) =
13615                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13616                else {
13617                    return;
13618                };
13619
13620                let mut best_length = usize::MAX;
13621                let mut best_inside = false;
13622                let mut best_in_bracket_range = false;
13623                let mut best_destination = None;
13624                for (open, close) in enclosing_bracket_ranges {
13625                    let close = close.to_inclusive();
13626                    let length = close.end() - open.start;
13627                    let inside = selection.start >= open.end && selection.end <= *close.start();
13628                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13629                        || close.contains(&selection.head());
13630
13631                    // If best is next to a bracket and current isn't, skip
13632                    if !in_bracket_range && best_in_bracket_range {
13633                        continue;
13634                    }
13635
13636                    // Prefer smaller lengths unless best is inside and current isn't
13637                    if length > best_length && (best_inside || !inside) {
13638                        continue;
13639                    }
13640
13641                    best_length = length;
13642                    best_inside = inside;
13643                    best_in_bracket_range = in_bracket_range;
13644                    best_destination = Some(
13645                        if close.contains(&selection.start) && close.contains(&selection.end) {
13646                            if inside { open.end } else { open.start }
13647                        } else if inside {
13648                            *close.start()
13649                        } else {
13650                            *close.end()
13651                        },
13652                    );
13653                }
13654
13655                if let Some(destination) = best_destination {
13656                    selection.collapse_to(destination, SelectionGoal::None);
13657                }
13658            })
13659        });
13660    }
13661
13662    pub fn undo_selection(
13663        &mut self,
13664        _: &UndoSelection,
13665        window: &mut Window,
13666        cx: &mut Context<Self>,
13667    ) {
13668        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13669        self.end_selection(window, cx);
13670        self.selection_history.mode = SelectionHistoryMode::Undoing;
13671        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13672            self.change_selections(None, window, cx, |s| {
13673                s.select_anchors(entry.selections.to_vec())
13674            });
13675            self.select_next_state = entry.select_next_state;
13676            self.select_prev_state = entry.select_prev_state;
13677            self.add_selections_state = entry.add_selections_state;
13678            self.request_autoscroll(Autoscroll::newest(), cx);
13679        }
13680        self.selection_history.mode = SelectionHistoryMode::Normal;
13681    }
13682
13683    pub fn redo_selection(
13684        &mut self,
13685        _: &RedoSelection,
13686        window: &mut Window,
13687        cx: &mut Context<Self>,
13688    ) {
13689        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13690        self.end_selection(window, cx);
13691        self.selection_history.mode = SelectionHistoryMode::Redoing;
13692        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13693            self.change_selections(None, window, cx, |s| {
13694                s.select_anchors(entry.selections.to_vec())
13695            });
13696            self.select_next_state = entry.select_next_state;
13697            self.select_prev_state = entry.select_prev_state;
13698            self.add_selections_state = entry.add_selections_state;
13699            self.request_autoscroll(Autoscroll::newest(), cx);
13700        }
13701        self.selection_history.mode = SelectionHistoryMode::Normal;
13702    }
13703
13704    pub fn expand_excerpts(
13705        &mut self,
13706        action: &ExpandExcerpts,
13707        _: &mut Window,
13708        cx: &mut Context<Self>,
13709    ) {
13710        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13711    }
13712
13713    pub fn expand_excerpts_down(
13714        &mut self,
13715        action: &ExpandExcerptsDown,
13716        _: &mut Window,
13717        cx: &mut Context<Self>,
13718    ) {
13719        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13720    }
13721
13722    pub fn expand_excerpts_up(
13723        &mut self,
13724        action: &ExpandExcerptsUp,
13725        _: &mut Window,
13726        cx: &mut Context<Self>,
13727    ) {
13728        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13729    }
13730
13731    pub fn expand_excerpts_for_direction(
13732        &mut self,
13733        lines: u32,
13734        direction: ExpandExcerptDirection,
13735
13736        cx: &mut Context<Self>,
13737    ) {
13738        let selections = self.selections.disjoint_anchors();
13739
13740        let lines = if lines == 0 {
13741            EditorSettings::get_global(cx).expand_excerpt_lines
13742        } else {
13743            lines
13744        };
13745
13746        self.buffer.update(cx, |buffer, cx| {
13747            let snapshot = buffer.snapshot(cx);
13748            let mut excerpt_ids = selections
13749                .iter()
13750                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13751                .collect::<Vec<_>>();
13752            excerpt_ids.sort();
13753            excerpt_ids.dedup();
13754            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13755        })
13756    }
13757
13758    pub fn expand_excerpt(
13759        &mut self,
13760        excerpt: ExcerptId,
13761        direction: ExpandExcerptDirection,
13762        window: &mut Window,
13763        cx: &mut Context<Self>,
13764    ) {
13765        let current_scroll_position = self.scroll_position(cx);
13766        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13767        let mut should_scroll_up = false;
13768
13769        if direction == ExpandExcerptDirection::Down {
13770            let multi_buffer = self.buffer.read(cx);
13771            let snapshot = multi_buffer.snapshot(cx);
13772            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13773                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13774                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13775                        let buffer_snapshot = buffer.read(cx).snapshot();
13776                        let excerpt_end_row =
13777                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13778                        let last_row = buffer_snapshot.max_point().row;
13779                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13780                        should_scroll_up = lines_below >= lines_to_expand;
13781                    }
13782                }
13783            }
13784        }
13785
13786        self.buffer.update(cx, |buffer, cx| {
13787            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13788        });
13789
13790        if should_scroll_up {
13791            let new_scroll_position =
13792                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13793            self.set_scroll_position(new_scroll_position, window, cx);
13794        }
13795    }
13796
13797    pub fn go_to_singleton_buffer_point(
13798        &mut self,
13799        point: Point,
13800        window: &mut Window,
13801        cx: &mut Context<Self>,
13802    ) {
13803        self.go_to_singleton_buffer_range(point..point, window, cx);
13804    }
13805
13806    pub fn go_to_singleton_buffer_range(
13807        &mut self,
13808        range: Range<Point>,
13809        window: &mut Window,
13810        cx: &mut Context<Self>,
13811    ) {
13812        let multibuffer = self.buffer().read(cx);
13813        let Some(buffer) = multibuffer.as_singleton() else {
13814            return;
13815        };
13816        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13817            return;
13818        };
13819        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13820            return;
13821        };
13822        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13823            s.select_anchor_ranges([start..end])
13824        });
13825    }
13826
13827    pub fn go_to_diagnostic(
13828        &mut self,
13829        _: &GoToDiagnostic,
13830        window: &mut Window,
13831        cx: &mut Context<Self>,
13832    ) {
13833        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13834        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13835    }
13836
13837    pub fn go_to_prev_diagnostic(
13838        &mut self,
13839        _: &GoToPreviousDiagnostic,
13840        window: &mut Window,
13841        cx: &mut Context<Self>,
13842    ) {
13843        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13844        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13845    }
13846
13847    pub fn go_to_diagnostic_impl(
13848        &mut self,
13849        direction: Direction,
13850        window: &mut Window,
13851        cx: &mut Context<Self>,
13852    ) {
13853        let buffer = self.buffer.read(cx).snapshot(cx);
13854        let selection = self.selections.newest::<usize>(cx);
13855
13856        let mut active_group_id = None;
13857        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13858            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13859                active_group_id = Some(active_group.group_id);
13860            }
13861        }
13862
13863        fn filtered(
13864            snapshot: EditorSnapshot,
13865            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13866        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13867            diagnostics
13868                .filter(|entry| entry.range.start != entry.range.end)
13869                .filter(|entry| !entry.diagnostic.is_unnecessary)
13870                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13871        }
13872
13873        let snapshot = self.snapshot(window, cx);
13874        let before = filtered(
13875            snapshot.clone(),
13876            buffer
13877                .diagnostics_in_range(0..selection.start)
13878                .filter(|entry| entry.range.start <= selection.start),
13879        );
13880        let after = filtered(
13881            snapshot,
13882            buffer
13883                .diagnostics_in_range(selection.start..buffer.len())
13884                .filter(|entry| entry.range.start >= selection.start),
13885        );
13886
13887        let mut found: Option<DiagnosticEntry<usize>> = None;
13888        if direction == Direction::Prev {
13889            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13890            {
13891                for diagnostic in prev_diagnostics.into_iter().rev() {
13892                    if diagnostic.range.start != selection.start
13893                        || active_group_id
13894                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13895                    {
13896                        found = Some(diagnostic);
13897                        break 'outer;
13898                    }
13899                }
13900            }
13901        } else {
13902            for diagnostic in after.chain(before) {
13903                if diagnostic.range.start != selection.start
13904                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13905                {
13906                    found = Some(diagnostic);
13907                    break;
13908                }
13909            }
13910        }
13911        let Some(next_diagnostic) = found else {
13912            return;
13913        };
13914
13915        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13916            return;
13917        };
13918        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13919            s.select_ranges(vec![
13920                next_diagnostic.range.start..next_diagnostic.range.start,
13921            ])
13922        });
13923        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13924        self.refresh_inline_completion(false, true, window, cx);
13925    }
13926
13927    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13928        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13929        let snapshot = self.snapshot(window, cx);
13930        let selection = self.selections.newest::<Point>(cx);
13931        self.go_to_hunk_before_or_after_position(
13932            &snapshot,
13933            selection.head(),
13934            Direction::Next,
13935            window,
13936            cx,
13937        );
13938    }
13939
13940    pub fn go_to_hunk_before_or_after_position(
13941        &mut self,
13942        snapshot: &EditorSnapshot,
13943        position: Point,
13944        direction: Direction,
13945        window: &mut Window,
13946        cx: &mut Context<Editor>,
13947    ) {
13948        let row = if direction == Direction::Next {
13949            self.hunk_after_position(snapshot, position)
13950                .map(|hunk| hunk.row_range.start)
13951        } else {
13952            self.hunk_before_position(snapshot, position)
13953        };
13954
13955        if let Some(row) = row {
13956            let destination = Point::new(row.0, 0);
13957            let autoscroll = Autoscroll::center();
13958
13959            self.unfold_ranges(&[destination..destination], false, false, cx);
13960            self.change_selections(Some(autoscroll), window, cx, |s| {
13961                s.select_ranges([destination..destination]);
13962            });
13963        }
13964    }
13965
13966    fn hunk_after_position(
13967        &mut self,
13968        snapshot: &EditorSnapshot,
13969        position: Point,
13970    ) -> Option<MultiBufferDiffHunk> {
13971        snapshot
13972            .buffer_snapshot
13973            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13974            .find(|hunk| hunk.row_range.start.0 > position.row)
13975            .or_else(|| {
13976                snapshot
13977                    .buffer_snapshot
13978                    .diff_hunks_in_range(Point::zero()..position)
13979                    .find(|hunk| hunk.row_range.end.0 < position.row)
13980            })
13981    }
13982
13983    fn go_to_prev_hunk(
13984        &mut self,
13985        _: &GoToPreviousHunk,
13986        window: &mut Window,
13987        cx: &mut Context<Self>,
13988    ) {
13989        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13990        let snapshot = self.snapshot(window, cx);
13991        let selection = self.selections.newest::<Point>(cx);
13992        self.go_to_hunk_before_or_after_position(
13993            &snapshot,
13994            selection.head(),
13995            Direction::Prev,
13996            window,
13997            cx,
13998        );
13999    }
14000
14001    fn hunk_before_position(
14002        &mut self,
14003        snapshot: &EditorSnapshot,
14004        position: Point,
14005    ) -> Option<MultiBufferRow> {
14006        snapshot
14007            .buffer_snapshot
14008            .diff_hunk_before(position)
14009            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14010    }
14011
14012    fn go_to_next_change(
14013        &mut self,
14014        _: &GoToNextChange,
14015        window: &mut Window,
14016        cx: &mut Context<Self>,
14017    ) {
14018        if let Some(selections) = self
14019            .change_list
14020            .next_change(1, Direction::Next)
14021            .map(|s| s.to_vec())
14022        {
14023            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14024                let map = s.display_map();
14025                s.select_display_ranges(selections.iter().map(|a| {
14026                    let point = a.to_display_point(&map);
14027                    point..point
14028                }))
14029            })
14030        }
14031    }
14032
14033    fn go_to_previous_change(
14034        &mut self,
14035        _: &GoToPreviousChange,
14036        window: &mut Window,
14037        cx: &mut Context<Self>,
14038    ) {
14039        if let Some(selections) = self
14040            .change_list
14041            .next_change(1, Direction::Prev)
14042            .map(|s| s.to_vec())
14043        {
14044            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14045                let map = s.display_map();
14046                s.select_display_ranges(selections.iter().map(|a| {
14047                    let point = a.to_display_point(&map);
14048                    point..point
14049                }))
14050            })
14051        }
14052    }
14053
14054    fn go_to_line<T: 'static>(
14055        &mut self,
14056        position: Anchor,
14057        highlight_color: Option<Hsla>,
14058        window: &mut Window,
14059        cx: &mut Context<Self>,
14060    ) {
14061        let snapshot = self.snapshot(window, cx).display_snapshot;
14062        let position = position.to_point(&snapshot.buffer_snapshot);
14063        let start = snapshot
14064            .buffer_snapshot
14065            .clip_point(Point::new(position.row, 0), Bias::Left);
14066        let end = start + Point::new(1, 0);
14067        let start = snapshot.buffer_snapshot.anchor_before(start);
14068        let end = snapshot.buffer_snapshot.anchor_before(end);
14069
14070        self.highlight_rows::<T>(
14071            start..end,
14072            highlight_color
14073                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14074            Default::default(),
14075            cx,
14076        );
14077
14078        if self.buffer.read(cx).is_singleton() {
14079            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14080        }
14081    }
14082
14083    pub fn go_to_definition(
14084        &mut self,
14085        _: &GoToDefinition,
14086        window: &mut Window,
14087        cx: &mut Context<Self>,
14088    ) -> Task<Result<Navigated>> {
14089        let definition =
14090            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14091        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14092        cx.spawn_in(window, async move |editor, cx| {
14093            if definition.await? == Navigated::Yes {
14094                return Ok(Navigated::Yes);
14095            }
14096            match fallback_strategy {
14097                GoToDefinitionFallback::None => Ok(Navigated::No),
14098                GoToDefinitionFallback::FindAllReferences => {
14099                    match editor.update_in(cx, |editor, window, cx| {
14100                        editor.find_all_references(&FindAllReferences, window, cx)
14101                    })? {
14102                        Some(references) => references.await,
14103                        None => Ok(Navigated::No),
14104                    }
14105                }
14106            }
14107        })
14108    }
14109
14110    pub fn go_to_declaration(
14111        &mut self,
14112        _: &GoToDeclaration,
14113        window: &mut Window,
14114        cx: &mut Context<Self>,
14115    ) -> Task<Result<Navigated>> {
14116        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14117    }
14118
14119    pub fn go_to_declaration_split(
14120        &mut self,
14121        _: &GoToDeclaration,
14122        window: &mut Window,
14123        cx: &mut Context<Self>,
14124    ) -> Task<Result<Navigated>> {
14125        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14126    }
14127
14128    pub fn go_to_implementation(
14129        &mut self,
14130        _: &GoToImplementation,
14131        window: &mut Window,
14132        cx: &mut Context<Self>,
14133    ) -> Task<Result<Navigated>> {
14134        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14135    }
14136
14137    pub fn go_to_implementation_split(
14138        &mut self,
14139        _: &GoToImplementationSplit,
14140        window: &mut Window,
14141        cx: &mut Context<Self>,
14142    ) -> Task<Result<Navigated>> {
14143        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14144    }
14145
14146    pub fn go_to_type_definition(
14147        &mut self,
14148        _: &GoToTypeDefinition,
14149        window: &mut Window,
14150        cx: &mut Context<Self>,
14151    ) -> Task<Result<Navigated>> {
14152        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14153    }
14154
14155    pub fn go_to_definition_split(
14156        &mut self,
14157        _: &GoToDefinitionSplit,
14158        window: &mut Window,
14159        cx: &mut Context<Self>,
14160    ) -> Task<Result<Navigated>> {
14161        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14162    }
14163
14164    pub fn go_to_type_definition_split(
14165        &mut self,
14166        _: &GoToTypeDefinitionSplit,
14167        window: &mut Window,
14168        cx: &mut Context<Self>,
14169    ) -> Task<Result<Navigated>> {
14170        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14171    }
14172
14173    fn go_to_definition_of_kind(
14174        &mut self,
14175        kind: GotoDefinitionKind,
14176        split: bool,
14177        window: &mut Window,
14178        cx: &mut Context<Self>,
14179    ) -> Task<Result<Navigated>> {
14180        let Some(provider) = self.semantics_provider.clone() else {
14181            return Task::ready(Ok(Navigated::No));
14182        };
14183        let head = self.selections.newest::<usize>(cx).head();
14184        let buffer = self.buffer.read(cx);
14185        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14186            text_anchor
14187        } else {
14188            return Task::ready(Ok(Navigated::No));
14189        };
14190
14191        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14192            return Task::ready(Ok(Navigated::No));
14193        };
14194
14195        cx.spawn_in(window, async move |editor, cx| {
14196            let definitions = definitions.await?;
14197            let navigated = editor
14198                .update_in(cx, |editor, window, cx| {
14199                    editor.navigate_to_hover_links(
14200                        Some(kind),
14201                        definitions
14202                            .into_iter()
14203                            .filter(|location| {
14204                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14205                            })
14206                            .map(HoverLink::Text)
14207                            .collect::<Vec<_>>(),
14208                        split,
14209                        window,
14210                        cx,
14211                    )
14212                })?
14213                .await?;
14214            anyhow::Ok(navigated)
14215        })
14216    }
14217
14218    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14219        let selection = self.selections.newest_anchor();
14220        let head = selection.head();
14221        let tail = selection.tail();
14222
14223        let Some((buffer, start_position)) =
14224            self.buffer.read(cx).text_anchor_for_position(head, cx)
14225        else {
14226            return;
14227        };
14228
14229        let end_position = if head != tail {
14230            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14231                return;
14232            };
14233            Some(pos)
14234        } else {
14235            None
14236        };
14237
14238        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14239            let url = if let Some(end_pos) = end_position {
14240                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14241            } else {
14242                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14243            };
14244
14245            if let Some(url) = url {
14246                editor.update(cx, |_, cx| {
14247                    cx.open_url(&url);
14248                })
14249            } else {
14250                Ok(())
14251            }
14252        });
14253
14254        url_finder.detach();
14255    }
14256
14257    pub fn open_selected_filename(
14258        &mut self,
14259        _: &OpenSelectedFilename,
14260        window: &mut Window,
14261        cx: &mut Context<Self>,
14262    ) {
14263        let Some(workspace) = self.workspace() else {
14264            return;
14265        };
14266
14267        let position = self.selections.newest_anchor().head();
14268
14269        let Some((buffer, buffer_position)) =
14270            self.buffer.read(cx).text_anchor_for_position(position, cx)
14271        else {
14272            return;
14273        };
14274
14275        let project = self.project.clone();
14276
14277        cx.spawn_in(window, async move |_, cx| {
14278            let result = find_file(&buffer, project, buffer_position, cx).await;
14279
14280            if let Some((_, path)) = result {
14281                workspace
14282                    .update_in(cx, |workspace, window, cx| {
14283                        workspace.open_resolved_path(path, window, cx)
14284                    })?
14285                    .await?;
14286            }
14287            anyhow::Ok(())
14288        })
14289        .detach();
14290    }
14291
14292    pub(crate) fn navigate_to_hover_links(
14293        &mut self,
14294        kind: Option<GotoDefinitionKind>,
14295        mut definitions: Vec<HoverLink>,
14296        split: bool,
14297        window: &mut Window,
14298        cx: &mut Context<Editor>,
14299    ) -> Task<Result<Navigated>> {
14300        // If there is one definition, just open it directly
14301        if definitions.len() == 1 {
14302            let definition = definitions.pop().unwrap();
14303
14304            enum TargetTaskResult {
14305                Location(Option<Location>),
14306                AlreadyNavigated,
14307            }
14308
14309            let target_task = match definition {
14310                HoverLink::Text(link) => {
14311                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14312                }
14313                HoverLink::InlayHint(lsp_location, server_id) => {
14314                    let computation =
14315                        self.compute_target_location(lsp_location, server_id, window, cx);
14316                    cx.background_spawn(async move {
14317                        let location = computation.await?;
14318                        Ok(TargetTaskResult::Location(location))
14319                    })
14320                }
14321                HoverLink::Url(url) => {
14322                    cx.open_url(&url);
14323                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14324                }
14325                HoverLink::File(path) => {
14326                    if let Some(workspace) = self.workspace() {
14327                        cx.spawn_in(window, async move |_, cx| {
14328                            workspace
14329                                .update_in(cx, |workspace, window, cx| {
14330                                    workspace.open_resolved_path(path, window, cx)
14331                                })?
14332                                .await
14333                                .map(|_| TargetTaskResult::AlreadyNavigated)
14334                        })
14335                    } else {
14336                        Task::ready(Ok(TargetTaskResult::Location(None)))
14337                    }
14338                }
14339            };
14340            cx.spawn_in(window, async move |editor, cx| {
14341                let target = match target_task.await.context("target resolution task")? {
14342                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14343                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14344                    TargetTaskResult::Location(Some(target)) => target,
14345                };
14346
14347                editor.update_in(cx, |editor, window, cx| {
14348                    let Some(workspace) = editor.workspace() else {
14349                        return Navigated::No;
14350                    };
14351                    let pane = workspace.read(cx).active_pane().clone();
14352
14353                    let range = target.range.to_point(target.buffer.read(cx));
14354                    let range = editor.range_for_match(&range);
14355                    let range = collapse_multiline_range(range);
14356
14357                    if !split
14358                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14359                    {
14360                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14361                    } else {
14362                        window.defer(cx, move |window, cx| {
14363                            let target_editor: Entity<Self> =
14364                                workspace.update(cx, |workspace, cx| {
14365                                    let pane = if split {
14366                                        workspace.adjacent_pane(window, cx)
14367                                    } else {
14368                                        workspace.active_pane().clone()
14369                                    };
14370
14371                                    workspace.open_project_item(
14372                                        pane,
14373                                        target.buffer.clone(),
14374                                        true,
14375                                        true,
14376                                        window,
14377                                        cx,
14378                                    )
14379                                });
14380                            target_editor.update(cx, |target_editor, cx| {
14381                                // When selecting a definition in a different buffer, disable the nav history
14382                                // to avoid creating a history entry at the previous cursor location.
14383                                pane.update(cx, |pane, _| pane.disable_history());
14384                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14385                                pane.update(cx, |pane, _| pane.enable_history());
14386                            });
14387                        });
14388                    }
14389                    Navigated::Yes
14390                })
14391            })
14392        } else if !definitions.is_empty() {
14393            cx.spawn_in(window, async move |editor, cx| {
14394                let (title, location_tasks, workspace) = editor
14395                    .update_in(cx, |editor, window, cx| {
14396                        let tab_kind = match kind {
14397                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14398                            _ => "Definitions",
14399                        };
14400                        let title = definitions
14401                            .iter()
14402                            .find_map(|definition| match definition {
14403                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14404                                    let buffer = origin.buffer.read(cx);
14405                                    format!(
14406                                        "{} for {}",
14407                                        tab_kind,
14408                                        buffer
14409                                            .text_for_range(origin.range.clone())
14410                                            .collect::<String>()
14411                                    )
14412                                }),
14413                                HoverLink::InlayHint(_, _) => None,
14414                                HoverLink::Url(_) => None,
14415                                HoverLink::File(_) => None,
14416                            })
14417                            .unwrap_or(tab_kind.to_string());
14418                        let location_tasks = definitions
14419                            .into_iter()
14420                            .map(|definition| match definition {
14421                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14422                                HoverLink::InlayHint(lsp_location, server_id) => editor
14423                                    .compute_target_location(lsp_location, server_id, window, cx),
14424                                HoverLink::Url(_) => Task::ready(Ok(None)),
14425                                HoverLink::File(_) => Task::ready(Ok(None)),
14426                            })
14427                            .collect::<Vec<_>>();
14428                        (title, location_tasks, editor.workspace().clone())
14429                    })
14430                    .context("location tasks preparation")?;
14431
14432                let locations = future::join_all(location_tasks)
14433                    .await
14434                    .into_iter()
14435                    .filter_map(|location| location.transpose())
14436                    .collect::<Result<_>>()
14437                    .context("location tasks")?;
14438
14439                let Some(workspace) = workspace else {
14440                    return Ok(Navigated::No);
14441                };
14442                let opened = workspace
14443                    .update_in(cx, |workspace, window, cx| {
14444                        Self::open_locations_in_multibuffer(
14445                            workspace,
14446                            locations,
14447                            title,
14448                            split,
14449                            MultibufferSelectionMode::First,
14450                            window,
14451                            cx,
14452                        )
14453                    })
14454                    .ok();
14455
14456                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14457            })
14458        } else {
14459            Task::ready(Ok(Navigated::No))
14460        }
14461    }
14462
14463    fn compute_target_location(
14464        &self,
14465        lsp_location: lsp::Location,
14466        server_id: LanguageServerId,
14467        window: &mut Window,
14468        cx: &mut Context<Self>,
14469    ) -> Task<anyhow::Result<Option<Location>>> {
14470        let Some(project) = self.project.clone() else {
14471            return Task::ready(Ok(None));
14472        };
14473
14474        cx.spawn_in(window, async move |editor, cx| {
14475            let location_task = editor.update(cx, |_, cx| {
14476                project.update(cx, |project, cx| {
14477                    let language_server_name = project
14478                        .language_server_statuses(cx)
14479                        .find(|(id, _)| server_id == *id)
14480                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14481                    language_server_name.map(|language_server_name| {
14482                        project.open_local_buffer_via_lsp(
14483                            lsp_location.uri.clone(),
14484                            server_id,
14485                            language_server_name,
14486                            cx,
14487                        )
14488                    })
14489                })
14490            })?;
14491            let location = match location_task {
14492                Some(task) => Some({
14493                    let target_buffer_handle = task.await.context("open local buffer")?;
14494                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14495                        let target_start = target_buffer
14496                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14497                        let target_end = target_buffer
14498                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14499                        target_buffer.anchor_after(target_start)
14500                            ..target_buffer.anchor_before(target_end)
14501                    })?;
14502                    Location {
14503                        buffer: target_buffer_handle,
14504                        range,
14505                    }
14506                }),
14507                None => None,
14508            };
14509            Ok(location)
14510        })
14511    }
14512
14513    pub fn find_all_references(
14514        &mut self,
14515        _: &FindAllReferences,
14516        window: &mut Window,
14517        cx: &mut Context<Self>,
14518    ) -> Option<Task<Result<Navigated>>> {
14519        let selection = self.selections.newest::<usize>(cx);
14520        let multi_buffer = self.buffer.read(cx);
14521        let head = selection.head();
14522
14523        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14524        let head_anchor = multi_buffer_snapshot.anchor_at(
14525            head,
14526            if head < selection.tail() {
14527                Bias::Right
14528            } else {
14529                Bias::Left
14530            },
14531        );
14532
14533        match self
14534            .find_all_references_task_sources
14535            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14536        {
14537            Ok(_) => {
14538                log::info!(
14539                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14540                );
14541                return None;
14542            }
14543            Err(i) => {
14544                self.find_all_references_task_sources.insert(i, head_anchor);
14545            }
14546        }
14547
14548        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14549        let workspace = self.workspace()?;
14550        let project = workspace.read(cx).project().clone();
14551        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14552        Some(cx.spawn_in(window, async move |editor, cx| {
14553            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14554                if let Ok(i) = editor
14555                    .find_all_references_task_sources
14556                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14557                {
14558                    editor.find_all_references_task_sources.remove(i);
14559                }
14560            });
14561
14562            let locations = references.await?;
14563            if locations.is_empty() {
14564                return anyhow::Ok(Navigated::No);
14565            }
14566
14567            workspace.update_in(cx, |workspace, window, cx| {
14568                let title = locations
14569                    .first()
14570                    .as_ref()
14571                    .map(|location| {
14572                        let buffer = location.buffer.read(cx);
14573                        format!(
14574                            "References to `{}`",
14575                            buffer
14576                                .text_for_range(location.range.clone())
14577                                .collect::<String>()
14578                        )
14579                    })
14580                    .unwrap();
14581                Self::open_locations_in_multibuffer(
14582                    workspace,
14583                    locations,
14584                    title,
14585                    false,
14586                    MultibufferSelectionMode::First,
14587                    window,
14588                    cx,
14589                );
14590                Navigated::Yes
14591            })
14592        }))
14593    }
14594
14595    /// Opens a multibuffer with the given project locations in it
14596    pub fn open_locations_in_multibuffer(
14597        workspace: &mut Workspace,
14598        mut locations: Vec<Location>,
14599        title: String,
14600        split: bool,
14601        multibuffer_selection_mode: MultibufferSelectionMode,
14602        window: &mut Window,
14603        cx: &mut Context<Workspace>,
14604    ) {
14605        // If there are multiple definitions, open them in a multibuffer
14606        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14607        let mut locations = locations.into_iter().peekable();
14608        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14609        let capability = workspace.project().read(cx).capability();
14610
14611        let excerpt_buffer = cx.new(|cx| {
14612            let mut multibuffer = MultiBuffer::new(capability);
14613            while let Some(location) = locations.next() {
14614                let buffer = location.buffer.read(cx);
14615                let mut ranges_for_buffer = Vec::new();
14616                let range = location.range.to_point(buffer);
14617                ranges_for_buffer.push(range.clone());
14618
14619                while let Some(next_location) = locations.peek() {
14620                    if next_location.buffer == location.buffer {
14621                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14622                        locations.next();
14623                    } else {
14624                        break;
14625                    }
14626                }
14627
14628                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14629                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14630                    PathKey::for_buffer(&location.buffer, cx),
14631                    location.buffer.clone(),
14632                    ranges_for_buffer,
14633                    DEFAULT_MULTIBUFFER_CONTEXT,
14634                    cx,
14635                );
14636                ranges.extend(new_ranges)
14637            }
14638
14639            multibuffer.with_title(title)
14640        });
14641
14642        let editor = cx.new(|cx| {
14643            Editor::for_multibuffer(
14644                excerpt_buffer,
14645                Some(workspace.project().clone()),
14646                window,
14647                cx,
14648            )
14649        });
14650        editor.update(cx, |editor, cx| {
14651            match multibuffer_selection_mode {
14652                MultibufferSelectionMode::First => {
14653                    if let Some(first_range) = ranges.first() {
14654                        editor.change_selections(None, window, cx, |selections| {
14655                            selections.clear_disjoint();
14656                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14657                        });
14658                    }
14659                    editor.highlight_background::<Self>(
14660                        &ranges,
14661                        |theme| theme.editor_highlighted_line_background,
14662                        cx,
14663                    );
14664                }
14665                MultibufferSelectionMode::All => {
14666                    editor.change_selections(None, window, cx, |selections| {
14667                        selections.clear_disjoint();
14668                        selections.select_anchor_ranges(ranges);
14669                    });
14670                }
14671            }
14672            editor.register_buffers_with_language_servers(cx);
14673        });
14674
14675        let item = Box::new(editor);
14676        let item_id = item.item_id();
14677
14678        if split {
14679            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14680        } else {
14681            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14682                let (preview_item_id, preview_item_idx) =
14683                    workspace.active_pane().update(cx, |pane, _| {
14684                        (pane.preview_item_id(), pane.preview_item_idx())
14685                    });
14686
14687                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14688
14689                if let Some(preview_item_id) = preview_item_id {
14690                    workspace.active_pane().update(cx, |pane, cx| {
14691                        pane.remove_item(preview_item_id, false, false, window, cx);
14692                    });
14693                }
14694            } else {
14695                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14696            }
14697        }
14698        workspace.active_pane().update(cx, |pane, cx| {
14699            pane.set_preview_item_id(Some(item_id), cx);
14700        });
14701    }
14702
14703    pub fn rename(
14704        &mut self,
14705        _: &Rename,
14706        window: &mut Window,
14707        cx: &mut Context<Self>,
14708    ) -> Option<Task<Result<()>>> {
14709        use language::ToOffset as _;
14710
14711        let provider = self.semantics_provider.clone()?;
14712        let selection = self.selections.newest_anchor().clone();
14713        let (cursor_buffer, cursor_buffer_position) = self
14714            .buffer
14715            .read(cx)
14716            .text_anchor_for_position(selection.head(), cx)?;
14717        let (tail_buffer, cursor_buffer_position_end) = self
14718            .buffer
14719            .read(cx)
14720            .text_anchor_for_position(selection.tail(), cx)?;
14721        if tail_buffer != cursor_buffer {
14722            return None;
14723        }
14724
14725        let snapshot = cursor_buffer.read(cx).snapshot();
14726        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14727        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14728        let prepare_rename = provider
14729            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14730            .unwrap_or_else(|| Task::ready(Ok(None)));
14731        drop(snapshot);
14732
14733        Some(cx.spawn_in(window, async move |this, cx| {
14734            let rename_range = if let Some(range) = prepare_rename.await? {
14735                Some(range)
14736            } else {
14737                this.update(cx, |this, cx| {
14738                    let buffer = this.buffer.read(cx).snapshot(cx);
14739                    let mut buffer_highlights = this
14740                        .document_highlights_for_position(selection.head(), &buffer)
14741                        .filter(|highlight| {
14742                            highlight.start.excerpt_id == selection.head().excerpt_id
14743                                && highlight.end.excerpt_id == selection.head().excerpt_id
14744                        });
14745                    buffer_highlights
14746                        .next()
14747                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14748                })?
14749            };
14750            if let Some(rename_range) = rename_range {
14751                this.update_in(cx, |this, window, cx| {
14752                    let snapshot = cursor_buffer.read(cx).snapshot();
14753                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14754                    let cursor_offset_in_rename_range =
14755                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14756                    let cursor_offset_in_rename_range_end =
14757                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14758
14759                    this.take_rename(false, window, cx);
14760                    let buffer = this.buffer.read(cx).read(cx);
14761                    let cursor_offset = selection.head().to_offset(&buffer);
14762                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14763                    let rename_end = rename_start + rename_buffer_range.len();
14764                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14765                    let mut old_highlight_id = None;
14766                    let old_name: Arc<str> = buffer
14767                        .chunks(rename_start..rename_end, true)
14768                        .map(|chunk| {
14769                            if old_highlight_id.is_none() {
14770                                old_highlight_id = chunk.syntax_highlight_id;
14771                            }
14772                            chunk.text
14773                        })
14774                        .collect::<String>()
14775                        .into();
14776
14777                    drop(buffer);
14778
14779                    // Position the selection in the rename editor so that it matches the current selection.
14780                    this.show_local_selections = false;
14781                    let rename_editor = cx.new(|cx| {
14782                        let mut editor = Editor::single_line(window, cx);
14783                        editor.buffer.update(cx, |buffer, cx| {
14784                            buffer.edit([(0..0, old_name.clone())], None, cx)
14785                        });
14786                        let rename_selection_range = match cursor_offset_in_rename_range
14787                            .cmp(&cursor_offset_in_rename_range_end)
14788                        {
14789                            Ordering::Equal => {
14790                                editor.select_all(&SelectAll, window, cx);
14791                                return editor;
14792                            }
14793                            Ordering::Less => {
14794                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14795                            }
14796                            Ordering::Greater => {
14797                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14798                            }
14799                        };
14800                        if rename_selection_range.end > old_name.len() {
14801                            editor.select_all(&SelectAll, window, cx);
14802                        } else {
14803                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14804                                s.select_ranges([rename_selection_range]);
14805                            });
14806                        }
14807                        editor
14808                    });
14809                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14810                        if e == &EditorEvent::Focused {
14811                            cx.emit(EditorEvent::FocusedIn)
14812                        }
14813                    })
14814                    .detach();
14815
14816                    let write_highlights =
14817                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14818                    let read_highlights =
14819                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14820                    let ranges = write_highlights
14821                        .iter()
14822                        .flat_map(|(_, ranges)| ranges.iter())
14823                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14824                        .cloned()
14825                        .collect();
14826
14827                    this.highlight_text::<Rename>(
14828                        ranges,
14829                        HighlightStyle {
14830                            fade_out: Some(0.6),
14831                            ..Default::default()
14832                        },
14833                        cx,
14834                    );
14835                    let rename_focus_handle = rename_editor.focus_handle(cx);
14836                    window.focus(&rename_focus_handle);
14837                    let block_id = this.insert_blocks(
14838                        [BlockProperties {
14839                            style: BlockStyle::Flex,
14840                            placement: BlockPlacement::Below(range.start),
14841                            height: Some(1),
14842                            render: Arc::new({
14843                                let rename_editor = rename_editor.clone();
14844                                move |cx: &mut BlockContext| {
14845                                    let mut text_style = cx.editor_style.text.clone();
14846                                    if let Some(highlight_style) = old_highlight_id
14847                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14848                                    {
14849                                        text_style = text_style.highlight(highlight_style);
14850                                    }
14851                                    div()
14852                                        .block_mouse_down()
14853                                        .pl(cx.anchor_x)
14854                                        .child(EditorElement::new(
14855                                            &rename_editor,
14856                                            EditorStyle {
14857                                                background: cx.theme().system().transparent,
14858                                                local_player: cx.editor_style.local_player,
14859                                                text: text_style,
14860                                                scrollbar_width: cx.editor_style.scrollbar_width,
14861                                                syntax: cx.editor_style.syntax.clone(),
14862                                                status: cx.editor_style.status.clone(),
14863                                                inlay_hints_style: HighlightStyle {
14864                                                    font_weight: Some(FontWeight::BOLD),
14865                                                    ..make_inlay_hints_style(cx.app)
14866                                                },
14867                                                inline_completion_styles: make_suggestion_styles(
14868                                                    cx.app,
14869                                                ),
14870                                                ..EditorStyle::default()
14871                                            },
14872                                        ))
14873                                        .into_any_element()
14874                                }
14875                            }),
14876                            priority: 0,
14877                            render_in_minimap: true,
14878                        }],
14879                        Some(Autoscroll::fit()),
14880                        cx,
14881                    )[0];
14882                    this.pending_rename = Some(RenameState {
14883                        range,
14884                        old_name,
14885                        editor: rename_editor,
14886                        block_id,
14887                    });
14888                })?;
14889            }
14890
14891            Ok(())
14892        }))
14893    }
14894
14895    pub fn confirm_rename(
14896        &mut self,
14897        _: &ConfirmRename,
14898        window: &mut Window,
14899        cx: &mut Context<Self>,
14900    ) -> Option<Task<Result<()>>> {
14901        let rename = self.take_rename(false, window, cx)?;
14902        let workspace = self.workspace()?.downgrade();
14903        let (buffer, start) = self
14904            .buffer
14905            .read(cx)
14906            .text_anchor_for_position(rename.range.start, cx)?;
14907        let (end_buffer, _) = self
14908            .buffer
14909            .read(cx)
14910            .text_anchor_for_position(rename.range.end, cx)?;
14911        if buffer != end_buffer {
14912            return None;
14913        }
14914
14915        let old_name = rename.old_name;
14916        let new_name = rename.editor.read(cx).text(cx);
14917
14918        let rename = self.semantics_provider.as_ref()?.perform_rename(
14919            &buffer,
14920            start,
14921            new_name.clone(),
14922            cx,
14923        )?;
14924
14925        Some(cx.spawn_in(window, async move |editor, cx| {
14926            let project_transaction = rename.await?;
14927            Self::open_project_transaction(
14928                &editor,
14929                workspace,
14930                project_transaction,
14931                format!("Rename: {}{}", old_name, new_name),
14932                cx,
14933            )
14934            .await?;
14935
14936            editor.update(cx, |editor, cx| {
14937                editor.refresh_document_highlights(cx);
14938            })?;
14939            Ok(())
14940        }))
14941    }
14942
14943    fn take_rename(
14944        &mut self,
14945        moving_cursor: bool,
14946        window: &mut Window,
14947        cx: &mut Context<Self>,
14948    ) -> Option<RenameState> {
14949        let rename = self.pending_rename.take()?;
14950        if rename.editor.focus_handle(cx).is_focused(window) {
14951            window.focus(&self.focus_handle);
14952        }
14953
14954        self.remove_blocks(
14955            [rename.block_id].into_iter().collect(),
14956            Some(Autoscroll::fit()),
14957            cx,
14958        );
14959        self.clear_highlights::<Rename>(cx);
14960        self.show_local_selections = true;
14961
14962        if moving_cursor {
14963            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14964                editor.selections.newest::<usize>(cx).head()
14965            });
14966
14967            // Update the selection to match the position of the selection inside
14968            // the rename editor.
14969            let snapshot = self.buffer.read(cx).read(cx);
14970            let rename_range = rename.range.to_offset(&snapshot);
14971            let cursor_in_editor = snapshot
14972                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14973                .min(rename_range.end);
14974            drop(snapshot);
14975
14976            self.change_selections(None, window, cx, |s| {
14977                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14978            });
14979        } else {
14980            self.refresh_document_highlights(cx);
14981        }
14982
14983        Some(rename)
14984    }
14985
14986    pub fn pending_rename(&self) -> Option<&RenameState> {
14987        self.pending_rename.as_ref()
14988    }
14989
14990    fn format(
14991        &mut self,
14992        _: &Format,
14993        window: &mut Window,
14994        cx: &mut Context<Self>,
14995    ) -> Option<Task<Result<()>>> {
14996        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14997
14998        let project = match &self.project {
14999            Some(project) => project.clone(),
15000            None => return None,
15001        };
15002
15003        Some(self.perform_format(
15004            project,
15005            FormatTrigger::Manual,
15006            FormatTarget::Buffers,
15007            window,
15008            cx,
15009        ))
15010    }
15011
15012    fn format_selections(
15013        &mut self,
15014        _: &FormatSelections,
15015        window: &mut Window,
15016        cx: &mut Context<Self>,
15017    ) -> Option<Task<Result<()>>> {
15018        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15019
15020        let project = match &self.project {
15021            Some(project) => project.clone(),
15022            None => return None,
15023        };
15024
15025        let ranges = self
15026            .selections
15027            .all_adjusted(cx)
15028            .into_iter()
15029            .map(|selection| selection.range())
15030            .collect_vec();
15031
15032        Some(self.perform_format(
15033            project,
15034            FormatTrigger::Manual,
15035            FormatTarget::Ranges(ranges),
15036            window,
15037            cx,
15038        ))
15039    }
15040
15041    fn perform_format(
15042        &mut self,
15043        project: Entity<Project>,
15044        trigger: FormatTrigger,
15045        target: FormatTarget,
15046        window: &mut Window,
15047        cx: &mut Context<Self>,
15048    ) -> Task<Result<()>> {
15049        let buffer = self.buffer.clone();
15050        let (buffers, target) = match target {
15051            FormatTarget::Buffers => {
15052                let mut buffers = buffer.read(cx).all_buffers();
15053                if trigger == FormatTrigger::Save {
15054                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15055                }
15056                (buffers, LspFormatTarget::Buffers)
15057            }
15058            FormatTarget::Ranges(selection_ranges) => {
15059                let multi_buffer = buffer.read(cx);
15060                let snapshot = multi_buffer.read(cx);
15061                let mut buffers = HashSet::default();
15062                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15063                    BTreeMap::new();
15064                for selection_range in selection_ranges {
15065                    for (buffer, buffer_range, _) in
15066                        snapshot.range_to_buffer_ranges(selection_range)
15067                    {
15068                        let buffer_id = buffer.remote_id();
15069                        let start = buffer.anchor_before(buffer_range.start);
15070                        let end = buffer.anchor_after(buffer_range.end);
15071                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15072                        buffer_id_to_ranges
15073                            .entry(buffer_id)
15074                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15075                            .or_insert_with(|| vec![start..end]);
15076                    }
15077                }
15078                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15079            }
15080        };
15081
15082        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15083        let selections_prev = transaction_id_prev
15084            .and_then(|transaction_id_prev| {
15085                // default to selections as they were after the last edit, if we have them,
15086                // instead of how they are now.
15087                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15088                // will take you back to where you made the last edit, instead of staying where you scrolled
15089                self.selection_history
15090                    .transaction(transaction_id_prev)
15091                    .map(|t| t.0.clone())
15092            })
15093            .unwrap_or_else(|| {
15094                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15095                self.selections.disjoint_anchors()
15096            });
15097
15098        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15099        let format = project.update(cx, |project, cx| {
15100            project.format(buffers, target, true, trigger, cx)
15101        });
15102
15103        cx.spawn_in(window, async move |editor, cx| {
15104            let transaction = futures::select_biased! {
15105                transaction = format.log_err().fuse() => transaction,
15106                () = timeout => {
15107                    log::warn!("timed out waiting for formatting");
15108                    None
15109                }
15110            };
15111
15112            buffer
15113                .update(cx, |buffer, cx| {
15114                    if let Some(transaction) = transaction {
15115                        if !buffer.is_singleton() {
15116                            buffer.push_transaction(&transaction.0, cx);
15117                        }
15118                    }
15119                    cx.notify();
15120                })
15121                .ok();
15122
15123            if let Some(transaction_id_now) =
15124                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15125            {
15126                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15127                if has_new_transaction {
15128                    _ = editor.update(cx, |editor, _| {
15129                        editor
15130                            .selection_history
15131                            .insert_transaction(transaction_id_now, selections_prev);
15132                    });
15133                }
15134            }
15135
15136            Ok(())
15137        })
15138    }
15139
15140    fn organize_imports(
15141        &mut self,
15142        _: &OrganizeImports,
15143        window: &mut Window,
15144        cx: &mut Context<Self>,
15145    ) -> Option<Task<Result<()>>> {
15146        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15147        let project = match &self.project {
15148            Some(project) => project.clone(),
15149            None => return None,
15150        };
15151        Some(self.perform_code_action_kind(
15152            project,
15153            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15154            window,
15155            cx,
15156        ))
15157    }
15158
15159    fn perform_code_action_kind(
15160        &mut self,
15161        project: Entity<Project>,
15162        kind: CodeActionKind,
15163        window: &mut Window,
15164        cx: &mut Context<Self>,
15165    ) -> Task<Result<()>> {
15166        let buffer = self.buffer.clone();
15167        let buffers = buffer.read(cx).all_buffers();
15168        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15169        let apply_action = project.update(cx, |project, cx| {
15170            project.apply_code_action_kind(buffers, kind, true, cx)
15171        });
15172        cx.spawn_in(window, async move |_, cx| {
15173            let transaction = futures::select_biased! {
15174                () = timeout => {
15175                    log::warn!("timed out waiting for executing code action");
15176                    None
15177                }
15178                transaction = apply_action.log_err().fuse() => transaction,
15179            };
15180            buffer
15181                .update(cx, |buffer, cx| {
15182                    // check if we need this
15183                    if let Some(transaction) = transaction {
15184                        if !buffer.is_singleton() {
15185                            buffer.push_transaction(&transaction.0, cx);
15186                        }
15187                    }
15188                    cx.notify();
15189                })
15190                .ok();
15191            Ok(())
15192        })
15193    }
15194
15195    fn restart_language_server(
15196        &mut self,
15197        _: &RestartLanguageServer,
15198        _: &mut Window,
15199        cx: &mut Context<Self>,
15200    ) {
15201        if let Some(project) = self.project.clone() {
15202            self.buffer.update(cx, |multi_buffer, cx| {
15203                project.update(cx, |project, cx| {
15204                    project.restart_language_servers_for_buffers(
15205                        multi_buffer.all_buffers().into_iter().collect(),
15206                        cx,
15207                    );
15208                });
15209            })
15210        }
15211    }
15212
15213    fn stop_language_server(
15214        &mut self,
15215        _: &StopLanguageServer,
15216        _: &mut Window,
15217        cx: &mut Context<Self>,
15218    ) {
15219        if let Some(project) = self.project.clone() {
15220            self.buffer.update(cx, |multi_buffer, cx| {
15221                project.update(cx, |project, cx| {
15222                    project.stop_language_servers_for_buffers(
15223                        multi_buffer.all_buffers().into_iter().collect(),
15224                        cx,
15225                    );
15226                    cx.emit(project::Event::RefreshInlayHints);
15227                });
15228            });
15229        }
15230    }
15231
15232    fn cancel_language_server_work(
15233        workspace: &mut Workspace,
15234        _: &actions::CancelLanguageServerWork,
15235        _: &mut Window,
15236        cx: &mut Context<Workspace>,
15237    ) {
15238        let project = workspace.project();
15239        let buffers = workspace
15240            .active_item(cx)
15241            .and_then(|item| item.act_as::<Editor>(cx))
15242            .map_or(HashSet::default(), |editor| {
15243                editor.read(cx).buffer.read(cx).all_buffers()
15244            });
15245        project.update(cx, |project, cx| {
15246            project.cancel_language_server_work_for_buffers(buffers, cx);
15247        });
15248    }
15249
15250    fn show_character_palette(
15251        &mut self,
15252        _: &ShowCharacterPalette,
15253        window: &mut Window,
15254        _: &mut Context<Self>,
15255    ) {
15256        window.show_character_palette();
15257    }
15258
15259    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15260        if self.mode.is_minimap() {
15261            return;
15262        }
15263
15264        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15265            let buffer = self.buffer.read(cx).snapshot(cx);
15266            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15267            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15268            let is_valid = buffer
15269                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15270                .any(|entry| {
15271                    entry.diagnostic.is_primary
15272                        && !entry.range.is_empty()
15273                        && entry.range.start == primary_range_start
15274                        && entry.diagnostic.message == active_diagnostics.active_message
15275                });
15276
15277            if !is_valid {
15278                self.dismiss_diagnostics(cx);
15279            }
15280        }
15281    }
15282
15283    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15284        match &self.active_diagnostics {
15285            ActiveDiagnostic::Group(group) => Some(group),
15286            _ => None,
15287        }
15288    }
15289
15290    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15291        self.dismiss_diagnostics(cx);
15292        self.active_diagnostics = ActiveDiagnostic::All;
15293    }
15294
15295    fn activate_diagnostics(
15296        &mut self,
15297        buffer_id: BufferId,
15298        diagnostic: DiagnosticEntry<usize>,
15299        window: &mut Window,
15300        cx: &mut Context<Self>,
15301    ) {
15302        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15303            return;
15304        }
15305        self.dismiss_diagnostics(cx);
15306        let snapshot = self.snapshot(window, cx);
15307        let buffer = self.buffer.read(cx).snapshot(cx);
15308        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15309            return;
15310        };
15311
15312        let diagnostic_group = buffer
15313            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15314            .collect::<Vec<_>>();
15315
15316        let blocks =
15317            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15318
15319        let blocks = self.display_map.update(cx, |display_map, cx| {
15320            display_map.insert_blocks(blocks, cx).into_iter().collect()
15321        });
15322        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15323            active_range: buffer.anchor_before(diagnostic.range.start)
15324                ..buffer.anchor_after(diagnostic.range.end),
15325            active_message: diagnostic.diagnostic.message.clone(),
15326            group_id: diagnostic.diagnostic.group_id,
15327            blocks,
15328        });
15329        cx.notify();
15330    }
15331
15332    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15333        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15334            return;
15335        };
15336
15337        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15338        if let ActiveDiagnostic::Group(group) = prev {
15339            self.display_map.update(cx, |display_map, cx| {
15340                display_map.remove_blocks(group.blocks, cx);
15341            });
15342            cx.notify();
15343        }
15344    }
15345
15346    /// Disable inline diagnostics rendering for this editor.
15347    pub fn disable_inline_diagnostics(&mut self) {
15348        self.inline_diagnostics_enabled = false;
15349        self.inline_diagnostics_update = Task::ready(());
15350        self.inline_diagnostics.clear();
15351    }
15352
15353    pub fn diagnostics_enabled(&self) -> bool {
15354        self.mode.is_full()
15355    }
15356
15357    pub fn inline_diagnostics_enabled(&self) -> bool {
15358        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15359    }
15360
15361    pub fn show_inline_diagnostics(&self) -> bool {
15362        self.show_inline_diagnostics
15363    }
15364
15365    pub fn toggle_inline_diagnostics(
15366        &mut self,
15367        _: &ToggleInlineDiagnostics,
15368        window: &mut Window,
15369        cx: &mut Context<Editor>,
15370    ) {
15371        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15372        self.refresh_inline_diagnostics(false, window, cx);
15373    }
15374
15375    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15376        self.diagnostics_max_severity = severity;
15377        self.display_map.update(cx, |display_map, _| {
15378            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15379        });
15380    }
15381
15382    pub fn toggle_diagnostics(
15383        &mut self,
15384        _: &ToggleDiagnostics,
15385        window: &mut Window,
15386        cx: &mut Context<Editor>,
15387    ) {
15388        if !self.diagnostics_enabled() {
15389            return;
15390        }
15391
15392        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15393            EditorSettings::get_global(cx)
15394                .diagnostics_max_severity
15395                .filter(|severity| severity != &DiagnosticSeverity::Off)
15396                .unwrap_or(DiagnosticSeverity::Hint)
15397        } else {
15398            DiagnosticSeverity::Off
15399        };
15400        self.set_max_diagnostics_severity(new_severity, cx);
15401        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15402            self.active_diagnostics = ActiveDiagnostic::None;
15403            self.inline_diagnostics_update = Task::ready(());
15404            self.inline_diagnostics.clear();
15405        } else {
15406            self.refresh_inline_diagnostics(false, window, cx);
15407        }
15408
15409        cx.notify();
15410    }
15411
15412    pub fn toggle_minimap(
15413        &mut self,
15414        _: &ToggleMinimap,
15415        window: &mut Window,
15416        cx: &mut Context<Editor>,
15417    ) {
15418        if self.supports_minimap(cx) {
15419            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15420        }
15421    }
15422
15423    fn refresh_inline_diagnostics(
15424        &mut self,
15425        debounce: bool,
15426        window: &mut Window,
15427        cx: &mut Context<Self>,
15428    ) {
15429        let max_severity = ProjectSettings::get_global(cx)
15430            .diagnostics
15431            .inline
15432            .max_severity
15433            .unwrap_or(self.diagnostics_max_severity);
15434
15435        if self.mode.is_minimap()
15436            || !self.inline_diagnostics_enabled()
15437            || !self.show_inline_diagnostics
15438            || max_severity == DiagnosticSeverity::Off
15439        {
15440            self.inline_diagnostics_update = Task::ready(());
15441            self.inline_diagnostics.clear();
15442            return;
15443        }
15444
15445        let debounce_ms = ProjectSettings::get_global(cx)
15446            .diagnostics
15447            .inline
15448            .update_debounce_ms;
15449        let debounce = if debounce && debounce_ms > 0 {
15450            Some(Duration::from_millis(debounce_ms))
15451        } else {
15452            None
15453        };
15454        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15455            let editor = editor.upgrade().unwrap();
15456
15457            if let Some(debounce) = debounce {
15458                cx.background_executor().timer(debounce).await;
15459            }
15460            let Some(snapshot) = editor
15461                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15462                .ok()
15463            else {
15464                return;
15465            };
15466
15467            let new_inline_diagnostics = cx
15468                .background_spawn(async move {
15469                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15470                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15471                        let message = diagnostic_entry
15472                            .diagnostic
15473                            .message
15474                            .split_once('\n')
15475                            .map(|(line, _)| line)
15476                            .map(SharedString::new)
15477                            .unwrap_or_else(|| {
15478                                SharedString::from(diagnostic_entry.diagnostic.message)
15479                            });
15480                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15481                        let (Ok(i) | Err(i)) = inline_diagnostics
15482                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15483                        inline_diagnostics.insert(
15484                            i,
15485                            (
15486                                start_anchor,
15487                                InlineDiagnostic {
15488                                    message,
15489                                    group_id: diagnostic_entry.diagnostic.group_id,
15490                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15491                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15492                                    severity: diagnostic_entry.diagnostic.severity,
15493                                },
15494                            ),
15495                        );
15496                    }
15497                    inline_diagnostics
15498                })
15499                .await;
15500
15501            editor
15502                .update(cx, |editor, cx| {
15503                    editor.inline_diagnostics = new_inline_diagnostics;
15504                    cx.notify();
15505                })
15506                .ok();
15507        });
15508    }
15509
15510    pub fn set_selections_from_remote(
15511        &mut self,
15512        selections: Vec<Selection<Anchor>>,
15513        pending_selection: Option<Selection<Anchor>>,
15514        window: &mut Window,
15515        cx: &mut Context<Self>,
15516    ) {
15517        let old_cursor_position = self.selections.newest_anchor().head();
15518        self.selections.change_with(cx, |s| {
15519            s.select_anchors(selections);
15520            if let Some(pending_selection) = pending_selection {
15521                s.set_pending(pending_selection, SelectMode::Character);
15522            } else {
15523                s.clear_pending();
15524            }
15525        });
15526        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15527    }
15528
15529    fn push_to_selection_history(&mut self) {
15530        self.selection_history.push(SelectionHistoryEntry {
15531            selections: self.selections.disjoint_anchors(),
15532            select_next_state: self.select_next_state.clone(),
15533            select_prev_state: self.select_prev_state.clone(),
15534            add_selections_state: self.add_selections_state.clone(),
15535        });
15536    }
15537
15538    pub fn transact(
15539        &mut self,
15540        window: &mut Window,
15541        cx: &mut Context<Self>,
15542        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15543    ) -> Option<TransactionId> {
15544        self.start_transaction_at(Instant::now(), window, cx);
15545        update(self, window, cx);
15546        self.end_transaction_at(Instant::now(), cx)
15547    }
15548
15549    pub fn start_transaction_at(
15550        &mut self,
15551        now: Instant,
15552        window: &mut Window,
15553        cx: &mut Context<Self>,
15554    ) {
15555        self.end_selection(window, cx);
15556        if let Some(tx_id) = self
15557            .buffer
15558            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15559        {
15560            self.selection_history
15561                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15562            cx.emit(EditorEvent::TransactionBegun {
15563                transaction_id: tx_id,
15564            })
15565        }
15566    }
15567
15568    pub fn end_transaction_at(
15569        &mut self,
15570        now: Instant,
15571        cx: &mut Context<Self>,
15572    ) -> Option<TransactionId> {
15573        if let Some(transaction_id) = self
15574            .buffer
15575            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15576        {
15577            if let Some((_, end_selections)) =
15578                self.selection_history.transaction_mut(transaction_id)
15579            {
15580                *end_selections = Some(self.selections.disjoint_anchors());
15581            } else {
15582                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15583            }
15584
15585            cx.emit(EditorEvent::Edited { transaction_id });
15586            Some(transaction_id)
15587        } else {
15588            None
15589        }
15590    }
15591
15592    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15593        if self.selection_mark_mode {
15594            self.change_selections(None, window, cx, |s| {
15595                s.move_with(|_, sel| {
15596                    sel.collapse_to(sel.head(), SelectionGoal::None);
15597                });
15598            })
15599        }
15600        self.selection_mark_mode = true;
15601        cx.notify();
15602    }
15603
15604    pub fn swap_selection_ends(
15605        &mut self,
15606        _: &actions::SwapSelectionEnds,
15607        window: &mut Window,
15608        cx: &mut Context<Self>,
15609    ) {
15610        self.change_selections(None, window, cx, |s| {
15611            s.move_with(|_, sel| {
15612                if sel.start != sel.end {
15613                    sel.reversed = !sel.reversed
15614                }
15615            });
15616        });
15617        self.request_autoscroll(Autoscroll::newest(), cx);
15618        cx.notify();
15619    }
15620
15621    pub fn toggle_fold(
15622        &mut self,
15623        _: &actions::ToggleFold,
15624        window: &mut Window,
15625        cx: &mut Context<Self>,
15626    ) {
15627        if self.is_singleton(cx) {
15628            let selection = self.selections.newest::<Point>(cx);
15629
15630            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15631            let range = if selection.is_empty() {
15632                let point = selection.head().to_display_point(&display_map);
15633                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15634                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15635                    .to_point(&display_map);
15636                start..end
15637            } else {
15638                selection.range()
15639            };
15640            if display_map.folds_in_range(range).next().is_some() {
15641                self.unfold_lines(&Default::default(), window, cx)
15642            } else {
15643                self.fold(&Default::default(), window, cx)
15644            }
15645        } else {
15646            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15647            let buffer_ids: HashSet<_> = self
15648                .selections
15649                .disjoint_anchor_ranges()
15650                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15651                .collect();
15652
15653            let should_unfold = buffer_ids
15654                .iter()
15655                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15656
15657            for buffer_id in buffer_ids {
15658                if should_unfold {
15659                    self.unfold_buffer(buffer_id, cx);
15660                } else {
15661                    self.fold_buffer(buffer_id, cx);
15662                }
15663            }
15664        }
15665    }
15666
15667    pub fn toggle_fold_recursive(
15668        &mut self,
15669        _: &actions::ToggleFoldRecursive,
15670        window: &mut Window,
15671        cx: &mut Context<Self>,
15672    ) {
15673        let selection = self.selections.newest::<Point>(cx);
15674
15675        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15676        let range = if selection.is_empty() {
15677            let point = selection.head().to_display_point(&display_map);
15678            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15679            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15680                .to_point(&display_map);
15681            start..end
15682        } else {
15683            selection.range()
15684        };
15685        if display_map.folds_in_range(range).next().is_some() {
15686            self.unfold_recursive(&Default::default(), window, cx)
15687        } else {
15688            self.fold_recursive(&Default::default(), window, cx)
15689        }
15690    }
15691
15692    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15693        if self.is_singleton(cx) {
15694            let mut to_fold = Vec::new();
15695            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15696            let selections = self.selections.all_adjusted(cx);
15697
15698            for selection in selections {
15699                let range = selection.range().sorted();
15700                let buffer_start_row = range.start.row;
15701
15702                if range.start.row != range.end.row {
15703                    let mut found = false;
15704                    let mut row = range.start.row;
15705                    while row <= range.end.row {
15706                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15707                        {
15708                            found = true;
15709                            row = crease.range().end.row + 1;
15710                            to_fold.push(crease);
15711                        } else {
15712                            row += 1
15713                        }
15714                    }
15715                    if found {
15716                        continue;
15717                    }
15718                }
15719
15720                for row in (0..=range.start.row).rev() {
15721                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15722                        if crease.range().end.row >= buffer_start_row {
15723                            to_fold.push(crease);
15724                            if row <= range.start.row {
15725                                break;
15726                            }
15727                        }
15728                    }
15729                }
15730            }
15731
15732            self.fold_creases(to_fold, true, window, cx);
15733        } else {
15734            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15735            let buffer_ids = self
15736                .selections
15737                .disjoint_anchor_ranges()
15738                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15739                .collect::<HashSet<_>>();
15740            for buffer_id in buffer_ids {
15741                self.fold_buffer(buffer_id, cx);
15742            }
15743        }
15744    }
15745
15746    fn fold_at_level(
15747        &mut self,
15748        fold_at: &FoldAtLevel,
15749        window: &mut Window,
15750        cx: &mut Context<Self>,
15751    ) {
15752        if !self.buffer.read(cx).is_singleton() {
15753            return;
15754        }
15755
15756        let fold_at_level = fold_at.0;
15757        let snapshot = self.buffer.read(cx).snapshot(cx);
15758        let mut to_fold = Vec::new();
15759        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15760
15761        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15762            while start_row < end_row {
15763                match self
15764                    .snapshot(window, cx)
15765                    .crease_for_buffer_row(MultiBufferRow(start_row))
15766                {
15767                    Some(crease) => {
15768                        let nested_start_row = crease.range().start.row + 1;
15769                        let nested_end_row = crease.range().end.row;
15770
15771                        if current_level < fold_at_level {
15772                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15773                        } else if current_level == fold_at_level {
15774                            to_fold.push(crease);
15775                        }
15776
15777                        start_row = nested_end_row + 1;
15778                    }
15779                    None => start_row += 1,
15780                }
15781            }
15782        }
15783
15784        self.fold_creases(to_fold, true, window, cx);
15785    }
15786
15787    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15788        if self.buffer.read(cx).is_singleton() {
15789            let mut fold_ranges = Vec::new();
15790            let snapshot = self.buffer.read(cx).snapshot(cx);
15791
15792            for row in 0..snapshot.max_row().0 {
15793                if let Some(foldable_range) = self
15794                    .snapshot(window, cx)
15795                    .crease_for_buffer_row(MultiBufferRow(row))
15796                {
15797                    fold_ranges.push(foldable_range);
15798                }
15799            }
15800
15801            self.fold_creases(fold_ranges, true, window, cx);
15802        } else {
15803            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15804                editor
15805                    .update_in(cx, |editor, _, cx| {
15806                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15807                            editor.fold_buffer(buffer_id, cx);
15808                        }
15809                    })
15810                    .ok();
15811            });
15812        }
15813    }
15814
15815    pub fn fold_function_bodies(
15816        &mut self,
15817        _: &actions::FoldFunctionBodies,
15818        window: &mut Window,
15819        cx: &mut Context<Self>,
15820    ) {
15821        let snapshot = self.buffer.read(cx).snapshot(cx);
15822
15823        let ranges = snapshot
15824            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15825            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15826            .collect::<Vec<_>>();
15827
15828        let creases = ranges
15829            .into_iter()
15830            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15831            .collect();
15832
15833        self.fold_creases(creases, true, window, cx);
15834    }
15835
15836    pub fn fold_recursive(
15837        &mut self,
15838        _: &actions::FoldRecursive,
15839        window: &mut Window,
15840        cx: &mut Context<Self>,
15841    ) {
15842        let mut to_fold = Vec::new();
15843        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15844        let selections = self.selections.all_adjusted(cx);
15845
15846        for selection in selections {
15847            let range = selection.range().sorted();
15848            let buffer_start_row = range.start.row;
15849
15850            if range.start.row != range.end.row {
15851                let mut found = false;
15852                for row in range.start.row..=range.end.row {
15853                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15854                        found = true;
15855                        to_fold.push(crease);
15856                    }
15857                }
15858                if found {
15859                    continue;
15860                }
15861            }
15862
15863            for row in (0..=range.start.row).rev() {
15864                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15865                    if crease.range().end.row >= buffer_start_row {
15866                        to_fold.push(crease);
15867                    } else {
15868                        break;
15869                    }
15870                }
15871            }
15872        }
15873
15874        self.fold_creases(to_fold, true, window, cx);
15875    }
15876
15877    pub fn fold_at(
15878        &mut self,
15879        buffer_row: MultiBufferRow,
15880        window: &mut Window,
15881        cx: &mut Context<Self>,
15882    ) {
15883        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15884
15885        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15886            let autoscroll = self
15887                .selections
15888                .all::<Point>(cx)
15889                .iter()
15890                .any(|selection| crease.range().overlaps(&selection.range()));
15891
15892            self.fold_creases(vec![crease], autoscroll, window, cx);
15893        }
15894    }
15895
15896    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15897        if self.is_singleton(cx) {
15898            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15899            let buffer = &display_map.buffer_snapshot;
15900            let selections = self.selections.all::<Point>(cx);
15901            let ranges = selections
15902                .iter()
15903                .map(|s| {
15904                    let range = s.display_range(&display_map).sorted();
15905                    let mut start = range.start.to_point(&display_map);
15906                    let mut end = range.end.to_point(&display_map);
15907                    start.column = 0;
15908                    end.column = buffer.line_len(MultiBufferRow(end.row));
15909                    start..end
15910                })
15911                .collect::<Vec<_>>();
15912
15913            self.unfold_ranges(&ranges, true, true, cx);
15914        } else {
15915            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15916            let buffer_ids = self
15917                .selections
15918                .disjoint_anchor_ranges()
15919                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15920                .collect::<HashSet<_>>();
15921            for buffer_id in buffer_ids {
15922                self.unfold_buffer(buffer_id, cx);
15923            }
15924        }
15925    }
15926
15927    pub fn unfold_recursive(
15928        &mut self,
15929        _: &UnfoldRecursive,
15930        _window: &mut Window,
15931        cx: &mut Context<Self>,
15932    ) {
15933        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15934        let selections = self.selections.all::<Point>(cx);
15935        let ranges = selections
15936            .iter()
15937            .map(|s| {
15938                let mut range = s.display_range(&display_map).sorted();
15939                *range.start.column_mut() = 0;
15940                *range.end.column_mut() = display_map.line_len(range.end.row());
15941                let start = range.start.to_point(&display_map);
15942                let end = range.end.to_point(&display_map);
15943                start..end
15944            })
15945            .collect::<Vec<_>>();
15946
15947        self.unfold_ranges(&ranges, true, true, cx);
15948    }
15949
15950    pub fn unfold_at(
15951        &mut self,
15952        buffer_row: MultiBufferRow,
15953        _window: &mut Window,
15954        cx: &mut Context<Self>,
15955    ) {
15956        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15957
15958        let intersection_range = Point::new(buffer_row.0, 0)
15959            ..Point::new(
15960                buffer_row.0,
15961                display_map.buffer_snapshot.line_len(buffer_row),
15962            );
15963
15964        let autoscroll = self
15965            .selections
15966            .all::<Point>(cx)
15967            .iter()
15968            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15969
15970        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15971    }
15972
15973    pub fn unfold_all(
15974        &mut self,
15975        _: &actions::UnfoldAll,
15976        _window: &mut Window,
15977        cx: &mut Context<Self>,
15978    ) {
15979        if self.buffer.read(cx).is_singleton() {
15980            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15981            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15982        } else {
15983            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15984                editor
15985                    .update(cx, |editor, cx| {
15986                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15987                            editor.unfold_buffer(buffer_id, cx);
15988                        }
15989                    })
15990                    .ok();
15991            });
15992        }
15993    }
15994
15995    pub fn fold_selected_ranges(
15996        &mut self,
15997        _: &FoldSelectedRanges,
15998        window: &mut Window,
15999        cx: &mut Context<Self>,
16000    ) {
16001        let selections = self.selections.all_adjusted(cx);
16002        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16003        let ranges = selections
16004            .into_iter()
16005            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16006            .collect::<Vec<_>>();
16007        self.fold_creases(ranges, true, window, cx);
16008    }
16009
16010    pub fn fold_ranges<T: ToOffset + Clone>(
16011        &mut self,
16012        ranges: Vec<Range<T>>,
16013        auto_scroll: bool,
16014        window: &mut Window,
16015        cx: &mut Context<Self>,
16016    ) {
16017        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16018        let ranges = ranges
16019            .into_iter()
16020            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16021            .collect::<Vec<_>>();
16022        self.fold_creases(ranges, auto_scroll, window, cx);
16023    }
16024
16025    pub fn fold_creases<T: ToOffset + Clone>(
16026        &mut self,
16027        creases: Vec<Crease<T>>,
16028        auto_scroll: bool,
16029        _window: &mut Window,
16030        cx: &mut Context<Self>,
16031    ) {
16032        if creases.is_empty() {
16033            return;
16034        }
16035
16036        let mut buffers_affected = HashSet::default();
16037        let multi_buffer = self.buffer().read(cx);
16038        for crease in &creases {
16039            if let Some((_, buffer, _)) =
16040                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16041            {
16042                buffers_affected.insert(buffer.read(cx).remote_id());
16043            };
16044        }
16045
16046        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16047
16048        if auto_scroll {
16049            self.request_autoscroll(Autoscroll::fit(), cx);
16050        }
16051
16052        cx.notify();
16053
16054        self.scrollbar_marker_state.dirty = true;
16055        self.folds_did_change(cx);
16056    }
16057
16058    /// Removes any folds whose ranges intersect any of the given ranges.
16059    pub fn unfold_ranges<T: ToOffset + Clone>(
16060        &mut self,
16061        ranges: &[Range<T>],
16062        inclusive: bool,
16063        auto_scroll: bool,
16064        cx: &mut Context<Self>,
16065    ) {
16066        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16067            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16068        });
16069        self.folds_did_change(cx);
16070    }
16071
16072    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16073        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16074            return;
16075        }
16076        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16077        self.display_map.update(cx, |display_map, cx| {
16078            display_map.fold_buffers([buffer_id], cx)
16079        });
16080        cx.emit(EditorEvent::BufferFoldToggled {
16081            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16082            folded: true,
16083        });
16084        cx.notify();
16085    }
16086
16087    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16088        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16089            return;
16090        }
16091        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16092        self.display_map.update(cx, |display_map, cx| {
16093            display_map.unfold_buffers([buffer_id], cx);
16094        });
16095        cx.emit(EditorEvent::BufferFoldToggled {
16096            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16097            folded: false,
16098        });
16099        cx.notify();
16100    }
16101
16102    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16103        self.display_map.read(cx).is_buffer_folded(buffer)
16104    }
16105
16106    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16107        self.display_map.read(cx).folded_buffers()
16108    }
16109
16110    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16111        self.display_map.update(cx, |display_map, cx| {
16112            display_map.disable_header_for_buffer(buffer_id, cx);
16113        });
16114        cx.notify();
16115    }
16116
16117    /// Removes any folds with the given ranges.
16118    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16119        &mut self,
16120        ranges: &[Range<T>],
16121        type_id: TypeId,
16122        auto_scroll: bool,
16123        cx: &mut Context<Self>,
16124    ) {
16125        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16126            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16127        });
16128        self.folds_did_change(cx);
16129    }
16130
16131    fn remove_folds_with<T: ToOffset + Clone>(
16132        &mut self,
16133        ranges: &[Range<T>],
16134        auto_scroll: bool,
16135        cx: &mut Context<Self>,
16136        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16137    ) {
16138        if ranges.is_empty() {
16139            return;
16140        }
16141
16142        let mut buffers_affected = HashSet::default();
16143        let multi_buffer = self.buffer().read(cx);
16144        for range in ranges {
16145            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16146                buffers_affected.insert(buffer.read(cx).remote_id());
16147            };
16148        }
16149
16150        self.display_map.update(cx, update);
16151
16152        if auto_scroll {
16153            self.request_autoscroll(Autoscroll::fit(), cx);
16154        }
16155
16156        cx.notify();
16157        self.scrollbar_marker_state.dirty = true;
16158        self.active_indent_guides_state.dirty = true;
16159    }
16160
16161    pub fn update_fold_widths(
16162        &mut self,
16163        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16164        cx: &mut Context<Self>,
16165    ) -> bool {
16166        self.display_map
16167            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16168    }
16169
16170    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16171        self.display_map.read(cx).fold_placeholder.clone()
16172    }
16173
16174    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16175        self.buffer.update(cx, |buffer, cx| {
16176            buffer.set_all_diff_hunks_expanded(cx);
16177        });
16178    }
16179
16180    pub fn expand_all_diff_hunks(
16181        &mut self,
16182        _: &ExpandAllDiffHunks,
16183        _window: &mut Window,
16184        cx: &mut Context<Self>,
16185    ) {
16186        self.buffer.update(cx, |buffer, cx| {
16187            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16188        });
16189    }
16190
16191    pub fn toggle_selected_diff_hunks(
16192        &mut self,
16193        _: &ToggleSelectedDiffHunks,
16194        _window: &mut Window,
16195        cx: &mut Context<Self>,
16196    ) {
16197        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16198        self.toggle_diff_hunks_in_ranges(ranges, cx);
16199    }
16200
16201    pub fn diff_hunks_in_ranges<'a>(
16202        &'a self,
16203        ranges: &'a [Range<Anchor>],
16204        buffer: &'a MultiBufferSnapshot,
16205    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16206        ranges.iter().flat_map(move |range| {
16207            let end_excerpt_id = range.end.excerpt_id;
16208            let range = range.to_point(buffer);
16209            let mut peek_end = range.end;
16210            if range.end.row < buffer.max_row().0 {
16211                peek_end = Point::new(range.end.row + 1, 0);
16212            }
16213            buffer
16214                .diff_hunks_in_range(range.start..peek_end)
16215                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16216        })
16217    }
16218
16219    pub fn has_stageable_diff_hunks_in_ranges(
16220        &self,
16221        ranges: &[Range<Anchor>],
16222        snapshot: &MultiBufferSnapshot,
16223    ) -> bool {
16224        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16225        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16226    }
16227
16228    pub fn toggle_staged_selected_diff_hunks(
16229        &mut self,
16230        _: &::git::ToggleStaged,
16231        _: &mut Window,
16232        cx: &mut Context<Self>,
16233    ) {
16234        let snapshot = self.buffer.read(cx).snapshot(cx);
16235        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16236        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16237        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16238    }
16239
16240    pub fn set_render_diff_hunk_controls(
16241        &mut self,
16242        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16243        cx: &mut Context<Self>,
16244    ) {
16245        self.render_diff_hunk_controls = render_diff_hunk_controls;
16246        cx.notify();
16247    }
16248
16249    pub fn stage_and_next(
16250        &mut self,
16251        _: &::git::StageAndNext,
16252        window: &mut Window,
16253        cx: &mut Context<Self>,
16254    ) {
16255        self.do_stage_or_unstage_and_next(true, window, cx);
16256    }
16257
16258    pub fn unstage_and_next(
16259        &mut self,
16260        _: &::git::UnstageAndNext,
16261        window: &mut Window,
16262        cx: &mut Context<Self>,
16263    ) {
16264        self.do_stage_or_unstage_and_next(false, window, cx);
16265    }
16266
16267    pub fn stage_or_unstage_diff_hunks(
16268        &mut self,
16269        stage: bool,
16270        ranges: Vec<Range<Anchor>>,
16271        cx: &mut Context<Self>,
16272    ) {
16273        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16274        cx.spawn(async move |this, cx| {
16275            task.await?;
16276            this.update(cx, |this, cx| {
16277                let snapshot = this.buffer.read(cx).snapshot(cx);
16278                let chunk_by = this
16279                    .diff_hunks_in_ranges(&ranges, &snapshot)
16280                    .chunk_by(|hunk| hunk.buffer_id);
16281                for (buffer_id, hunks) in &chunk_by {
16282                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16283                }
16284            })
16285        })
16286        .detach_and_log_err(cx);
16287    }
16288
16289    fn save_buffers_for_ranges_if_needed(
16290        &mut self,
16291        ranges: &[Range<Anchor>],
16292        cx: &mut Context<Editor>,
16293    ) -> Task<Result<()>> {
16294        let multibuffer = self.buffer.read(cx);
16295        let snapshot = multibuffer.read(cx);
16296        let buffer_ids: HashSet<_> = ranges
16297            .iter()
16298            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16299            .collect();
16300        drop(snapshot);
16301
16302        let mut buffers = HashSet::default();
16303        for buffer_id in buffer_ids {
16304            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16305                let buffer = buffer_entity.read(cx);
16306                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16307                {
16308                    buffers.insert(buffer_entity);
16309                }
16310            }
16311        }
16312
16313        if let Some(project) = &self.project {
16314            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16315        } else {
16316            Task::ready(Ok(()))
16317        }
16318    }
16319
16320    fn do_stage_or_unstage_and_next(
16321        &mut self,
16322        stage: bool,
16323        window: &mut Window,
16324        cx: &mut Context<Self>,
16325    ) {
16326        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16327
16328        if ranges.iter().any(|range| range.start != range.end) {
16329            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16330            return;
16331        }
16332
16333        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16334        let snapshot = self.snapshot(window, cx);
16335        let position = self.selections.newest::<Point>(cx).head();
16336        let mut row = snapshot
16337            .buffer_snapshot
16338            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16339            .find(|hunk| hunk.row_range.start.0 > position.row)
16340            .map(|hunk| hunk.row_range.start);
16341
16342        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16343        // Outside of the project diff editor, wrap around to the beginning.
16344        if !all_diff_hunks_expanded {
16345            row = row.or_else(|| {
16346                snapshot
16347                    .buffer_snapshot
16348                    .diff_hunks_in_range(Point::zero()..position)
16349                    .find(|hunk| hunk.row_range.end.0 < position.row)
16350                    .map(|hunk| hunk.row_range.start)
16351            });
16352        }
16353
16354        if let Some(row) = row {
16355            let destination = Point::new(row.0, 0);
16356            let autoscroll = Autoscroll::center();
16357
16358            self.unfold_ranges(&[destination..destination], false, false, cx);
16359            self.change_selections(Some(autoscroll), window, cx, |s| {
16360                s.select_ranges([destination..destination]);
16361            });
16362        }
16363    }
16364
16365    fn do_stage_or_unstage(
16366        &self,
16367        stage: bool,
16368        buffer_id: BufferId,
16369        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16370        cx: &mut App,
16371    ) -> Option<()> {
16372        let project = self.project.as_ref()?;
16373        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16374        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16375        let buffer_snapshot = buffer.read(cx).snapshot();
16376        let file_exists = buffer_snapshot
16377            .file()
16378            .is_some_and(|file| file.disk_state().exists());
16379        diff.update(cx, |diff, cx| {
16380            diff.stage_or_unstage_hunks(
16381                stage,
16382                &hunks
16383                    .map(|hunk| buffer_diff::DiffHunk {
16384                        buffer_range: hunk.buffer_range,
16385                        diff_base_byte_range: hunk.diff_base_byte_range,
16386                        secondary_status: hunk.secondary_status,
16387                        range: Point::zero()..Point::zero(), // unused
16388                    })
16389                    .collect::<Vec<_>>(),
16390                &buffer_snapshot,
16391                file_exists,
16392                cx,
16393            )
16394        });
16395        None
16396    }
16397
16398    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16399        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16400        self.buffer
16401            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16402    }
16403
16404    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16405        self.buffer.update(cx, |buffer, cx| {
16406            let ranges = vec![Anchor::min()..Anchor::max()];
16407            if !buffer.all_diff_hunks_expanded()
16408                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16409            {
16410                buffer.collapse_diff_hunks(ranges, cx);
16411                true
16412            } else {
16413                false
16414            }
16415        })
16416    }
16417
16418    fn toggle_diff_hunks_in_ranges(
16419        &mut self,
16420        ranges: Vec<Range<Anchor>>,
16421        cx: &mut Context<Editor>,
16422    ) {
16423        self.buffer.update(cx, |buffer, cx| {
16424            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16425            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16426        })
16427    }
16428
16429    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16430        self.buffer.update(cx, |buffer, cx| {
16431            let snapshot = buffer.snapshot(cx);
16432            let excerpt_id = range.end.excerpt_id;
16433            let point_range = range.to_point(&snapshot);
16434            let expand = !buffer.single_hunk_is_expanded(range, cx);
16435            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16436        })
16437    }
16438
16439    pub(crate) fn apply_all_diff_hunks(
16440        &mut self,
16441        _: &ApplyAllDiffHunks,
16442        window: &mut Window,
16443        cx: &mut Context<Self>,
16444    ) {
16445        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16446
16447        let buffers = self.buffer.read(cx).all_buffers();
16448        for branch_buffer in buffers {
16449            branch_buffer.update(cx, |branch_buffer, cx| {
16450                branch_buffer.merge_into_base(Vec::new(), cx);
16451            });
16452        }
16453
16454        if let Some(project) = self.project.clone() {
16455            self.save(true, project, window, cx).detach_and_log_err(cx);
16456        }
16457    }
16458
16459    pub(crate) fn apply_selected_diff_hunks(
16460        &mut self,
16461        _: &ApplyDiffHunk,
16462        window: &mut Window,
16463        cx: &mut Context<Self>,
16464    ) {
16465        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16466        let snapshot = self.snapshot(window, cx);
16467        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16468        let mut ranges_by_buffer = HashMap::default();
16469        self.transact(window, cx, |editor, _window, cx| {
16470            for hunk in hunks {
16471                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16472                    ranges_by_buffer
16473                        .entry(buffer.clone())
16474                        .or_insert_with(Vec::new)
16475                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16476                }
16477            }
16478
16479            for (buffer, ranges) in ranges_by_buffer {
16480                buffer.update(cx, |buffer, cx| {
16481                    buffer.merge_into_base(ranges, cx);
16482                });
16483            }
16484        });
16485
16486        if let Some(project) = self.project.clone() {
16487            self.save(true, project, window, cx).detach_and_log_err(cx);
16488        }
16489    }
16490
16491    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16492        if hovered != self.gutter_hovered {
16493            self.gutter_hovered = hovered;
16494            cx.notify();
16495        }
16496    }
16497
16498    pub fn insert_blocks(
16499        &mut self,
16500        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16501        autoscroll: Option<Autoscroll>,
16502        cx: &mut Context<Self>,
16503    ) -> Vec<CustomBlockId> {
16504        let blocks = self
16505            .display_map
16506            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16507        if let Some(autoscroll) = autoscroll {
16508            self.request_autoscroll(autoscroll, cx);
16509        }
16510        cx.notify();
16511        blocks
16512    }
16513
16514    pub fn resize_blocks(
16515        &mut self,
16516        heights: HashMap<CustomBlockId, u32>,
16517        autoscroll: Option<Autoscroll>,
16518        cx: &mut Context<Self>,
16519    ) {
16520        self.display_map
16521            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16522        if let Some(autoscroll) = autoscroll {
16523            self.request_autoscroll(autoscroll, cx);
16524        }
16525        cx.notify();
16526    }
16527
16528    pub fn replace_blocks(
16529        &mut self,
16530        renderers: HashMap<CustomBlockId, RenderBlock>,
16531        autoscroll: Option<Autoscroll>,
16532        cx: &mut Context<Self>,
16533    ) {
16534        self.display_map
16535            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16536        if let Some(autoscroll) = autoscroll {
16537            self.request_autoscroll(autoscroll, cx);
16538        }
16539        cx.notify();
16540    }
16541
16542    pub fn remove_blocks(
16543        &mut self,
16544        block_ids: HashSet<CustomBlockId>,
16545        autoscroll: Option<Autoscroll>,
16546        cx: &mut Context<Self>,
16547    ) {
16548        self.display_map.update(cx, |display_map, cx| {
16549            display_map.remove_blocks(block_ids, cx)
16550        });
16551        if let Some(autoscroll) = autoscroll {
16552            self.request_autoscroll(autoscroll, cx);
16553        }
16554        cx.notify();
16555    }
16556
16557    pub fn row_for_block(
16558        &self,
16559        block_id: CustomBlockId,
16560        cx: &mut Context<Self>,
16561    ) -> Option<DisplayRow> {
16562        self.display_map
16563            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16564    }
16565
16566    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16567        self.focused_block = Some(focused_block);
16568    }
16569
16570    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16571        self.focused_block.take()
16572    }
16573
16574    pub fn insert_creases(
16575        &mut self,
16576        creases: impl IntoIterator<Item = Crease<Anchor>>,
16577        cx: &mut Context<Self>,
16578    ) -> Vec<CreaseId> {
16579        self.display_map
16580            .update(cx, |map, cx| map.insert_creases(creases, cx))
16581    }
16582
16583    pub fn remove_creases(
16584        &mut self,
16585        ids: impl IntoIterator<Item = CreaseId>,
16586        cx: &mut Context<Self>,
16587    ) -> Vec<(CreaseId, Range<Anchor>)> {
16588        self.display_map
16589            .update(cx, |map, cx| map.remove_creases(ids, cx))
16590    }
16591
16592    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16593        self.display_map
16594            .update(cx, |map, cx| map.snapshot(cx))
16595            .longest_row()
16596    }
16597
16598    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16599        self.display_map
16600            .update(cx, |map, cx| map.snapshot(cx))
16601            .max_point()
16602    }
16603
16604    pub fn text(&self, cx: &App) -> String {
16605        self.buffer.read(cx).read(cx).text()
16606    }
16607
16608    pub fn is_empty(&self, cx: &App) -> bool {
16609        self.buffer.read(cx).read(cx).is_empty()
16610    }
16611
16612    pub fn text_option(&self, cx: &App) -> Option<String> {
16613        let text = self.text(cx);
16614        let text = text.trim();
16615
16616        if text.is_empty() {
16617            return None;
16618        }
16619
16620        Some(text.to_string())
16621    }
16622
16623    pub fn set_text(
16624        &mut self,
16625        text: impl Into<Arc<str>>,
16626        window: &mut Window,
16627        cx: &mut Context<Self>,
16628    ) {
16629        self.transact(window, cx, |this, _, cx| {
16630            this.buffer
16631                .read(cx)
16632                .as_singleton()
16633                .expect("you can only call set_text on editors for singleton buffers")
16634                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16635        });
16636    }
16637
16638    pub fn display_text(&self, cx: &mut App) -> String {
16639        self.display_map
16640            .update(cx, |map, cx| map.snapshot(cx))
16641            .text()
16642    }
16643
16644    fn create_minimap(
16645        &self,
16646        minimap_settings: MinimapSettings,
16647        window: &mut Window,
16648        cx: &mut Context<Self>,
16649    ) -> Option<Entity<Self>> {
16650        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16651            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16652    }
16653
16654    fn initialize_new_minimap(
16655        &self,
16656        minimap_settings: MinimapSettings,
16657        window: &mut Window,
16658        cx: &mut Context<Self>,
16659    ) -> Entity<Self> {
16660        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16661
16662        let mut minimap = Editor::new_internal(
16663            EditorMode::Minimap {
16664                parent: cx.weak_entity(),
16665            },
16666            self.buffer.clone(),
16667            self.project.clone(),
16668            Some(self.display_map.clone()),
16669            window,
16670            cx,
16671        );
16672        minimap.scroll_manager.clone_state(&self.scroll_manager);
16673        minimap.set_text_style_refinement(TextStyleRefinement {
16674            font_size: Some(MINIMAP_FONT_SIZE),
16675            font_weight: Some(MINIMAP_FONT_WEIGHT),
16676            ..Default::default()
16677        });
16678        minimap.update_minimap_configuration(minimap_settings, cx);
16679        cx.new(|_| minimap)
16680    }
16681
16682    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16683        let current_line_highlight = minimap_settings
16684            .current_line_highlight
16685            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16686        self.set_current_line_highlight(Some(current_line_highlight));
16687    }
16688
16689    pub fn minimap(&self) -> Option<&Entity<Self>> {
16690        self.minimap
16691            .as_ref()
16692            .filter(|_| self.minimap_visibility.visible())
16693    }
16694
16695    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16696        let mut wrap_guides = smallvec::smallvec![];
16697
16698        if self.show_wrap_guides == Some(false) {
16699            return wrap_guides;
16700        }
16701
16702        let settings = self.buffer.read(cx).language_settings(cx);
16703        if settings.show_wrap_guides {
16704            match self.soft_wrap_mode(cx) {
16705                SoftWrap::Column(soft_wrap) => {
16706                    wrap_guides.push((soft_wrap as usize, true));
16707                }
16708                SoftWrap::Bounded(soft_wrap) => {
16709                    wrap_guides.push((soft_wrap as usize, true));
16710                }
16711                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16712            }
16713            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16714        }
16715
16716        wrap_guides
16717    }
16718
16719    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16720        let settings = self.buffer.read(cx).language_settings(cx);
16721        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16722        match mode {
16723            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16724                SoftWrap::None
16725            }
16726            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16727            language_settings::SoftWrap::PreferredLineLength => {
16728                SoftWrap::Column(settings.preferred_line_length)
16729            }
16730            language_settings::SoftWrap::Bounded => {
16731                SoftWrap::Bounded(settings.preferred_line_length)
16732            }
16733        }
16734    }
16735
16736    pub fn set_soft_wrap_mode(
16737        &mut self,
16738        mode: language_settings::SoftWrap,
16739
16740        cx: &mut Context<Self>,
16741    ) {
16742        self.soft_wrap_mode_override = Some(mode);
16743        cx.notify();
16744    }
16745
16746    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16747        self.hard_wrap = hard_wrap;
16748        cx.notify();
16749    }
16750
16751    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16752        self.text_style_refinement = Some(style);
16753    }
16754
16755    /// called by the Element so we know what style we were most recently rendered with.
16756    pub(crate) fn set_style(
16757        &mut self,
16758        style: EditorStyle,
16759        window: &mut Window,
16760        cx: &mut Context<Self>,
16761    ) {
16762        // We intentionally do not inform the display map about the minimap style
16763        // so that wrapping is not recalculated and stays consistent for the editor
16764        // and its linked minimap.
16765        if !self.mode.is_minimap() {
16766            let rem_size = window.rem_size();
16767            self.display_map.update(cx, |map, cx| {
16768                map.set_font(
16769                    style.text.font(),
16770                    style.text.font_size.to_pixels(rem_size),
16771                    cx,
16772                )
16773            });
16774        }
16775        self.style = Some(style);
16776    }
16777
16778    pub fn style(&self) -> Option<&EditorStyle> {
16779        self.style.as_ref()
16780    }
16781
16782    // Called by the element. This method is not designed to be called outside of the editor
16783    // element's layout code because it does not notify when rewrapping is computed synchronously.
16784    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16785        self.display_map
16786            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16787    }
16788
16789    pub fn set_soft_wrap(&mut self) {
16790        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16791    }
16792
16793    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16794        if self.soft_wrap_mode_override.is_some() {
16795            self.soft_wrap_mode_override.take();
16796        } else {
16797            let soft_wrap = match self.soft_wrap_mode(cx) {
16798                SoftWrap::GitDiff => return,
16799                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16800                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16801                    language_settings::SoftWrap::None
16802                }
16803            };
16804            self.soft_wrap_mode_override = Some(soft_wrap);
16805        }
16806        cx.notify();
16807    }
16808
16809    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16810        let Some(workspace) = self.workspace() else {
16811            return;
16812        };
16813        let fs = workspace.read(cx).app_state().fs.clone();
16814        let current_show = TabBarSettings::get_global(cx).show;
16815        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16816            setting.show = Some(!current_show);
16817        });
16818    }
16819
16820    pub fn toggle_indent_guides(
16821        &mut self,
16822        _: &ToggleIndentGuides,
16823        _: &mut Window,
16824        cx: &mut Context<Self>,
16825    ) {
16826        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16827            self.buffer
16828                .read(cx)
16829                .language_settings(cx)
16830                .indent_guides
16831                .enabled
16832        });
16833        self.show_indent_guides = Some(!currently_enabled);
16834        cx.notify();
16835    }
16836
16837    fn should_show_indent_guides(&self) -> Option<bool> {
16838        self.show_indent_guides
16839    }
16840
16841    pub fn toggle_line_numbers(
16842        &mut self,
16843        _: &ToggleLineNumbers,
16844        _: &mut Window,
16845        cx: &mut Context<Self>,
16846    ) {
16847        let mut editor_settings = EditorSettings::get_global(cx).clone();
16848        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16849        EditorSettings::override_global(editor_settings, cx);
16850    }
16851
16852    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16853        if let Some(show_line_numbers) = self.show_line_numbers {
16854            return show_line_numbers;
16855        }
16856        EditorSettings::get_global(cx).gutter.line_numbers
16857    }
16858
16859    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16860        self.use_relative_line_numbers
16861            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16862    }
16863
16864    pub fn toggle_relative_line_numbers(
16865        &mut self,
16866        _: &ToggleRelativeLineNumbers,
16867        _: &mut Window,
16868        cx: &mut Context<Self>,
16869    ) {
16870        let is_relative = self.should_use_relative_line_numbers(cx);
16871        self.set_relative_line_number(Some(!is_relative), cx)
16872    }
16873
16874    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16875        self.use_relative_line_numbers = is_relative;
16876        cx.notify();
16877    }
16878
16879    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16880        self.show_gutter = show_gutter;
16881        cx.notify();
16882    }
16883
16884    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16885        self.show_scrollbars = show_scrollbars;
16886        cx.notify();
16887    }
16888
16889    pub fn set_minimap_visibility(
16890        &mut self,
16891        minimap_visibility: MinimapVisibility,
16892        window: &mut Window,
16893        cx: &mut Context<Self>,
16894    ) {
16895        if self.minimap_visibility != minimap_visibility {
16896            if minimap_visibility.visible() && self.minimap.is_none() {
16897                let minimap_settings = EditorSettings::get_global(cx).minimap;
16898                self.minimap =
16899                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16900            }
16901            self.minimap_visibility = minimap_visibility;
16902            cx.notify();
16903        }
16904    }
16905
16906    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16907        self.set_show_scrollbars(false, cx);
16908        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16909    }
16910
16911    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16912        self.show_line_numbers = Some(show_line_numbers);
16913        cx.notify();
16914    }
16915
16916    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16917        self.disable_expand_excerpt_buttons = true;
16918        cx.notify();
16919    }
16920
16921    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16922        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16923        cx.notify();
16924    }
16925
16926    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16927        self.show_code_actions = Some(show_code_actions);
16928        cx.notify();
16929    }
16930
16931    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16932        self.show_runnables = Some(show_runnables);
16933        cx.notify();
16934    }
16935
16936    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16937        self.show_breakpoints = Some(show_breakpoints);
16938        cx.notify();
16939    }
16940
16941    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16942        if self.display_map.read(cx).masked != masked {
16943            self.display_map.update(cx, |map, _| map.masked = masked);
16944        }
16945        cx.notify()
16946    }
16947
16948    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16949        self.show_wrap_guides = Some(show_wrap_guides);
16950        cx.notify();
16951    }
16952
16953    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16954        self.show_indent_guides = Some(show_indent_guides);
16955        cx.notify();
16956    }
16957
16958    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16959        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16960            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16961                if let Some(dir) = file.abs_path(cx).parent() {
16962                    return Some(dir.to_owned());
16963                }
16964            }
16965
16966            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16967                return Some(project_path.path.to_path_buf());
16968            }
16969        }
16970
16971        None
16972    }
16973
16974    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16975        self.active_excerpt(cx)?
16976            .1
16977            .read(cx)
16978            .file()
16979            .and_then(|f| f.as_local())
16980    }
16981
16982    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16983        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16984            let buffer = buffer.read(cx);
16985            if let Some(project_path) = buffer.project_path(cx) {
16986                let project = self.project.as_ref()?.read(cx);
16987                project.absolute_path(&project_path, cx)
16988            } else {
16989                buffer
16990                    .file()
16991                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16992            }
16993        })
16994    }
16995
16996    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16997        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16998            let project_path = buffer.read(cx).project_path(cx)?;
16999            let project = self.project.as_ref()?.read(cx);
17000            let entry = project.entry_for_path(&project_path, cx)?;
17001            let path = entry.path.to_path_buf();
17002            Some(path)
17003        })
17004    }
17005
17006    pub fn reveal_in_finder(
17007        &mut self,
17008        _: &RevealInFileManager,
17009        _window: &mut Window,
17010        cx: &mut Context<Self>,
17011    ) {
17012        if let Some(target) = self.target_file(cx) {
17013            cx.reveal_path(&target.abs_path(cx));
17014        }
17015    }
17016
17017    pub fn copy_path(
17018        &mut self,
17019        _: &zed_actions::workspace::CopyPath,
17020        _window: &mut Window,
17021        cx: &mut Context<Self>,
17022    ) {
17023        if let Some(path) = self.target_file_abs_path(cx) {
17024            if let Some(path) = path.to_str() {
17025                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17026            }
17027        }
17028    }
17029
17030    pub fn copy_relative_path(
17031        &mut self,
17032        _: &zed_actions::workspace::CopyRelativePath,
17033        _window: &mut Window,
17034        cx: &mut Context<Self>,
17035    ) {
17036        if let Some(path) = self.target_file_path(cx) {
17037            if let Some(path) = path.to_str() {
17038                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17039            }
17040        }
17041    }
17042
17043    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17044        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17045            buffer.read(cx).project_path(cx)
17046        } else {
17047            None
17048        }
17049    }
17050
17051    // Returns true if the editor handled a go-to-line request
17052    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17053        maybe!({
17054            let breakpoint_store = self.breakpoint_store.as_ref()?;
17055
17056            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17057            else {
17058                self.clear_row_highlights::<ActiveDebugLine>();
17059                return None;
17060            };
17061
17062            let position = active_stack_frame.position;
17063            let buffer_id = position.buffer_id?;
17064            let snapshot = self
17065                .project
17066                .as_ref()?
17067                .read(cx)
17068                .buffer_for_id(buffer_id, cx)?
17069                .read(cx)
17070                .snapshot();
17071
17072            let mut handled = false;
17073            for (id, ExcerptRange { context, .. }) in
17074                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17075            {
17076                if context.start.cmp(&position, &snapshot).is_ge()
17077                    || context.end.cmp(&position, &snapshot).is_lt()
17078                {
17079                    continue;
17080                }
17081                let snapshot = self.buffer.read(cx).snapshot(cx);
17082                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17083
17084                handled = true;
17085                self.clear_row_highlights::<ActiveDebugLine>();
17086
17087                self.go_to_line::<ActiveDebugLine>(
17088                    multibuffer_anchor,
17089                    Some(cx.theme().colors().editor_debugger_active_line_background),
17090                    window,
17091                    cx,
17092                );
17093
17094                cx.notify();
17095            }
17096
17097            handled.then_some(())
17098        })
17099        .is_some()
17100    }
17101
17102    pub fn copy_file_name_without_extension(
17103        &mut self,
17104        _: &CopyFileNameWithoutExtension,
17105        _: &mut Window,
17106        cx: &mut Context<Self>,
17107    ) {
17108        if let Some(file) = self.target_file(cx) {
17109            if let Some(file_stem) = file.path().file_stem() {
17110                if let Some(name) = file_stem.to_str() {
17111                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17112                }
17113            }
17114        }
17115    }
17116
17117    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17118        if let Some(file) = self.target_file(cx) {
17119            if let Some(file_name) = file.path().file_name() {
17120                if let Some(name) = file_name.to_str() {
17121                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17122                }
17123            }
17124        }
17125    }
17126
17127    pub fn toggle_git_blame(
17128        &mut self,
17129        _: &::git::Blame,
17130        window: &mut Window,
17131        cx: &mut Context<Self>,
17132    ) {
17133        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17134
17135        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17136            self.start_git_blame(true, window, cx);
17137        }
17138
17139        cx.notify();
17140    }
17141
17142    pub fn toggle_git_blame_inline(
17143        &mut self,
17144        _: &ToggleGitBlameInline,
17145        window: &mut Window,
17146        cx: &mut Context<Self>,
17147    ) {
17148        self.toggle_git_blame_inline_internal(true, window, cx);
17149        cx.notify();
17150    }
17151
17152    pub fn open_git_blame_commit(
17153        &mut self,
17154        _: &OpenGitBlameCommit,
17155        window: &mut Window,
17156        cx: &mut Context<Self>,
17157    ) {
17158        self.open_git_blame_commit_internal(window, cx);
17159    }
17160
17161    fn open_git_blame_commit_internal(
17162        &mut self,
17163        window: &mut Window,
17164        cx: &mut Context<Self>,
17165    ) -> Option<()> {
17166        let blame = self.blame.as_ref()?;
17167        let snapshot = self.snapshot(window, cx);
17168        let cursor = self.selections.newest::<Point>(cx).head();
17169        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17170        let blame_entry = blame
17171            .update(cx, |blame, cx| {
17172                blame
17173                    .blame_for_rows(
17174                        &[RowInfo {
17175                            buffer_id: Some(buffer.remote_id()),
17176                            buffer_row: Some(point.row),
17177                            ..Default::default()
17178                        }],
17179                        cx,
17180                    )
17181                    .next()
17182            })
17183            .flatten()?;
17184        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17185        let repo = blame.read(cx).repository(cx)?;
17186        let workspace = self.workspace()?.downgrade();
17187        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17188        None
17189    }
17190
17191    pub fn git_blame_inline_enabled(&self) -> bool {
17192        self.git_blame_inline_enabled
17193    }
17194
17195    pub fn toggle_selection_menu(
17196        &mut self,
17197        _: &ToggleSelectionMenu,
17198        _: &mut Window,
17199        cx: &mut Context<Self>,
17200    ) {
17201        self.show_selection_menu = self
17202            .show_selection_menu
17203            .map(|show_selections_menu| !show_selections_menu)
17204            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17205
17206        cx.notify();
17207    }
17208
17209    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17210        self.show_selection_menu
17211            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17212    }
17213
17214    fn start_git_blame(
17215        &mut self,
17216        user_triggered: bool,
17217        window: &mut Window,
17218        cx: &mut Context<Self>,
17219    ) {
17220        if let Some(project) = self.project.as_ref() {
17221            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17222                return;
17223            };
17224
17225            if buffer.read(cx).file().is_none() {
17226                return;
17227            }
17228
17229            let focused = self.focus_handle(cx).contains_focused(window, cx);
17230
17231            let project = project.clone();
17232            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17233            self.blame_subscription =
17234                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17235            self.blame = Some(blame);
17236        }
17237    }
17238
17239    fn toggle_git_blame_inline_internal(
17240        &mut self,
17241        user_triggered: bool,
17242        window: &mut Window,
17243        cx: &mut Context<Self>,
17244    ) {
17245        if self.git_blame_inline_enabled {
17246            self.git_blame_inline_enabled = false;
17247            self.show_git_blame_inline = false;
17248            self.show_git_blame_inline_delay_task.take();
17249        } else {
17250            self.git_blame_inline_enabled = true;
17251            self.start_git_blame_inline(user_triggered, window, cx);
17252        }
17253
17254        cx.notify();
17255    }
17256
17257    fn start_git_blame_inline(
17258        &mut self,
17259        user_triggered: bool,
17260        window: &mut Window,
17261        cx: &mut Context<Self>,
17262    ) {
17263        self.start_git_blame(user_triggered, window, cx);
17264
17265        if ProjectSettings::get_global(cx)
17266            .git
17267            .inline_blame_delay()
17268            .is_some()
17269        {
17270            self.start_inline_blame_timer(window, cx);
17271        } else {
17272            self.show_git_blame_inline = true
17273        }
17274    }
17275
17276    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17277        self.blame.as_ref()
17278    }
17279
17280    pub fn show_git_blame_gutter(&self) -> bool {
17281        self.show_git_blame_gutter
17282    }
17283
17284    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17285        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17286    }
17287
17288    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17289        self.show_git_blame_inline
17290            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17291            && !self.newest_selection_head_on_empty_line(cx)
17292            && self.has_blame_entries(cx)
17293    }
17294
17295    fn has_blame_entries(&self, cx: &App) -> bool {
17296        self.blame()
17297            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17298    }
17299
17300    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17301        let cursor_anchor = self.selections.newest_anchor().head();
17302
17303        let snapshot = self.buffer.read(cx).snapshot(cx);
17304        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17305
17306        snapshot.line_len(buffer_row) == 0
17307    }
17308
17309    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17310        let buffer_and_selection = maybe!({
17311            let selection = self.selections.newest::<Point>(cx);
17312            let selection_range = selection.range();
17313
17314            let multi_buffer = self.buffer().read(cx);
17315            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17316            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17317
17318            let (buffer, range, _) = if selection.reversed {
17319                buffer_ranges.first()
17320            } else {
17321                buffer_ranges.last()
17322            }?;
17323
17324            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17325                ..text::ToPoint::to_point(&range.end, &buffer).row;
17326            Some((
17327                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17328                selection,
17329            ))
17330        });
17331
17332        let Some((buffer, selection)) = buffer_and_selection else {
17333            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17334        };
17335
17336        let Some(project) = self.project.as_ref() else {
17337            return Task::ready(Err(anyhow!("editor does not have project")));
17338        };
17339
17340        project.update(cx, |project, cx| {
17341            project.get_permalink_to_line(&buffer, selection, cx)
17342        })
17343    }
17344
17345    pub fn copy_permalink_to_line(
17346        &mut self,
17347        _: &CopyPermalinkToLine,
17348        window: &mut Window,
17349        cx: &mut Context<Self>,
17350    ) {
17351        let permalink_task = self.get_permalink_to_line(cx);
17352        let workspace = self.workspace();
17353
17354        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17355            Ok(permalink) => {
17356                cx.update(|_, cx| {
17357                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17358                })
17359                .ok();
17360            }
17361            Err(err) => {
17362                let message = format!("Failed to copy permalink: {err}");
17363
17364                anyhow::Result::<()>::Err(err).log_err();
17365
17366                if let Some(workspace) = workspace {
17367                    workspace
17368                        .update_in(cx, |workspace, _, cx| {
17369                            struct CopyPermalinkToLine;
17370
17371                            workspace.show_toast(
17372                                Toast::new(
17373                                    NotificationId::unique::<CopyPermalinkToLine>(),
17374                                    message,
17375                                ),
17376                                cx,
17377                            )
17378                        })
17379                        .ok();
17380                }
17381            }
17382        })
17383        .detach();
17384    }
17385
17386    pub fn copy_file_location(
17387        &mut self,
17388        _: &CopyFileLocation,
17389        _: &mut Window,
17390        cx: &mut Context<Self>,
17391    ) {
17392        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17393        if let Some(file) = self.target_file(cx) {
17394            if let Some(path) = file.path().to_str() {
17395                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17396            }
17397        }
17398    }
17399
17400    pub fn open_permalink_to_line(
17401        &mut self,
17402        _: &OpenPermalinkToLine,
17403        window: &mut Window,
17404        cx: &mut Context<Self>,
17405    ) {
17406        let permalink_task = self.get_permalink_to_line(cx);
17407        let workspace = self.workspace();
17408
17409        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17410            Ok(permalink) => {
17411                cx.update(|_, cx| {
17412                    cx.open_url(permalink.as_ref());
17413                })
17414                .ok();
17415            }
17416            Err(err) => {
17417                let message = format!("Failed to open permalink: {err}");
17418
17419                anyhow::Result::<()>::Err(err).log_err();
17420
17421                if let Some(workspace) = workspace {
17422                    workspace
17423                        .update(cx, |workspace, cx| {
17424                            struct OpenPermalinkToLine;
17425
17426                            workspace.show_toast(
17427                                Toast::new(
17428                                    NotificationId::unique::<OpenPermalinkToLine>(),
17429                                    message,
17430                                ),
17431                                cx,
17432                            )
17433                        })
17434                        .ok();
17435                }
17436            }
17437        })
17438        .detach();
17439    }
17440
17441    pub fn insert_uuid_v4(
17442        &mut self,
17443        _: &InsertUuidV4,
17444        window: &mut Window,
17445        cx: &mut Context<Self>,
17446    ) {
17447        self.insert_uuid(UuidVersion::V4, window, cx);
17448    }
17449
17450    pub fn insert_uuid_v7(
17451        &mut self,
17452        _: &InsertUuidV7,
17453        window: &mut Window,
17454        cx: &mut Context<Self>,
17455    ) {
17456        self.insert_uuid(UuidVersion::V7, window, cx);
17457    }
17458
17459    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17460        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17461        self.transact(window, cx, |this, window, cx| {
17462            let edits = this
17463                .selections
17464                .all::<Point>(cx)
17465                .into_iter()
17466                .map(|selection| {
17467                    let uuid = match version {
17468                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17469                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17470                    };
17471
17472                    (selection.range(), uuid.to_string())
17473                });
17474            this.edit(edits, cx);
17475            this.refresh_inline_completion(true, false, window, cx);
17476        });
17477    }
17478
17479    pub fn open_selections_in_multibuffer(
17480        &mut self,
17481        _: &OpenSelectionsInMultibuffer,
17482        window: &mut Window,
17483        cx: &mut Context<Self>,
17484    ) {
17485        let multibuffer = self.buffer.read(cx);
17486
17487        let Some(buffer) = multibuffer.as_singleton() else {
17488            return;
17489        };
17490
17491        let Some(workspace) = self.workspace() else {
17492            return;
17493        };
17494
17495        let locations = self
17496            .selections
17497            .disjoint_anchors()
17498            .iter()
17499            .map(|range| Location {
17500                buffer: buffer.clone(),
17501                range: range.start.text_anchor..range.end.text_anchor,
17502            })
17503            .collect::<Vec<_>>();
17504
17505        let title = multibuffer.title(cx).to_string();
17506
17507        cx.spawn_in(window, async move |_, cx| {
17508            workspace.update_in(cx, |workspace, window, cx| {
17509                Self::open_locations_in_multibuffer(
17510                    workspace,
17511                    locations,
17512                    format!("Selections for '{title}'"),
17513                    false,
17514                    MultibufferSelectionMode::All,
17515                    window,
17516                    cx,
17517                );
17518            })
17519        })
17520        .detach();
17521    }
17522
17523    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17524    /// last highlight added will be used.
17525    ///
17526    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17527    pub fn highlight_rows<T: 'static>(
17528        &mut self,
17529        range: Range<Anchor>,
17530        color: Hsla,
17531        options: RowHighlightOptions,
17532        cx: &mut Context<Self>,
17533    ) {
17534        let snapshot = self.buffer().read(cx).snapshot(cx);
17535        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17536        let ix = row_highlights.binary_search_by(|highlight| {
17537            Ordering::Equal
17538                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17539                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17540        });
17541
17542        if let Err(mut ix) = ix {
17543            let index = post_inc(&mut self.highlight_order);
17544
17545            // If this range intersects with the preceding highlight, then merge it with
17546            // the preceding highlight. Otherwise insert a new highlight.
17547            let mut merged = false;
17548            if ix > 0 {
17549                let prev_highlight = &mut row_highlights[ix - 1];
17550                if prev_highlight
17551                    .range
17552                    .end
17553                    .cmp(&range.start, &snapshot)
17554                    .is_ge()
17555                {
17556                    ix -= 1;
17557                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17558                        prev_highlight.range.end = range.end;
17559                    }
17560                    merged = true;
17561                    prev_highlight.index = index;
17562                    prev_highlight.color = color;
17563                    prev_highlight.options = options;
17564                }
17565            }
17566
17567            if !merged {
17568                row_highlights.insert(
17569                    ix,
17570                    RowHighlight {
17571                        range: range.clone(),
17572                        index,
17573                        color,
17574                        options,
17575                        type_id: TypeId::of::<T>(),
17576                    },
17577                );
17578            }
17579
17580            // If any of the following highlights intersect with this one, merge them.
17581            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17582                let highlight = &row_highlights[ix];
17583                if next_highlight
17584                    .range
17585                    .start
17586                    .cmp(&highlight.range.end, &snapshot)
17587                    .is_le()
17588                {
17589                    if next_highlight
17590                        .range
17591                        .end
17592                        .cmp(&highlight.range.end, &snapshot)
17593                        .is_gt()
17594                    {
17595                        row_highlights[ix].range.end = next_highlight.range.end;
17596                    }
17597                    row_highlights.remove(ix + 1);
17598                } else {
17599                    break;
17600                }
17601            }
17602        }
17603    }
17604
17605    /// Remove any highlighted row ranges of the given type that intersect the
17606    /// given ranges.
17607    pub fn remove_highlighted_rows<T: 'static>(
17608        &mut self,
17609        ranges_to_remove: Vec<Range<Anchor>>,
17610        cx: &mut Context<Self>,
17611    ) {
17612        let snapshot = self.buffer().read(cx).snapshot(cx);
17613        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17614        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17615        row_highlights.retain(|highlight| {
17616            while let Some(range_to_remove) = ranges_to_remove.peek() {
17617                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17618                    Ordering::Less | Ordering::Equal => {
17619                        ranges_to_remove.next();
17620                    }
17621                    Ordering::Greater => {
17622                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17623                            Ordering::Less | Ordering::Equal => {
17624                                return false;
17625                            }
17626                            Ordering::Greater => break,
17627                        }
17628                    }
17629                }
17630            }
17631
17632            true
17633        })
17634    }
17635
17636    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17637    pub fn clear_row_highlights<T: 'static>(&mut self) {
17638        self.highlighted_rows.remove(&TypeId::of::<T>());
17639    }
17640
17641    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17642    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17643        self.highlighted_rows
17644            .get(&TypeId::of::<T>())
17645            .map_or(&[] as &[_], |vec| vec.as_slice())
17646            .iter()
17647            .map(|highlight| (highlight.range.clone(), highlight.color))
17648    }
17649
17650    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17651    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17652    /// Allows to ignore certain kinds of highlights.
17653    pub fn highlighted_display_rows(
17654        &self,
17655        window: &mut Window,
17656        cx: &mut App,
17657    ) -> BTreeMap<DisplayRow, LineHighlight> {
17658        let snapshot = self.snapshot(window, cx);
17659        let mut used_highlight_orders = HashMap::default();
17660        self.highlighted_rows
17661            .iter()
17662            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17663            .fold(
17664                BTreeMap::<DisplayRow, LineHighlight>::new(),
17665                |mut unique_rows, highlight| {
17666                    let start = highlight.range.start.to_display_point(&snapshot);
17667                    let end = highlight.range.end.to_display_point(&snapshot);
17668                    let start_row = start.row().0;
17669                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17670                        && end.column() == 0
17671                    {
17672                        end.row().0.saturating_sub(1)
17673                    } else {
17674                        end.row().0
17675                    };
17676                    for row in start_row..=end_row {
17677                        let used_index =
17678                            used_highlight_orders.entry(row).or_insert(highlight.index);
17679                        if highlight.index >= *used_index {
17680                            *used_index = highlight.index;
17681                            unique_rows.insert(
17682                                DisplayRow(row),
17683                                LineHighlight {
17684                                    include_gutter: highlight.options.include_gutter,
17685                                    border: None,
17686                                    background: highlight.color.into(),
17687                                    type_id: Some(highlight.type_id),
17688                                },
17689                            );
17690                        }
17691                    }
17692                    unique_rows
17693                },
17694            )
17695    }
17696
17697    pub fn highlighted_display_row_for_autoscroll(
17698        &self,
17699        snapshot: &DisplaySnapshot,
17700    ) -> Option<DisplayRow> {
17701        self.highlighted_rows
17702            .values()
17703            .flat_map(|highlighted_rows| highlighted_rows.iter())
17704            .filter_map(|highlight| {
17705                if highlight.options.autoscroll {
17706                    Some(highlight.range.start.to_display_point(snapshot).row())
17707                } else {
17708                    None
17709                }
17710            })
17711            .min()
17712    }
17713
17714    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17715        self.highlight_background::<SearchWithinRange>(
17716            ranges,
17717            |colors| colors.editor_document_highlight_read_background,
17718            cx,
17719        )
17720    }
17721
17722    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17723        self.breadcrumb_header = Some(new_header);
17724    }
17725
17726    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17727        self.clear_background_highlights::<SearchWithinRange>(cx);
17728    }
17729
17730    pub fn highlight_background<T: 'static>(
17731        &mut self,
17732        ranges: &[Range<Anchor>],
17733        color_fetcher: fn(&ThemeColors) -> Hsla,
17734        cx: &mut Context<Self>,
17735    ) {
17736        self.background_highlights
17737            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17738        self.scrollbar_marker_state.dirty = true;
17739        cx.notify();
17740    }
17741
17742    pub fn clear_background_highlights<T: 'static>(
17743        &mut self,
17744        cx: &mut Context<Self>,
17745    ) -> Option<BackgroundHighlight> {
17746        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17747        if !text_highlights.1.is_empty() {
17748            self.scrollbar_marker_state.dirty = true;
17749            cx.notify();
17750        }
17751        Some(text_highlights)
17752    }
17753
17754    pub fn highlight_gutter<T: 'static>(
17755        &mut self,
17756        ranges: &[Range<Anchor>],
17757        color_fetcher: fn(&App) -> Hsla,
17758        cx: &mut Context<Self>,
17759    ) {
17760        self.gutter_highlights
17761            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17762        cx.notify();
17763    }
17764
17765    pub fn clear_gutter_highlights<T: 'static>(
17766        &mut self,
17767        cx: &mut Context<Self>,
17768    ) -> Option<GutterHighlight> {
17769        cx.notify();
17770        self.gutter_highlights.remove(&TypeId::of::<T>())
17771    }
17772
17773    #[cfg(feature = "test-support")]
17774    pub fn all_text_background_highlights(
17775        &self,
17776        window: &mut Window,
17777        cx: &mut Context<Self>,
17778    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17779        let snapshot = self.snapshot(window, cx);
17780        let buffer = &snapshot.buffer_snapshot;
17781        let start = buffer.anchor_before(0);
17782        let end = buffer.anchor_after(buffer.len());
17783        let theme = cx.theme().colors();
17784        self.background_highlights_in_range(start..end, &snapshot, theme)
17785    }
17786
17787    #[cfg(feature = "test-support")]
17788    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17789        let snapshot = self.buffer().read(cx).snapshot(cx);
17790
17791        let highlights = self
17792            .background_highlights
17793            .get(&TypeId::of::<items::BufferSearchHighlights>());
17794
17795        if let Some((_color, ranges)) = highlights {
17796            ranges
17797                .iter()
17798                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17799                .collect_vec()
17800        } else {
17801            vec![]
17802        }
17803    }
17804
17805    fn document_highlights_for_position<'a>(
17806        &'a self,
17807        position: Anchor,
17808        buffer: &'a MultiBufferSnapshot,
17809    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17810        let read_highlights = self
17811            .background_highlights
17812            .get(&TypeId::of::<DocumentHighlightRead>())
17813            .map(|h| &h.1);
17814        let write_highlights = self
17815            .background_highlights
17816            .get(&TypeId::of::<DocumentHighlightWrite>())
17817            .map(|h| &h.1);
17818        let left_position = position.bias_left(buffer);
17819        let right_position = position.bias_right(buffer);
17820        read_highlights
17821            .into_iter()
17822            .chain(write_highlights)
17823            .flat_map(move |ranges| {
17824                let start_ix = match ranges.binary_search_by(|probe| {
17825                    let cmp = probe.end.cmp(&left_position, buffer);
17826                    if cmp.is_ge() {
17827                        Ordering::Greater
17828                    } else {
17829                        Ordering::Less
17830                    }
17831                }) {
17832                    Ok(i) | Err(i) => i,
17833                };
17834
17835                ranges[start_ix..]
17836                    .iter()
17837                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17838            })
17839    }
17840
17841    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17842        self.background_highlights
17843            .get(&TypeId::of::<T>())
17844            .map_or(false, |(_, highlights)| !highlights.is_empty())
17845    }
17846
17847    pub fn background_highlights_in_range(
17848        &self,
17849        search_range: Range<Anchor>,
17850        display_snapshot: &DisplaySnapshot,
17851        theme: &ThemeColors,
17852    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17853        let mut results = Vec::new();
17854        for (color_fetcher, ranges) in self.background_highlights.values() {
17855            let color = color_fetcher(theme);
17856            let start_ix = match ranges.binary_search_by(|probe| {
17857                let cmp = probe
17858                    .end
17859                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17860                if cmp.is_gt() {
17861                    Ordering::Greater
17862                } else {
17863                    Ordering::Less
17864                }
17865            }) {
17866                Ok(i) | Err(i) => i,
17867            };
17868            for range in &ranges[start_ix..] {
17869                if range
17870                    .start
17871                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17872                    .is_ge()
17873                {
17874                    break;
17875                }
17876
17877                let start = range.start.to_display_point(display_snapshot);
17878                let end = range.end.to_display_point(display_snapshot);
17879                results.push((start..end, color))
17880            }
17881        }
17882        results
17883    }
17884
17885    pub fn background_highlight_row_ranges<T: 'static>(
17886        &self,
17887        search_range: Range<Anchor>,
17888        display_snapshot: &DisplaySnapshot,
17889        count: usize,
17890    ) -> Vec<RangeInclusive<DisplayPoint>> {
17891        let mut results = Vec::new();
17892        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17893            return vec![];
17894        };
17895
17896        let start_ix = match ranges.binary_search_by(|probe| {
17897            let cmp = probe
17898                .end
17899                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17900            if cmp.is_gt() {
17901                Ordering::Greater
17902            } else {
17903                Ordering::Less
17904            }
17905        }) {
17906            Ok(i) | Err(i) => i,
17907        };
17908        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17909            if let (Some(start_display), Some(end_display)) = (start, end) {
17910                results.push(
17911                    start_display.to_display_point(display_snapshot)
17912                        ..=end_display.to_display_point(display_snapshot),
17913                );
17914            }
17915        };
17916        let mut start_row: Option<Point> = None;
17917        let mut end_row: Option<Point> = None;
17918        if ranges.len() > count {
17919            return Vec::new();
17920        }
17921        for range in &ranges[start_ix..] {
17922            if range
17923                .start
17924                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17925                .is_ge()
17926            {
17927                break;
17928            }
17929            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17930            if let Some(current_row) = &end_row {
17931                if end.row == current_row.row {
17932                    continue;
17933                }
17934            }
17935            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17936            if start_row.is_none() {
17937                assert_eq!(end_row, None);
17938                start_row = Some(start);
17939                end_row = Some(end);
17940                continue;
17941            }
17942            if let Some(current_end) = end_row.as_mut() {
17943                if start.row > current_end.row + 1 {
17944                    push_region(start_row, end_row);
17945                    start_row = Some(start);
17946                    end_row = Some(end);
17947                } else {
17948                    // Merge two hunks.
17949                    *current_end = end;
17950                }
17951            } else {
17952                unreachable!();
17953            }
17954        }
17955        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17956        push_region(start_row, end_row);
17957        results
17958    }
17959
17960    pub fn gutter_highlights_in_range(
17961        &self,
17962        search_range: Range<Anchor>,
17963        display_snapshot: &DisplaySnapshot,
17964        cx: &App,
17965    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17966        let mut results = Vec::new();
17967        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17968            let color = color_fetcher(cx);
17969            let start_ix = match ranges.binary_search_by(|probe| {
17970                let cmp = probe
17971                    .end
17972                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17973                if cmp.is_gt() {
17974                    Ordering::Greater
17975                } else {
17976                    Ordering::Less
17977                }
17978            }) {
17979                Ok(i) | Err(i) => i,
17980            };
17981            for range in &ranges[start_ix..] {
17982                if range
17983                    .start
17984                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17985                    .is_ge()
17986                {
17987                    break;
17988                }
17989
17990                let start = range.start.to_display_point(display_snapshot);
17991                let end = range.end.to_display_point(display_snapshot);
17992                results.push((start..end, color))
17993            }
17994        }
17995        results
17996    }
17997
17998    /// Get the text ranges corresponding to the redaction query
17999    pub fn redacted_ranges(
18000        &self,
18001        search_range: Range<Anchor>,
18002        display_snapshot: &DisplaySnapshot,
18003        cx: &App,
18004    ) -> Vec<Range<DisplayPoint>> {
18005        display_snapshot
18006            .buffer_snapshot
18007            .redacted_ranges(search_range, |file| {
18008                if let Some(file) = file {
18009                    file.is_private()
18010                        && EditorSettings::get(
18011                            Some(SettingsLocation {
18012                                worktree_id: file.worktree_id(cx),
18013                                path: file.path().as_ref(),
18014                            }),
18015                            cx,
18016                        )
18017                        .redact_private_values
18018                } else {
18019                    false
18020                }
18021            })
18022            .map(|range| {
18023                range.start.to_display_point(display_snapshot)
18024                    ..range.end.to_display_point(display_snapshot)
18025            })
18026            .collect()
18027    }
18028
18029    pub fn highlight_text<T: 'static>(
18030        &mut self,
18031        ranges: Vec<Range<Anchor>>,
18032        style: HighlightStyle,
18033        cx: &mut Context<Self>,
18034    ) {
18035        self.display_map.update(cx, |map, _| {
18036            map.highlight_text(TypeId::of::<T>(), ranges, style)
18037        });
18038        cx.notify();
18039    }
18040
18041    pub(crate) fn highlight_inlays<T: 'static>(
18042        &mut self,
18043        highlights: Vec<InlayHighlight>,
18044        style: HighlightStyle,
18045        cx: &mut Context<Self>,
18046    ) {
18047        self.display_map.update(cx, |map, _| {
18048            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18049        });
18050        cx.notify();
18051    }
18052
18053    pub fn text_highlights<'a, T: 'static>(
18054        &'a self,
18055        cx: &'a App,
18056    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18057        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18058    }
18059
18060    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18061        let cleared = self
18062            .display_map
18063            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18064        if cleared {
18065            cx.notify();
18066        }
18067    }
18068
18069    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18070        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18071            && self.focus_handle.is_focused(window)
18072    }
18073
18074    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18075        self.show_cursor_when_unfocused = is_enabled;
18076        cx.notify();
18077    }
18078
18079    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18080        cx.notify();
18081    }
18082
18083    fn on_debug_session_event(
18084        &mut self,
18085        _session: Entity<Session>,
18086        event: &SessionEvent,
18087        cx: &mut Context<Self>,
18088    ) {
18089        match event {
18090            SessionEvent::InvalidateInlineValue => {
18091                self.refresh_inline_values(cx);
18092            }
18093            _ => {}
18094        }
18095    }
18096
18097    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18098        let Some(project) = self.project.clone() else {
18099            return;
18100        };
18101
18102        if !self.inline_value_cache.enabled {
18103            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18104            self.splice_inlays(&inlays, Vec::new(), cx);
18105            return;
18106        }
18107
18108        let current_execution_position = self
18109            .highlighted_rows
18110            .get(&TypeId::of::<ActiveDebugLine>())
18111            .and_then(|lines| lines.last().map(|line| line.range.start));
18112
18113        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18114            let inline_values = editor
18115                .update(cx, |editor, cx| {
18116                    let Some(current_execution_position) = current_execution_position else {
18117                        return Some(Task::ready(Ok(Vec::new())));
18118                    };
18119
18120                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18121                        let snapshot = buffer.snapshot(cx);
18122
18123                        let excerpt = snapshot.excerpt_containing(
18124                            current_execution_position..current_execution_position,
18125                        )?;
18126
18127                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18128                    })?;
18129
18130                    let range =
18131                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18132
18133                    project.inline_values(buffer, range, cx)
18134                })
18135                .ok()
18136                .flatten()?
18137                .await
18138                .context("refreshing debugger inlays")
18139                .log_err()?;
18140
18141            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18142
18143            for (buffer_id, inline_value) in inline_values
18144                .into_iter()
18145                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18146            {
18147                buffer_inline_values
18148                    .entry(buffer_id)
18149                    .or_default()
18150                    .push(inline_value);
18151            }
18152
18153            editor
18154                .update(cx, |editor, cx| {
18155                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18156                    let mut new_inlays = Vec::default();
18157
18158                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18159                        let buffer_id = buffer_snapshot.remote_id();
18160                        buffer_inline_values
18161                            .get(&buffer_id)
18162                            .into_iter()
18163                            .flatten()
18164                            .for_each(|hint| {
18165                                let inlay = Inlay::debugger_hint(
18166                                    post_inc(&mut editor.next_inlay_id),
18167                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18168                                    hint.text(),
18169                                );
18170
18171                                new_inlays.push(inlay);
18172                            });
18173                    }
18174
18175                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18176                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18177
18178                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18179                })
18180                .ok()?;
18181            Some(())
18182        });
18183    }
18184
18185    fn on_buffer_event(
18186        &mut self,
18187        multibuffer: &Entity<MultiBuffer>,
18188        event: &multi_buffer::Event,
18189        window: &mut Window,
18190        cx: &mut Context<Self>,
18191    ) {
18192        match event {
18193            multi_buffer::Event::Edited {
18194                singleton_buffer_edited,
18195                edited_buffer: buffer_edited,
18196            } => {
18197                self.scrollbar_marker_state.dirty = true;
18198                self.active_indent_guides_state.dirty = true;
18199                self.refresh_active_diagnostics(cx);
18200                self.refresh_code_actions(window, cx);
18201                self.refresh_selected_text_highlights(true, window, cx);
18202                refresh_matching_bracket_highlights(self, window, cx);
18203                if self.has_active_inline_completion() {
18204                    self.update_visible_inline_completion(window, cx);
18205                }
18206                if let Some(buffer) = buffer_edited {
18207                    let buffer_id = buffer.read(cx).remote_id();
18208                    if !self.registered_buffers.contains_key(&buffer_id) {
18209                        if let Some(project) = self.project.as_ref() {
18210                            project.update(cx, |project, cx| {
18211                                self.registered_buffers.insert(
18212                                    buffer_id,
18213                                    project.register_buffer_with_language_servers(&buffer, cx),
18214                                );
18215                            })
18216                        }
18217                    }
18218                }
18219                cx.emit(EditorEvent::BufferEdited);
18220                cx.emit(SearchEvent::MatchesInvalidated);
18221                if *singleton_buffer_edited {
18222                    if let Some(project) = &self.project {
18223                        #[allow(clippy::mutable_key_type)]
18224                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18225                            multibuffer
18226                                .all_buffers()
18227                                .into_iter()
18228                                .filter_map(|buffer| {
18229                                    buffer.update(cx, |buffer, cx| {
18230                                        let language = buffer.language()?;
18231                                        let should_discard = project.update(cx, |project, cx| {
18232                                            project.is_local()
18233                                                && !project.has_language_servers_for(buffer, cx)
18234                                        });
18235                                        should_discard.not().then_some(language.clone())
18236                                    })
18237                                })
18238                                .collect::<HashSet<_>>()
18239                        });
18240                        if !languages_affected.is_empty() {
18241                            self.refresh_inlay_hints(
18242                                InlayHintRefreshReason::BufferEdited(languages_affected),
18243                                cx,
18244                            );
18245                        }
18246                    }
18247                }
18248
18249                let Some(project) = &self.project else { return };
18250                let (telemetry, is_via_ssh) = {
18251                    let project = project.read(cx);
18252                    let telemetry = project.client().telemetry().clone();
18253                    let is_via_ssh = project.is_via_ssh();
18254                    (telemetry, is_via_ssh)
18255                };
18256                refresh_linked_ranges(self, window, cx);
18257                telemetry.log_edit_event("editor", is_via_ssh);
18258            }
18259            multi_buffer::Event::ExcerptsAdded {
18260                buffer,
18261                predecessor,
18262                excerpts,
18263            } => {
18264                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18265                let buffer_id = buffer.read(cx).remote_id();
18266                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18267                    if let Some(project) = &self.project {
18268                        update_uncommitted_diff_for_buffer(
18269                            cx.entity(),
18270                            project,
18271                            [buffer.clone()],
18272                            self.buffer.clone(),
18273                            cx,
18274                        )
18275                        .detach();
18276                    }
18277                }
18278                cx.emit(EditorEvent::ExcerptsAdded {
18279                    buffer: buffer.clone(),
18280                    predecessor: *predecessor,
18281                    excerpts: excerpts.clone(),
18282                });
18283                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18284            }
18285            multi_buffer::Event::ExcerptsRemoved {
18286                ids,
18287                removed_buffer_ids,
18288            } => {
18289                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18290                let buffer = self.buffer.read(cx);
18291                self.registered_buffers
18292                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18293                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18294                cx.emit(EditorEvent::ExcerptsRemoved {
18295                    ids: ids.clone(),
18296                    removed_buffer_ids: removed_buffer_ids.clone(),
18297                })
18298            }
18299            multi_buffer::Event::ExcerptsEdited {
18300                excerpt_ids,
18301                buffer_ids,
18302            } => {
18303                self.display_map.update(cx, |map, cx| {
18304                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18305                });
18306                cx.emit(EditorEvent::ExcerptsEdited {
18307                    ids: excerpt_ids.clone(),
18308                })
18309            }
18310            multi_buffer::Event::ExcerptsExpanded { ids } => {
18311                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18312                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18313            }
18314            multi_buffer::Event::Reparsed(buffer_id) => {
18315                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18316                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18317
18318                cx.emit(EditorEvent::Reparsed(*buffer_id));
18319            }
18320            multi_buffer::Event::DiffHunksToggled => {
18321                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18322            }
18323            multi_buffer::Event::LanguageChanged(buffer_id) => {
18324                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18325                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18326                cx.emit(EditorEvent::Reparsed(*buffer_id));
18327                cx.notify();
18328            }
18329            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18330            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18331            multi_buffer::Event::FileHandleChanged
18332            | multi_buffer::Event::Reloaded
18333            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18334            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18335            multi_buffer::Event::DiagnosticsUpdated => {
18336                self.refresh_active_diagnostics(cx);
18337                self.refresh_inline_diagnostics(true, window, cx);
18338                self.scrollbar_marker_state.dirty = true;
18339                cx.notify();
18340            }
18341            _ => {}
18342        };
18343    }
18344
18345    pub fn start_temporary_diff_override(&mut self) {
18346        self.load_diff_task.take();
18347        self.temporary_diff_override = true;
18348    }
18349
18350    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18351        self.temporary_diff_override = false;
18352        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18353        self.buffer.update(cx, |buffer, cx| {
18354            buffer.set_all_diff_hunks_collapsed(cx);
18355        });
18356
18357        if let Some(project) = self.project.clone() {
18358            self.load_diff_task = Some(
18359                update_uncommitted_diff_for_buffer(
18360                    cx.entity(),
18361                    &project,
18362                    self.buffer.read(cx).all_buffers(),
18363                    self.buffer.clone(),
18364                    cx,
18365                )
18366                .shared(),
18367            );
18368        }
18369    }
18370
18371    fn on_display_map_changed(
18372        &mut self,
18373        _: Entity<DisplayMap>,
18374        _: &mut Window,
18375        cx: &mut Context<Self>,
18376    ) {
18377        cx.notify();
18378    }
18379
18380    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18381        let new_severity = if self.diagnostics_enabled() {
18382            EditorSettings::get_global(cx)
18383                .diagnostics_max_severity
18384                .unwrap_or(DiagnosticSeverity::Hint)
18385        } else {
18386            DiagnosticSeverity::Off
18387        };
18388        self.set_max_diagnostics_severity(new_severity, cx);
18389        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18390        self.update_edit_prediction_settings(cx);
18391        self.refresh_inline_completion(true, false, window, cx);
18392        self.refresh_inlay_hints(
18393            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18394                self.selections.newest_anchor().head(),
18395                &self.buffer.read(cx).snapshot(cx),
18396                cx,
18397            )),
18398            cx,
18399        );
18400
18401        let old_cursor_shape = self.cursor_shape;
18402
18403        {
18404            let editor_settings = EditorSettings::get_global(cx);
18405            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18406            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18407            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18408            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18409        }
18410
18411        if old_cursor_shape != self.cursor_shape {
18412            cx.emit(EditorEvent::CursorShapeChanged);
18413        }
18414
18415        let project_settings = ProjectSettings::get_global(cx);
18416        self.serialize_dirty_buffers =
18417            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18418
18419        if self.mode.is_full() {
18420            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18421            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18422            if self.show_inline_diagnostics != show_inline_diagnostics {
18423                self.show_inline_diagnostics = show_inline_diagnostics;
18424                self.refresh_inline_diagnostics(false, window, cx);
18425            }
18426
18427            if self.git_blame_inline_enabled != inline_blame_enabled {
18428                self.toggle_git_blame_inline_internal(false, window, cx);
18429            }
18430
18431            let minimap_settings = EditorSettings::get_global(cx).minimap;
18432            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18433                self.set_minimap_visibility(
18434                    self.minimap_visibility.toggle_visibility(),
18435                    window,
18436                    cx,
18437                );
18438            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18439                minimap_entity.update(cx, |minimap_editor, cx| {
18440                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18441                })
18442            }
18443        }
18444
18445        cx.notify();
18446    }
18447
18448    pub fn set_searchable(&mut self, searchable: bool) {
18449        self.searchable = searchable;
18450    }
18451
18452    pub fn searchable(&self) -> bool {
18453        self.searchable
18454    }
18455
18456    fn open_proposed_changes_editor(
18457        &mut self,
18458        _: &OpenProposedChangesEditor,
18459        window: &mut Window,
18460        cx: &mut Context<Self>,
18461    ) {
18462        let Some(workspace) = self.workspace() else {
18463            cx.propagate();
18464            return;
18465        };
18466
18467        let selections = self.selections.all::<usize>(cx);
18468        let multi_buffer = self.buffer.read(cx);
18469        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18470        let mut new_selections_by_buffer = HashMap::default();
18471        for selection in selections {
18472            for (buffer, range, _) in
18473                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18474            {
18475                let mut range = range.to_point(buffer);
18476                range.start.column = 0;
18477                range.end.column = buffer.line_len(range.end.row);
18478                new_selections_by_buffer
18479                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18480                    .or_insert(Vec::new())
18481                    .push(range)
18482            }
18483        }
18484
18485        let proposed_changes_buffers = new_selections_by_buffer
18486            .into_iter()
18487            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18488            .collect::<Vec<_>>();
18489        let proposed_changes_editor = cx.new(|cx| {
18490            ProposedChangesEditor::new(
18491                "Proposed changes",
18492                proposed_changes_buffers,
18493                self.project.clone(),
18494                window,
18495                cx,
18496            )
18497        });
18498
18499        window.defer(cx, move |window, cx| {
18500            workspace.update(cx, |workspace, cx| {
18501                workspace.active_pane().update(cx, |pane, cx| {
18502                    pane.add_item(
18503                        Box::new(proposed_changes_editor),
18504                        true,
18505                        true,
18506                        None,
18507                        window,
18508                        cx,
18509                    );
18510                });
18511            });
18512        });
18513    }
18514
18515    pub fn open_excerpts_in_split(
18516        &mut self,
18517        _: &OpenExcerptsSplit,
18518        window: &mut Window,
18519        cx: &mut Context<Self>,
18520    ) {
18521        self.open_excerpts_common(None, true, window, cx)
18522    }
18523
18524    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18525        self.open_excerpts_common(None, false, window, cx)
18526    }
18527
18528    fn open_excerpts_common(
18529        &mut self,
18530        jump_data: Option<JumpData>,
18531        split: bool,
18532        window: &mut Window,
18533        cx: &mut Context<Self>,
18534    ) {
18535        let Some(workspace) = self.workspace() else {
18536            cx.propagate();
18537            return;
18538        };
18539
18540        if self.buffer.read(cx).is_singleton() {
18541            cx.propagate();
18542            return;
18543        }
18544
18545        let mut new_selections_by_buffer = HashMap::default();
18546        match &jump_data {
18547            Some(JumpData::MultiBufferPoint {
18548                excerpt_id,
18549                position,
18550                anchor,
18551                line_offset_from_top,
18552            }) => {
18553                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18554                if let Some(buffer) = multi_buffer_snapshot
18555                    .buffer_id_for_excerpt(*excerpt_id)
18556                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18557                {
18558                    let buffer_snapshot = buffer.read(cx).snapshot();
18559                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18560                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18561                    } else {
18562                        buffer_snapshot.clip_point(*position, Bias::Left)
18563                    };
18564                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18565                    new_selections_by_buffer.insert(
18566                        buffer,
18567                        (
18568                            vec![jump_to_offset..jump_to_offset],
18569                            Some(*line_offset_from_top),
18570                        ),
18571                    );
18572                }
18573            }
18574            Some(JumpData::MultiBufferRow {
18575                row,
18576                line_offset_from_top,
18577            }) => {
18578                let point = MultiBufferPoint::new(row.0, 0);
18579                if let Some((buffer, buffer_point, _)) =
18580                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18581                {
18582                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18583                    new_selections_by_buffer
18584                        .entry(buffer)
18585                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18586                        .0
18587                        .push(buffer_offset..buffer_offset)
18588                }
18589            }
18590            None => {
18591                let selections = self.selections.all::<usize>(cx);
18592                let multi_buffer = self.buffer.read(cx);
18593                for selection in selections {
18594                    for (snapshot, range, _, anchor) in multi_buffer
18595                        .snapshot(cx)
18596                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18597                    {
18598                        if let Some(anchor) = anchor {
18599                            // selection is in a deleted hunk
18600                            let Some(buffer_id) = anchor.buffer_id else {
18601                                continue;
18602                            };
18603                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18604                                continue;
18605                            };
18606                            let offset = text::ToOffset::to_offset(
18607                                &anchor.text_anchor,
18608                                &buffer_handle.read(cx).snapshot(),
18609                            );
18610                            let range = offset..offset;
18611                            new_selections_by_buffer
18612                                .entry(buffer_handle)
18613                                .or_insert((Vec::new(), None))
18614                                .0
18615                                .push(range)
18616                        } else {
18617                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18618                            else {
18619                                continue;
18620                            };
18621                            new_selections_by_buffer
18622                                .entry(buffer_handle)
18623                                .or_insert((Vec::new(), None))
18624                                .0
18625                                .push(range)
18626                        }
18627                    }
18628                }
18629            }
18630        }
18631
18632        new_selections_by_buffer
18633            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18634
18635        if new_selections_by_buffer.is_empty() {
18636            return;
18637        }
18638
18639        // We defer the pane interaction because we ourselves are a workspace item
18640        // and activating a new item causes the pane to call a method on us reentrantly,
18641        // which panics if we're on the stack.
18642        window.defer(cx, move |window, cx| {
18643            workspace.update(cx, |workspace, cx| {
18644                let pane = if split {
18645                    workspace.adjacent_pane(window, cx)
18646                } else {
18647                    workspace.active_pane().clone()
18648                };
18649
18650                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18651                    let editor = buffer
18652                        .read(cx)
18653                        .file()
18654                        .is_none()
18655                        .then(|| {
18656                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18657                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18658                            // Instead, we try to activate the existing editor in the pane first.
18659                            let (editor, pane_item_index) =
18660                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18661                                    let editor = item.downcast::<Editor>()?;
18662                                    let singleton_buffer =
18663                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18664                                    if singleton_buffer == buffer {
18665                                        Some((editor, i))
18666                                    } else {
18667                                        None
18668                                    }
18669                                })?;
18670                            pane.update(cx, |pane, cx| {
18671                                pane.activate_item(pane_item_index, true, true, window, cx)
18672                            });
18673                            Some(editor)
18674                        })
18675                        .flatten()
18676                        .unwrap_or_else(|| {
18677                            workspace.open_project_item::<Self>(
18678                                pane.clone(),
18679                                buffer,
18680                                true,
18681                                true,
18682                                window,
18683                                cx,
18684                            )
18685                        });
18686
18687                    editor.update(cx, |editor, cx| {
18688                        let autoscroll = match scroll_offset {
18689                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18690                            None => Autoscroll::newest(),
18691                        };
18692                        let nav_history = editor.nav_history.take();
18693                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18694                            s.select_ranges(ranges);
18695                        });
18696                        editor.nav_history = nav_history;
18697                    });
18698                }
18699            })
18700        });
18701    }
18702
18703    // For now, don't allow opening excerpts in buffers that aren't backed by
18704    // regular project files.
18705    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18706        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18707    }
18708
18709    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18710        let snapshot = self.buffer.read(cx).read(cx);
18711        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18712        Some(
18713            ranges
18714                .iter()
18715                .map(move |range| {
18716                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18717                })
18718                .collect(),
18719        )
18720    }
18721
18722    fn selection_replacement_ranges(
18723        &self,
18724        range: Range<OffsetUtf16>,
18725        cx: &mut App,
18726    ) -> Vec<Range<OffsetUtf16>> {
18727        let selections = self.selections.all::<OffsetUtf16>(cx);
18728        let newest_selection = selections
18729            .iter()
18730            .max_by_key(|selection| selection.id)
18731            .unwrap();
18732        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18733        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18734        let snapshot = self.buffer.read(cx).read(cx);
18735        selections
18736            .into_iter()
18737            .map(|mut selection| {
18738                selection.start.0 =
18739                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18740                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18741                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18742                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18743            })
18744            .collect()
18745    }
18746
18747    fn report_editor_event(
18748        &self,
18749        event_type: &'static str,
18750        file_extension: Option<String>,
18751        cx: &App,
18752    ) {
18753        if cfg!(any(test, feature = "test-support")) {
18754            return;
18755        }
18756
18757        let Some(project) = &self.project else { return };
18758
18759        // If None, we are in a file without an extension
18760        let file = self
18761            .buffer
18762            .read(cx)
18763            .as_singleton()
18764            .and_then(|b| b.read(cx).file());
18765        let file_extension = file_extension.or(file
18766            .as_ref()
18767            .and_then(|file| Path::new(file.file_name(cx)).extension())
18768            .and_then(|e| e.to_str())
18769            .map(|a| a.to_string()));
18770
18771        let vim_mode = vim_enabled(cx);
18772
18773        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18774        let copilot_enabled = edit_predictions_provider
18775            == language::language_settings::EditPredictionProvider::Copilot;
18776        let copilot_enabled_for_language = self
18777            .buffer
18778            .read(cx)
18779            .language_settings(cx)
18780            .show_edit_predictions;
18781
18782        let project = project.read(cx);
18783        telemetry::event!(
18784            event_type,
18785            file_extension,
18786            vim_mode,
18787            copilot_enabled,
18788            copilot_enabled_for_language,
18789            edit_predictions_provider,
18790            is_via_ssh = project.is_via_ssh(),
18791        );
18792    }
18793
18794    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18795    /// with each line being an array of {text, highlight} objects.
18796    fn copy_highlight_json(
18797        &mut self,
18798        _: &CopyHighlightJson,
18799        window: &mut Window,
18800        cx: &mut Context<Self>,
18801    ) {
18802        #[derive(Serialize)]
18803        struct Chunk<'a> {
18804            text: String,
18805            highlight: Option<&'a str>,
18806        }
18807
18808        let snapshot = self.buffer.read(cx).snapshot(cx);
18809        let range = self
18810            .selected_text_range(false, window, cx)
18811            .and_then(|selection| {
18812                if selection.range.is_empty() {
18813                    None
18814                } else {
18815                    Some(selection.range)
18816                }
18817            })
18818            .unwrap_or_else(|| 0..snapshot.len());
18819
18820        let chunks = snapshot.chunks(range, true);
18821        let mut lines = Vec::new();
18822        let mut line: VecDeque<Chunk> = VecDeque::new();
18823
18824        let Some(style) = self.style.as_ref() else {
18825            return;
18826        };
18827
18828        for chunk in chunks {
18829            let highlight = chunk
18830                .syntax_highlight_id
18831                .and_then(|id| id.name(&style.syntax));
18832            let mut chunk_lines = chunk.text.split('\n').peekable();
18833            while let Some(text) = chunk_lines.next() {
18834                let mut merged_with_last_token = false;
18835                if let Some(last_token) = line.back_mut() {
18836                    if last_token.highlight == highlight {
18837                        last_token.text.push_str(text);
18838                        merged_with_last_token = true;
18839                    }
18840                }
18841
18842                if !merged_with_last_token {
18843                    line.push_back(Chunk {
18844                        text: text.into(),
18845                        highlight,
18846                    });
18847                }
18848
18849                if chunk_lines.peek().is_some() {
18850                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18851                        line.pop_front();
18852                    }
18853                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18854                        line.pop_back();
18855                    }
18856
18857                    lines.push(mem::take(&mut line));
18858                }
18859            }
18860        }
18861
18862        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18863            return;
18864        };
18865        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18866    }
18867
18868    pub fn open_context_menu(
18869        &mut self,
18870        _: &OpenContextMenu,
18871        window: &mut Window,
18872        cx: &mut Context<Self>,
18873    ) {
18874        self.request_autoscroll(Autoscroll::newest(), cx);
18875        let position = self.selections.newest_display(cx).start;
18876        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18877    }
18878
18879    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18880        &self.inlay_hint_cache
18881    }
18882
18883    pub fn replay_insert_event(
18884        &mut self,
18885        text: &str,
18886        relative_utf16_range: Option<Range<isize>>,
18887        window: &mut Window,
18888        cx: &mut Context<Self>,
18889    ) {
18890        if !self.input_enabled {
18891            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18892            return;
18893        }
18894        if let Some(relative_utf16_range) = relative_utf16_range {
18895            let selections = self.selections.all::<OffsetUtf16>(cx);
18896            self.change_selections(None, window, cx, |s| {
18897                let new_ranges = selections.into_iter().map(|range| {
18898                    let start = OffsetUtf16(
18899                        range
18900                            .head()
18901                            .0
18902                            .saturating_add_signed(relative_utf16_range.start),
18903                    );
18904                    let end = OffsetUtf16(
18905                        range
18906                            .head()
18907                            .0
18908                            .saturating_add_signed(relative_utf16_range.end),
18909                    );
18910                    start..end
18911                });
18912                s.select_ranges(new_ranges);
18913            });
18914        }
18915
18916        self.handle_input(text, window, cx);
18917    }
18918
18919    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18920        let Some(provider) = self.semantics_provider.as_ref() else {
18921            return false;
18922        };
18923
18924        let mut supports = false;
18925        self.buffer().update(cx, |this, cx| {
18926            this.for_each_buffer(|buffer| {
18927                supports |= provider.supports_inlay_hints(buffer, cx);
18928            });
18929        });
18930
18931        supports
18932    }
18933
18934    pub fn is_focused(&self, window: &Window) -> bool {
18935        self.focus_handle.is_focused(window)
18936    }
18937
18938    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18939        cx.emit(EditorEvent::Focused);
18940
18941        if let Some(descendant) = self
18942            .last_focused_descendant
18943            .take()
18944            .and_then(|descendant| descendant.upgrade())
18945        {
18946            window.focus(&descendant);
18947        } else {
18948            if let Some(blame) = self.blame.as_ref() {
18949                blame.update(cx, GitBlame::focus)
18950            }
18951
18952            self.blink_manager.update(cx, BlinkManager::enable);
18953            self.show_cursor_names(window, cx);
18954            self.buffer.update(cx, |buffer, cx| {
18955                buffer.finalize_last_transaction(cx);
18956                if self.leader_id.is_none() {
18957                    buffer.set_active_selections(
18958                        &self.selections.disjoint_anchors(),
18959                        self.selections.line_mode,
18960                        self.cursor_shape,
18961                        cx,
18962                    );
18963                }
18964            });
18965        }
18966    }
18967
18968    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18969        cx.emit(EditorEvent::FocusedIn)
18970    }
18971
18972    fn handle_focus_out(
18973        &mut self,
18974        event: FocusOutEvent,
18975        _window: &mut Window,
18976        cx: &mut Context<Self>,
18977    ) {
18978        if event.blurred != self.focus_handle {
18979            self.last_focused_descendant = Some(event.blurred);
18980        }
18981        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18982    }
18983
18984    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18985        self.blink_manager.update(cx, BlinkManager::disable);
18986        self.buffer
18987            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18988
18989        if let Some(blame) = self.blame.as_ref() {
18990            blame.update(cx, GitBlame::blur)
18991        }
18992        if !self.hover_state.focused(window, cx) {
18993            hide_hover(self, cx);
18994        }
18995        if !self
18996            .context_menu
18997            .borrow()
18998            .as_ref()
18999            .is_some_and(|context_menu| context_menu.focused(window, cx))
19000        {
19001            self.hide_context_menu(window, cx);
19002        }
19003        self.discard_inline_completion(false, cx);
19004        cx.emit(EditorEvent::Blurred);
19005        cx.notify();
19006    }
19007
19008    pub fn register_action<A: Action>(
19009        &mut self,
19010        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19011    ) -> Subscription {
19012        let id = self.next_editor_action_id.post_inc();
19013        let listener = Arc::new(listener);
19014        self.editor_actions.borrow_mut().insert(
19015            id,
19016            Box::new(move |window, _| {
19017                let listener = listener.clone();
19018                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19019                    let action = action.downcast_ref().unwrap();
19020                    if phase == DispatchPhase::Bubble {
19021                        listener(action, window, cx)
19022                    }
19023                })
19024            }),
19025        );
19026
19027        let editor_actions = self.editor_actions.clone();
19028        Subscription::new(move || {
19029            editor_actions.borrow_mut().remove(&id);
19030        })
19031    }
19032
19033    pub fn file_header_size(&self) -> u32 {
19034        FILE_HEADER_HEIGHT
19035    }
19036
19037    pub fn restore(
19038        &mut self,
19039        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19040        window: &mut Window,
19041        cx: &mut Context<Self>,
19042    ) {
19043        let workspace = self.workspace();
19044        let project = self.project.as_ref();
19045        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19046            let mut tasks = Vec::new();
19047            for (buffer_id, changes) in revert_changes {
19048                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19049                    buffer.update(cx, |buffer, cx| {
19050                        buffer.edit(
19051                            changes
19052                                .into_iter()
19053                                .map(|(range, text)| (range, text.to_string())),
19054                            None,
19055                            cx,
19056                        );
19057                    });
19058
19059                    if let Some(project) =
19060                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19061                    {
19062                        project.update(cx, |project, cx| {
19063                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19064                        })
19065                    }
19066                }
19067            }
19068            tasks
19069        });
19070        cx.spawn_in(window, async move |_, cx| {
19071            for (buffer, task) in save_tasks {
19072                let result = task.await;
19073                if result.is_err() {
19074                    let Some(path) = buffer
19075                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19076                        .ok()
19077                    else {
19078                        continue;
19079                    };
19080                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19081                        let Some(task) = cx
19082                            .update_window_entity(&workspace, |workspace, window, cx| {
19083                                workspace
19084                                    .open_path_preview(path, None, false, false, false, window, cx)
19085                            })
19086                            .ok()
19087                        else {
19088                            continue;
19089                        };
19090                        task.await.log_err();
19091                    }
19092                }
19093            }
19094        })
19095        .detach();
19096        self.change_selections(None, window, cx, |selections| selections.refresh());
19097    }
19098
19099    pub fn to_pixel_point(
19100        &self,
19101        source: multi_buffer::Anchor,
19102        editor_snapshot: &EditorSnapshot,
19103        window: &mut Window,
19104    ) -> Option<gpui::Point<Pixels>> {
19105        let source_point = source.to_display_point(editor_snapshot);
19106        self.display_to_pixel_point(source_point, editor_snapshot, window)
19107    }
19108
19109    pub fn display_to_pixel_point(
19110        &self,
19111        source: DisplayPoint,
19112        editor_snapshot: &EditorSnapshot,
19113        window: &mut Window,
19114    ) -> Option<gpui::Point<Pixels>> {
19115        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19116        let text_layout_details = self.text_layout_details(window);
19117        let scroll_top = text_layout_details
19118            .scroll_anchor
19119            .scroll_position(editor_snapshot)
19120            .y;
19121
19122        if source.row().as_f32() < scroll_top.floor() {
19123            return None;
19124        }
19125        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19126        let source_y = line_height * (source.row().as_f32() - scroll_top);
19127        Some(gpui::Point::new(source_x, source_y))
19128    }
19129
19130    pub fn has_visible_completions_menu(&self) -> bool {
19131        !self.edit_prediction_preview_is_active()
19132            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19133                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19134            })
19135    }
19136
19137    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19138        if self.mode.is_minimap() {
19139            return;
19140        }
19141        self.addons
19142            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19143    }
19144
19145    pub fn unregister_addon<T: Addon>(&mut self) {
19146        self.addons.remove(&std::any::TypeId::of::<T>());
19147    }
19148
19149    pub fn addon<T: Addon>(&self) -> Option<&T> {
19150        let type_id = std::any::TypeId::of::<T>();
19151        self.addons
19152            .get(&type_id)
19153            .and_then(|item| item.to_any().downcast_ref::<T>())
19154    }
19155
19156    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19157        let type_id = std::any::TypeId::of::<T>();
19158        self.addons
19159            .get_mut(&type_id)
19160            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19161    }
19162
19163    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19164        let text_layout_details = self.text_layout_details(window);
19165        let style = &text_layout_details.editor_style;
19166        let font_id = window.text_system().resolve_font(&style.text.font());
19167        let font_size = style.text.font_size.to_pixels(window.rem_size());
19168        let line_height = style.text.line_height_in_pixels(window.rem_size());
19169        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19170
19171        gpui::Size::new(em_width, line_height)
19172    }
19173
19174    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19175        self.load_diff_task.clone()
19176    }
19177
19178    fn read_metadata_from_db(
19179        &mut self,
19180        item_id: u64,
19181        workspace_id: WorkspaceId,
19182        window: &mut Window,
19183        cx: &mut Context<Editor>,
19184    ) {
19185        if self.is_singleton(cx)
19186            && !self.mode.is_minimap()
19187            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19188        {
19189            let buffer_snapshot = OnceCell::new();
19190
19191            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19192                if !folds.is_empty() {
19193                    let snapshot =
19194                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19195                    self.fold_ranges(
19196                        folds
19197                            .into_iter()
19198                            .map(|(start, end)| {
19199                                snapshot.clip_offset(start, Bias::Left)
19200                                    ..snapshot.clip_offset(end, Bias::Right)
19201                            })
19202                            .collect(),
19203                        false,
19204                        window,
19205                        cx,
19206                    );
19207                }
19208            }
19209
19210            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19211                if !selections.is_empty() {
19212                    let snapshot =
19213                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19214                    self.change_selections(None, window, cx, |s| {
19215                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19216                            snapshot.clip_offset(start, Bias::Left)
19217                                ..snapshot.clip_offset(end, Bias::Right)
19218                        }));
19219                    });
19220                }
19221            };
19222        }
19223
19224        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19225    }
19226}
19227
19228fn vim_enabled(cx: &App) -> bool {
19229    cx.global::<SettingsStore>()
19230        .raw_user_settings()
19231        .get("vim_mode")
19232        == Some(&serde_json::Value::Bool(true))
19233}
19234
19235// Consider user intent and default settings
19236fn choose_completion_range(
19237    completion: &Completion,
19238    intent: CompletionIntent,
19239    buffer: &Entity<Buffer>,
19240    cx: &mut Context<Editor>,
19241) -> Range<usize> {
19242    fn should_replace(
19243        completion: &Completion,
19244        insert_range: &Range<text::Anchor>,
19245        intent: CompletionIntent,
19246        completion_mode_setting: LspInsertMode,
19247        buffer: &Buffer,
19248    ) -> bool {
19249        // specific actions take precedence over settings
19250        match intent {
19251            CompletionIntent::CompleteWithInsert => return false,
19252            CompletionIntent::CompleteWithReplace => return true,
19253            CompletionIntent::Complete | CompletionIntent::Compose => {}
19254        }
19255
19256        match completion_mode_setting {
19257            LspInsertMode::Insert => false,
19258            LspInsertMode::Replace => true,
19259            LspInsertMode::ReplaceSubsequence => {
19260                let mut text_to_replace = buffer.chars_for_range(
19261                    buffer.anchor_before(completion.replace_range.start)
19262                        ..buffer.anchor_after(completion.replace_range.end),
19263                );
19264                let mut completion_text = completion.new_text.chars();
19265
19266                // is `text_to_replace` a subsequence of `completion_text`
19267                text_to_replace
19268                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19269            }
19270            LspInsertMode::ReplaceSuffix => {
19271                let range_after_cursor = insert_range.end..completion.replace_range.end;
19272
19273                let text_after_cursor = buffer
19274                    .text_for_range(
19275                        buffer.anchor_before(range_after_cursor.start)
19276                            ..buffer.anchor_after(range_after_cursor.end),
19277                    )
19278                    .collect::<String>();
19279                completion.new_text.ends_with(&text_after_cursor)
19280            }
19281        }
19282    }
19283
19284    let buffer = buffer.read(cx);
19285
19286    if let CompletionSource::Lsp {
19287        insert_range: Some(insert_range),
19288        ..
19289    } = &completion.source
19290    {
19291        let completion_mode_setting =
19292            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19293                .completions
19294                .lsp_insert_mode;
19295
19296        if !should_replace(
19297            completion,
19298            &insert_range,
19299            intent,
19300            completion_mode_setting,
19301            buffer,
19302        ) {
19303            return insert_range.to_offset(buffer);
19304        }
19305    }
19306
19307    completion.replace_range.to_offset(buffer)
19308}
19309
19310fn insert_extra_newline_brackets(
19311    buffer: &MultiBufferSnapshot,
19312    range: Range<usize>,
19313    language: &language::LanguageScope,
19314) -> bool {
19315    let leading_whitespace_len = buffer
19316        .reversed_chars_at(range.start)
19317        .take_while(|c| c.is_whitespace() && *c != '\n')
19318        .map(|c| c.len_utf8())
19319        .sum::<usize>();
19320    let trailing_whitespace_len = buffer
19321        .chars_at(range.end)
19322        .take_while(|c| c.is_whitespace() && *c != '\n')
19323        .map(|c| c.len_utf8())
19324        .sum::<usize>();
19325    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19326
19327    language.brackets().any(|(pair, enabled)| {
19328        let pair_start = pair.start.trim_end();
19329        let pair_end = pair.end.trim_start();
19330
19331        enabled
19332            && pair.newline
19333            && buffer.contains_str_at(range.end, pair_end)
19334            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19335    })
19336}
19337
19338fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19339    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19340        [(buffer, range, _)] => (*buffer, range.clone()),
19341        _ => return false,
19342    };
19343    let pair = {
19344        let mut result: Option<BracketMatch> = None;
19345
19346        for pair in buffer
19347            .all_bracket_ranges(range.clone())
19348            .filter(move |pair| {
19349                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19350            })
19351        {
19352            let len = pair.close_range.end - pair.open_range.start;
19353
19354            if let Some(existing) = &result {
19355                let existing_len = existing.close_range.end - existing.open_range.start;
19356                if len > existing_len {
19357                    continue;
19358                }
19359            }
19360
19361            result = Some(pair);
19362        }
19363
19364        result
19365    };
19366    let Some(pair) = pair else {
19367        return false;
19368    };
19369    pair.newline_only
19370        && buffer
19371            .chars_for_range(pair.open_range.end..range.start)
19372            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19373            .all(|c| c.is_whitespace() && c != '\n')
19374}
19375
19376fn update_uncommitted_diff_for_buffer(
19377    editor: Entity<Editor>,
19378    project: &Entity<Project>,
19379    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19380    buffer: Entity<MultiBuffer>,
19381    cx: &mut App,
19382) -> Task<()> {
19383    let mut tasks = Vec::new();
19384    project.update(cx, |project, cx| {
19385        for buffer in buffers {
19386            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19387                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19388            }
19389        }
19390    });
19391    cx.spawn(async move |cx| {
19392        let diffs = future::join_all(tasks).await;
19393        if editor
19394            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19395            .unwrap_or(false)
19396        {
19397            return;
19398        }
19399
19400        buffer
19401            .update(cx, |buffer, cx| {
19402                for diff in diffs.into_iter().flatten() {
19403                    buffer.add_diff(diff, cx);
19404                }
19405            })
19406            .ok();
19407    })
19408}
19409
19410fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19411    let tab_size = tab_size.get() as usize;
19412    let mut width = offset;
19413
19414    for ch in text.chars() {
19415        width += if ch == '\t' {
19416            tab_size - (width % tab_size)
19417        } else {
19418            1
19419        };
19420    }
19421
19422    width - offset
19423}
19424
19425#[cfg(test)]
19426mod tests {
19427    use super::*;
19428
19429    #[test]
19430    fn test_string_size_with_expanded_tabs() {
19431        let nz = |val| NonZeroU32::new(val).unwrap();
19432        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19433        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19434        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19435        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19436        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19437        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19438        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19439        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19440    }
19441}
19442
19443/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19444struct WordBreakingTokenizer<'a> {
19445    input: &'a str,
19446}
19447
19448impl<'a> WordBreakingTokenizer<'a> {
19449    fn new(input: &'a str) -> Self {
19450        Self { input }
19451    }
19452}
19453
19454fn is_char_ideographic(ch: char) -> bool {
19455    use unicode_script::Script::*;
19456    use unicode_script::UnicodeScript;
19457    matches!(ch.script(), Han | Tangut | Yi)
19458}
19459
19460fn is_grapheme_ideographic(text: &str) -> bool {
19461    text.chars().any(is_char_ideographic)
19462}
19463
19464fn is_grapheme_whitespace(text: &str) -> bool {
19465    text.chars().any(|x| x.is_whitespace())
19466}
19467
19468fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19469    text.chars().next().map_or(false, |ch| {
19470        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19471    })
19472}
19473
19474#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19475enum WordBreakToken<'a> {
19476    Word { token: &'a str, grapheme_len: usize },
19477    InlineWhitespace { token: &'a str, grapheme_len: usize },
19478    Newline,
19479}
19480
19481impl<'a> Iterator for WordBreakingTokenizer<'a> {
19482    /// Yields a span, the count of graphemes in the token, and whether it was
19483    /// whitespace. Note that it also breaks at word boundaries.
19484    type Item = WordBreakToken<'a>;
19485
19486    fn next(&mut self) -> Option<Self::Item> {
19487        use unicode_segmentation::UnicodeSegmentation;
19488        if self.input.is_empty() {
19489            return None;
19490        }
19491
19492        let mut iter = self.input.graphemes(true).peekable();
19493        let mut offset = 0;
19494        let mut grapheme_len = 0;
19495        if let Some(first_grapheme) = iter.next() {
19496            let is_newline = first_grapheme == "\n";
19497            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19498            offset += first_grapheme.len();
19499            grapheme_len += 1;
19500            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19501                if let Some(grapheme) = iter.peek().copied() {
19502                    if should_stay_with_preceding_ideograph(grapheme) {
19503                        offset += grapheme.len();
19504                        grapheme_len += 1;
19505                    }
19506                }
19507            } else {
19508                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19509                let mut next_word_bound = words.peek().copied();
19510                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19511                    next_word_bound = words.next();
19512                }
19513                while let Some(grapheme) = iter.peek().copied() {
19514                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19515                        break;
19516                    };
19517                    if is_grapheme_whitespace(grapheme) != is_whitespace
19518                        || (grapheme == "\n") != is_newline
19519                    {
19520                        break;
19521                    };
19522                    offset += grapheme.len();
19523                    grapheme_len += 1;
19524                    iter.next();
19525                }
19526            }
19527            let token = &self.input[..offset];
19528            self.input = &self.input[offset..];
19529            if token == "\n" {
19530                Some(WordBreakToken::Newline)
19531            } else if is_whitespace {
19532                Some(WordBreakToken::InlineWhitespace {
19533                    token,
19534                    grapheme_len,
19535                })
19536            } else {
19537                Some(WordBreakToken::Word {
19538                    token,
19539                    grapheme_len,
19540                })
19541            }
19542        } else {
19543            None
19544        }
19545    }
19546}
19547
19548#[test]
19549fn test_word_breaking_tokenizer() {
19550    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19551        ("", &[]),
19552        ("  ", &[whitespace("  ", 2)]),
19553        ("Ʒ", &[word("Ʒ", 1)]),
19554        ("Ǽ", &[word("Ǽ", 1)]),
19555        ("", &[word("", 1)]),
19556        ("⋑⋑", &[word("⋑⋑", 2)]),
19557        (
19558            "原理,进而",
19559            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19560        ),
19561        (
19562            "hello world",
19563            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19564        ),
19565        (
19566            "hello, world",
19567            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19568        ),
19569        (
19570            "  hello world",
19571            &[
19572                whitespace("  ", 2),
19573                word("hello", 5),
19574                whitespace(" ", 1),
19575                word("world", 5),
19576            ],
19577        ),
19578        (
19579            "这是什么 \n 钢笔",
19580            &[
19581                word("", 1),
19582                word("", 1),
19583                word("", 1),
19584                word("", 1),
19585                whitespace(" ", 1),
19586                newline(),
19587                whitespace(" ", 1),
19588                word("", 1),
19589                word("", 1),
19590            ],
19591        ),
19592        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19593    ];
19594
19595    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19596        WordBreakToken::Word {
19597            token,
19598            grapheme_len,
19599        }
19600    }
19601
19602    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19603        WordBreakToken::InlineWhitespace {
19604            token,
19605            grapheme_len,
19606        }
19607    }
19608
19609    fn newline() -> WordBreakToken<'static> {
19610        WordBreakToken::Newline
19611    }
19612
19613    for (input, result) in tests {
19614        assert_eq!(
19615            WordBreakingTokenizer::new(input)
19616                .collect::<Vec<_>>()
19617                .as_slice(),
19618            *result,
19619        );
19620    }
19621}
19622
19623fn wrap_with_prefix(
19624    line_prefix: String,
19625    unwrapped_text: String,
19626    wrap_column: usize,
19627    tab_size: NonZeroU32,
19628    preserve_existing_whitespace: bool,
19629) -> String {
19630    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19631    let mut wrapped_text = String::new();
19632    let mut current_line = line_prefix.clone();
19633
19634    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19635    let mut current_line_len = line_prefix_len;
19636    let mut in_whitespace = false;
19637    for token in tokenizer {
19638        let have_preceding_whitespace = in_whitespace;
19639        match token {
19640            WordBreakToken::Word {
19641                token,
19642                grapheme_len,
19643            } => {
19644                in_whitespace = false;
19645                if current_line_len + grapheme_len > wrap_column
19646                    && current_line_len != line_prefix_len
19647                {
19648                    wrapped_text.push_str(current_line.trim_end());
19649                    wrapped_text.push('\n');
19650                    current_line.truncate(line_prefix.len());
19651                    current_line_len = line_prefix_len;
19652                }
19653                current_line.push_str(token);
19654                current_line_len += grapheme_len;
19655            }
19656            WordBreakToken::InlineWhitespace {
19657                mut token,
19658                mut grapheme_len,
19659            } => {
19660                in_whitespace = true;
19661                if have_preceding_whitespace && !preserve_existing_whitespace {
19662                    continue;
19663                }
19664                if !preserve_existing_whitespace {
19665                    token = " ";
19666                    grapheme_len = 1;
19667                }
19668                if current_line_len + grapheme_len > wrap_column {
19669                    wrapped_text.push_str(current_line.trim_end());
19670                    wrapped_text.push('\n');
19671                    current_line.truncate(line_prefix.len());
19672                    current_line_len = line_prefix_len;
19673                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19674                    current_line.push_str(token);
19675                    current_line_len += grapheme_len;
19676                }
19677            }
19678            WordBreakToken::Newline => {
19679                in_whitespace = true;
19680                if preserve_existing_whitespace {
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 have_preceding_whitespace {
19686                    continue;
19687                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19688                {
19689                    wrapped_text.push_str(current_line.trim_end());
19690                    wrapped_text.push('\n');
19691                    current_line.truncate(line_prefix.len());
19692                    current_line_len = line_prefix_len;
19693                } else if current_line_len != line_prefix_len {
19694                    current_line.push(' ');
19695                    current_line_len += 1;
19696                }
19697            }
19698        }
19699    }
19700
19701    if !current_line.is_empty() {
19702        wrapped_text.push_str(&current_line);
19703    }
19704    wrapped_text
19705}
19706
19707#[test]
19708fn test_wrap_with_prefix() {
19709    assert_eq!(
19710        wrap_with_prefix(
19711            "# ".to_string(),
19712            "abcdefg".to_string(),
19713            4,
19714            NonZeroU32::new(4).unwrap(),
19715            false,
19716        ),
19717        "# abcdefg"
19718    );
19719    assert_eq!(
19720        wrap_with_prefix(
19721            "".to_string(),
19722            "\thello world".to_string(),
19723            8,
19724            NonZeroU32::new(4).unwrap(),
19725            false,
19726        ),
19727        "hello\nworld"
19728    );
19729    assert_eq!(
19730        wrap_with_prefix(
19731            "// ".to_string(),
19732            "xx \nyy zz aa bb cc".to_string(),
19733            12,
19734            NonZeroU32::new(4).unwrap(),
19735            false,
19736        ),
19737        "// xx yy zz\n// aa bb cc"
19738    );
19739    assert_eq!(
19740        wrap_with_prefix(
19741            String::new(),
19742            "这是什么 \n 钢笔".to_string(),
19743            3,
19744            NonZeroU32::new(4).unwrap(),
19745            false,
19746        ),
19747        "这是什\n么 钢\n"
19748    );
19749}
19750
19751pub trait CollaborationHub {
19752    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19753    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19754    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19755}
19756
19757impl CollaborationHub for Entity<Project> {
19758    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19759        self.read(cx).collaborators()
19760    }
19761
19762    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19763        self.read(cx).user_store().read(cx).participant_indices()
19764    }
19765
19766    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19767        let this = self.read(cx);
19768        let user_ids = this.collaborators().values().map(|c| c.user_id);
19769        this.user_store().read_with(cx, |user_store, cx| {
19770            user_store.participant_names(user_ids, cx)
19771        })
19772    }
19773}
19774
19775pub trait SemanticsProvider {
19776    fn hover(
19777        &self,
19778        buffer: &Entity<Buffer>,
19779        position: text::Anchor,
19780        cx: &mut App,
19781    ) -> Option<Task<Vec<project::Hover>>>;
19782
19783    fn inline_values(
19784        &self,
19785        buffer_handle: Entity<Buffer>,
19786        range: Range<text::Anchor>,
19787        cx: &mut App,
19788    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19789
19790    fn inlay_hints(
19791        &self,
19792        buffer_handle: Entity<Buffer>,
19793        range: Range<text::Anchor>,
19794        cx: &mut App,
19795    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19796
19797    fn resolve_inlay_hint(
19798        &self,
19799        hint: InlayHint,
19800        buffer_handle: Entity<Buffer>,
19801        server_id: LanguageServerId,
19802        cx: &mut App,
19803    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19804
19805    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19806
19807    fn document_highlights(
19808        &self,
19809        buffer: &Entity<Buffer>,
19810        position: text::Anchor,
19811        cx: &mut App,
19812    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19813
19814    fn definitions(
19815        &self,
19816        buffer: &Entity<Buffer>,
19817        position: text::Anchor,
19818        kind: GotoDefinitionKind,
19819        cx: &mut App,
19820    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19821
19822    fn range_for_rename(
19823        &self,
19824        buffer: &Entity<Buffer>,
19825        position: text::Anchor,
19826        cx: &mut App,
19827    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19828
19829    fn perform_rename(
19830        &self,
19831        buffer: &Entity<Buffer>,
19832        position: text::Anchor,
19833        new_name: String,
19834        cx: &mut App,
19835    ) -> Option<Task<Result<ProjectTransaction>>>;
19836}
19837
19838pub trait CompletionProvider {
19839    fn completions(
19840        &self,
19841        excerpt_id: ExcerptId,
19842        buffer: &Entity<Buffer>,
19843        buffer_position: text::Anchor,
19844        trigger: CompletionContext,
19845        window: &mut Window,
19846        cx: &mut Context<Editor>,
19847    ) -> Task<Result<Option<Vec<Completion>>>>;
19848
19849    fn resolve_completions(
19850        &self,
19851        buffer: Entity<Buffer>,
19852        completion_indices: Vec<usize>,
19853        completions: Rc<RefCell<Box<[Completion]>>>,
19854        cx: &mut Context<Editor>,
19855    ) -> Task<Result<bool>>;
19856
19857    fn apply_additional_edits_for_completion(
19858        &self,
19859        _buffer: Entity<Buffer>,
19860        _completions: Rc<RefCell<Box<[Completion]>>>,
19861        _completion_index: usize,
19862        _push_to_history: bool,
19863        _cx: &mut Context<Editor>,
19864    ) -> Task<Result<Option<language::Transaction>>> {
19865        Task::ready(Ok(None))
19866    }
19867
19868    fn is_completion_trigger(
19869        &self,
19870        buffer: &Entity<Buffer>,
19871        position: language::Anchor,
19872        text: &str,
19873        trigger_in_words: bool,
19874        cx: &mut Context<Editor>,
19875    ) -> bool;
19876
19877    fn sort_completions(&self) -> bool {
19878        true
19879    }
19880
19881    fn filter_completions(&self) -> bool {
19882        true
19883    }
19884}
19885
19886pub trait CodeActionProvider {
19887    fn id(&self) -> Arc<str>;
19888
19889    fn code_actions(
19890        &self,
19891        buffer: &Entity<Buffer>,
19892        range: Range<text::Anchor>,
19893        window: &mut Window,
19894        cx: &mut App,
19895    ) -> Task<Result<Vec<CodeAction>>>;
19896
19897    fn apply_code_action(
19898        &self,
19899        buffer_handle: Entity<Buffer>,
19900        action: CodeAction,
19901        excerpt_id: ExcerptId,
19902        push_to_history: bool,
19903        window: &mut Window,
19904        cx: &mut App,
19905    ) -> Task<Result<ProjectTransaction>>;
19906}
19907
19908impl CodeActionProvider for Entity<Project> {
19909    fn id(&self) -> Arc<str> {
19910        "project".into()
19911    }
19912
19913    fn code_actions(
19914        &self,
19915        buffer: &Entity<Buffer>,
19916        range: Range<text::Anchor>,
19917        _window: &mut Window,
19918        cx: &mut App,
19919    ) -> Task<Result<Vec<CodeAction>>> {
19920        self.update(cx, |project, cx| {
19921            let code_lens = project.code_lens(buffer, range.clone(), cx);
19922            let code_actions = project.code_actions(buffer, range, None, cx);
19923            cx.background_spawn(async move {
19924                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19925                Ok(code_lens
19926                    .context("code lens fetch")?
19927                    .into_iter()
19928                    .chain(code_actions.context("code action fetch")?)
19929                    .collect())
19930            })
19931        })
19932    }
19933
19934    fn apply_code_action(
19935        &self,
19936        buffer_handle: Entity<Buffer>,
19937        action: CodeAction,
19938        _excerpt_id: ExcerptId,
19939        push_to_history: bool,
19940        _window: &mut Window,
19941        cx: &mut App,
19942    ) -> Task<Result<ProjectTransaction>> {
19943        self.update(cx, |project, cx| {
19944            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19945        })
19946    }
19947}
19948
19949fn snippet_completions(
19950    project: &Project,
19951    buffer: &Entity<Buffer>,
19952    buffer_position: text::Anchor,
19953    cx: &mut App,
19954) -> Task<Result<Vec<Completion>>> {
19955    let languages = buffer.read(cx).languages_at(buffer_position);
19956    let snippet_store = project.snippets().read(cx);
19957
19958    let scopes: Vec<_> = languages
19959        .iter()
19960        .filter_map(|language| {
19961            let language_name = language.lsp_id();
19962            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19963
19964            if snippets.is_empty() {
19965                None
19966            } else {
19967                Some((language.default_scope(), snippets))
19968            }
19969        })
19970        .collect();
19971
19972    if scopes.is_empty() {
19973        return Task::ready(Ok(vec![]));
19974    }
19975
19976    let snapshot = buffer.read(cx).text_snapshot();
19977    let chars: String = snapshot
19978        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19979        .collect();
19980    let executor = cx.background_executor().clone();
19981
19982    cx.background_spawn(async move {
19983        let mut all_results: Vec<Completion> = Vec::new();
19984        for (scope, snippets) in scopes.into_iter() {
19985            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19986            let mut last_word = chars
19987                .chars()
19988                .take_while(|c| classifier.is_word(*c))
19989                .collect::<String>();
19990            last_word = last_word.chars().rev().collect();
19991
19992            if last_word.is_empty() {
19993                return Ok(vec![]);
19994            }
19995
19996            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19997            let to_lsp = |point: &text::Anchor| {
19998                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19999                point_to_lsp(end)
20000            };
20001            let lsp_end = to_lsp(&buffer_position);
20002
20003            let candidates = snippets
20004                .iter()
20005                .enumerate()
20006                .flat_map(|(ix, snippet)| {
20007                    snippet
20008                        .prefix
20009                        .iter()
20010                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20011                })
20012                .collect::<Vec<StringMatchCandidate>>();
20013
20014            let mut matches = fuzzy::match_strings(
20015                &candidates,
20016                &last_word,
20017                last_word.chars().any(|c| c.is_uppercase()),
20018                100,
20019                &Default::default(),
20020                executor.clone(),
20021            )
20022            .await;
20023
20024            // Remove all candidates where the query's start does not match the start of any word in the candidate
20025            if let Some(query_start) = last_word.chars().next() {
20026                matches.retain(|string_match| {
20027                    split_words(&string_match.string).any(|word| {
20028                        // Check that the first codepoint of the word as lowercase matches the first
20029                        // codepoint of the query as lowercase
20030                        word.chars()
20031                            .flat_map(|codepoint| codepoint.to_lowercase())
20032                            .zip(query_start.to_lowercase())
20033                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20034                    })
20035                });
20036            }
20037
20038            let matched_strings = matches
20039                .into_iter()
20040                .map(|m| m.string)
20041                .collect::<HashSet<_>>();
20042
20043            let mut result: Vec<Completion> = snippets
20044                .iter()
20045                .filter_map(|snippet| {
20046                    let matching_prefix = snippet
20047                        .prefix
20048                        .iter()
20049                        .find(|prefix| matched_strings.contains(*prefix))?;
20050                    let start = as_offset - last_word.len();
20051                    let start = snapshot.anchor_before(start);
20052                    let range = start..buffer_position;
20053                    let lsp_start = to_lsp(&start);
20054                    let lsp_range = lsp::Range {
20055                        start: lsp_start,
20056                        end: lsp_end,
20057                    };
20058                    Some(Completion {
20059                        replace_range: range,
20060                        new_text: snippet.body.clone(),
20061                        source: CompletionSource::Lsp {
20062                            insert_range: None,
20063                            server_id: LanguageServerId(usize::MAX),
20064                            resolved: true,
20065                            lsp_completion: Box::new(lsp::CompletionItem {
20066                                label: snippet.prefix.first().unwrap().clone(),
20067                                kind: Some(CompletionItemKind::SNIPPET),
20068                                label_details: snippet.description.as_ref().map(|description| {
20069                                    lsp::CompletionItemLabelDetails {
20070                                        detail: Some(description.clone()),
20071                                        description: None,
20072                                    }
20073                                }),
20074                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20075                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20076                                    lsp::InsertReplaceEdit {
20077                                        new_text: snippet.body.clone(),
20078                                        insert: lsp_range,
20079                                        replace: lsp_range,
20080                                    },
20081                                )),
20082                                filter_text: Some(snippet.body.clone()),
20083                                sort_text: Some(char::MAX.to_string()),
20084                                ..lsp::CompletionItem::default()
20085                            }),
20086                            lsp_defaults: None,
20087                        },
20088                        label: CodeLabel {
20089                            text: matching_prefix.clone(),
20090                            runs: Vec::new(),
20091                            filter_range: 0..matching_prefix.len(),
20092                        },
20093                        icon_path: None,
20094                        documentation: Some(
20095                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20096                                single_line: snippet.name.clone().into(),
20097                                plain_text: snippet
20098                                    .description
20099                                    .clone()
20100                                    .map(|description| description.into()),
20101                            },
20102                        ),
20103                        insert_text_mode: None,
20104                        confirm: None,
20105                    })
20106                })
20107                .collect();
20108
20109            all_results.append(&mut result);
20110        }
20111
20112        Ok(all_results)
20113    })
20114}
20115
20116impl CompletionProvider for Entity<Project> {
20117    fn completions(
20118        &self,
20119        _excerpt_id: ExcerptId,
20120        buffer: &Entity<Buffer>,
20121        buffer_position: text::Anchor,
20122        options: CompletionContext,
20123        _window: &mut Window,
20124        cx: &mut Context<Editor>,
20125    ) -> Task<Result<Option<Vec<Completion>>>> {
20126        self.update(cx, |project, cx| {
20127            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20128            let project_completions = project.completions(buffer, buffer_position, options, cx);
20129            cx.background_spawn(async move {
20130                let snippets_completions = snippets.await?;
20131                match project_completions.await? {
20132                    Some(mut completions) => {
20133                        completions.extend(snippets_completions);
20134                        Ok(Some(completions))
20135                    }
20136                    None => {
20137                        if snippets_completions.is_empty() {
20138                            Ok(None)
20139                        } else {
20140                            Ok(Some(snippets_completions))
20141                        }
20142                    }
20143                }
20144            })
20145        })
20146    }
20147
20148    fn resolve_completions(
20149        &self,
20150        buffer: Entity<Buffer>,
20151        completion_indices: Vec<usize>,
20152        completions: Rc<RefCell<Box<[Completion]>>>,
20153        cx: &mut Context<Editor>,
20154    ) -> Task<Result<bool>> {
20155        self.update(cx, |project, cx| {
20156            project.lsp_store().update(cx, |lsp_store, cx| {
20157                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20158            })
20159        })
20160    }
20161
20162    fn apply_additional_edits_for_completion(
20163        &self,
20164        buffer: Entity<Buffer>,
20165        completions: Rc<RefCell<Box<[Completion]>>>,
20166        completion_index: usize,
20167        push_to_history: bool,
20168        cx: &mut Context<Editor>,
20169    ) -> Task<Result<Option<language::Transaction>>> {
20170        self.update(cx, |project, cx| {
20171            project.lsp_store().update(cx, |lsp_store, cx| {
20172                lsp_store.apply_additional_edits_for_completion(
20173                    buffer,
20174                    completions,
20175                    completion_index,
20176                    push_to_history,
20177                    cx,
20178                )
20179            })
20180        })
20181    }
20182
20183    fn is_completion_trigger(
20184        &self,
20185        buffer: &Entity<Buffer>,
20186        position: language::Anchor,
20187        text: &str,
20188        trigger_in_words: bool,
20189        cx: &mut Context<Editor>,
20190    ) -> bool {
20191        let mut chars = text.chars();
20192        let char = if let Some(char) = chars.next() {
20193            char
20194        } else {
20195            return false;
20196        };
20197        if chars.next().is_some() {
20198            return false;
20199        }
20200
20201        let buffer = buffer.read(cx);
20202        let snapshot = buffer.snapshot();
20203        if !snapshot.settings_at(position, cx).show_completions_on_input {
20204            return false;
20205        }
20206        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20207        if trigger_in_words && classifier.is_word(char) {
20208            return true;
20209        }
20210
20211        buffer.completion_triggers().contains(text)
20212    }
20213}
20214
20215impl SemanticsProvider for Entity<Project> {
20216    fn hover(
20217        &self,
20218        buffer: &Entity<Buffer>,
20219        position: text::Anchor,
20220        cx: &mut App,
20221    ) -> Option<Task<Vec<project::Hover>>> {
20222        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20223    }
20224
20225    fn document_highlights(
20226        &self,
20227        buffer: &Entity<Buffer>,
20228        position: text::Anchor,
20229        cx: &mut App,
20230    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20231        Some(self.update(cx, |project, cx| {
20232            project.document_highlights(buffer, position, cx)
20233        }))
20234    }
20235
20236    fn definitions(
20237        &self,
20238        buffer: &Entity<Buffer>,
20239        position: text::Anchor,
20240        kind: GotoDefinitionKind,
20241        cx: &mut App,
20242    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20243        Some(self.update(cx, |project, cx| match kind {
20244            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20245            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20246            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20247            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20248        }))
20249    }
20250
20251    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20252        // TODO: make this work for remote projects
20253        self.update(cx, |project, cx| {
20254            if project
20255                .active_debug_session(cx)
20256                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20257            {
20258                return true;
20259            }
20260
20261            buffer.update(cx, |buffer, cx| {
20262                project.any_language_server_supports_inlay_hints(buffer, cx)
20263            })
20264        })
20265    }
20266
20267    fn inline_values(
20268        &self,
20269        buffer_handle: Entity<Buffer>,
20270
20271        range: Range<text::Anchor>,
20272        cx: &mut App,
20273    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20274        self.update(cx, |project, cx| {
20275            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20276
20277            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20278        })
20279    }
20280
20281    fn inlay_hints(
20282        &self,
20283        buffer_handle: Entity<Buffer>,
20284        range: Range<text::Anchor>,
20285        cx: &mut App,
20286    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20287        Some(self.update(cx, |project, cx| {
20288            project.inlay_hints(buffer_handle, range, cx)
20289        }))
20290    }
20291
20292    fn resolve_inlay_hint(
20293        &self,
20294        hint: InlayHint,
20295        buffer_handle: Entity<Buffer>,
20296        server_id: LanguageServerId,
20297        cx: &mut App,
20298    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20299        Some(self.update(cx, |project, cx| {
20300            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20301        }))
20302    }
20303
20304    fn range_for_rename(
20305        &self,
20306        buffer: &Entity<Buffer>,
20307        position: text::Anchor,
20308        cx: &mut App,
20309    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20310        Some(self.update(cx, |project, cx| {
20311            let buffer = buffer.clone();
20312            let task = project.prepare_rename(buffer.clone(), position, cx);
20313            cx.spawn(async move |_, cx| {
20314                Ok(match task.await? {
20315                    PrepareRenameResponse::Success(range) => Some(range),
20316                    PrepareRenameResponse::InvalidPosition => None,
20317                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20318                        // Fallback on using TreeSitter info to determine identifier range
20319                        buffer.update(cx, |buffer, _| {
20320                            let snapshot = buffer.snapshot();
20321                            let (range, kind) = snapshot.surrounding_word(position);
20322                            if kind != Some(CharKind::Word) {
20323                                return None;
20324                            }
20325                            Some(
20326                                snapshot.anchor_before(range.start)
20327                                    ..snapshot.anchor_after(range.end),
20328                            )
20329                        })?
20330                    }
20331                })
20332            })
20333        }))
20334    }
20335
20336    fn perform_rename(
20337        &self,
20338        buffer: &Entity<Buffer>,
20339        position: text::Anchor,
20340        new_name: String,
20341        cx: &mut App,
20342    ) -> Option<Task<Result<ProjectTransaction>>> {
20343        Some(self.update(cx, |project, cx| {
20344            project.perform_rename(buffer.clone(), position, new_name, cx)
20345        }))
20346    }
20347}
20348
20349fn inlay_hint_settings(
20350    location: Anchor,
20351    snapshot: &MultiBufferSnapshot,
20352    cx: &mut Context<Editor>,
20353) -> InlayHintSettings {
20354    let file = snapshot.file_at(location);
20355    let language = snapshot.language_at(location).map(|l| l.name());
20356    language_settings(language, file, cx).inlay_hints
20357}
20358
20359fn consume_contiguous_rows(
20360    contiguous_row_selections: &mut Vec<Selection<Point>>,
20361    selection: &Selection<Point>,
20362    display_map: &DisplaySnapshot,
20363    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20364) -> (MultiBufferRow, MultiBufferRow) {
20365    contiguous_row_selections.push(selection.clone());
20366    let start_row = MultiBufferRow(selection.start.row);
20367    let mut end_row = ending_row(selection, display_map);
20368
20369    while let Some(next_selection) = selections.peek() {
20370        if next_selection.start.row <= end_row.0 {
20371            end_row = ending_row(next_selection, display_map);
20372            contiguous_row_selections.push(selections.next().unwrap().clone());
20373        } else {
20374            break;
20375        }
20376    }
20377    (start_row, end_row)
20378}
20379
20380fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20381    if next_selection.end.column > 0 || next_selection.is_empty() {
20382        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20383    } else {
20384        MultiBufferRow(next_selection.end.row)
20385    }
20386}
20387
20388impl EditorSnapshot {
20389    pub fn remote_selections_in_range<'a>(
20390        &'a self,
20391        range: &'a Range<Anchor>,
20392        collaboration_hub: &dyn CollaborationHub,
20393        cx: &'a App,
20394    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20395        let participant_names = collaboration_hub.user_names(cx);
20396        let participant_indices = collaboration_hub.user_participant_indices(cx);
20397        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20398        let collaborators_by_replica_id = collaborators_by_peer_id
20399            .values()
20400            .map(|collaborator| (collaborator.replica_id, collaborator))
20401            .collect::<HashMap<_, _>>();
20402        self.buffer_snapshot
20403            .selections_in_range(range, false)
20404            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20405                if replica_id == AGENT_REPLICA_ID {
20406                    Some(RemoteSelection {
20407                        replica_id,
20408                        selection,
20409                        cursor_shape,
20410                        line_mode,
20411                        collaborator_id: CollaboratorId::Agent,
20412                        user_name: Some("Agent".into()),
20413                        color: cx.theme().players().agent(),
20414                    })
20415                } else {
20416                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20417                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20418                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20419                    Some(RemoteSelection {
20420                        replica_id,
20421                        selection,
20422                        cursor_shape,
20423                        line_mode,
20424                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20425                        user_name,
20426                        color: if let Some(index) = participant_index {
20427                            cx.theme().players().color_for_participant(index.0)
20428                        } else {
20429                            cx.theme().players().absent()
20430                        },
20431                    })
20432                }
20433            })
20434    }
20435
20436    pub fn hunks_for_ranges(
20437        &self,
20438        ranges: impl IntoIterator<Item = Range<Point>>,
20439    ) -> Vec<MultiBufferDiffHunk> {
20440        let mut hunks = Vec::new();
20441        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20442            HashMap::default();
20443        for query_range in ranges {
20444            let query_rows =
20445                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20446            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20447                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20448            ) {
20449                // Include deleted hunks that are adjacent to the query range, because
20450                // otherwise they would be missed.
20451                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20452                if hunk.status().is_deleted() {
20453                    intersects_range |= hunk.row_range.start == query_rows.end;
20454                    intersects_range |= hunk.row_range.end == query_rows.start;
20455                }
20456                if intersects_range {
20457                    if !processed_buffer_rows
20458                        .entry(hunk.buffer_id)
20459                        .or_default()
20460                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20461                    {
20462                        continue;
20463                    }
20464                    hunks.push(hunk);
20465                }
20466            }
20467        }
20468
20469        hunks
20470    }
20471
20472    fn display_diff_hunks_for_rows<'a>(
20473        &'a self,
20474        display_rows: Range<DisplayRow>,
20475        folded_buffers: &'a HashSet<BufferId>,
20476    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20477        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20478        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20479
20480        self.buffer_snapshot
20481            .diff_hunks_in_range(buffer_start..buffer_end)
20482            .filter_map(|hunk| {
20483                if folded_buffers.contains(&hunk.buffer_id) {
20484                    return None;
20485                }
20486
20487                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20488                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20489
20490                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20491                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20492
20493                let display_hunk = if hunk_display_start.column() != 0 {
20494                    DisplayDiffHunk::Folded {
20495                        display_row: hunk_display_start.row(),
20496                    }
20497                } else {
20498                    let mut end_row = hunk_display_end.row();
20499                    if hunk_display_end.column() > 0 {
20500                        end_row.0 += 1;
20501                    }
20502                    let is_created_file = hunk.is_created_file();
20503                    DisplayDiffHunk::Unfolded {
20504                        status: hunk.status(),
20505                        diff_base_byte_range: hunk.diff_base_byte_range,
20506                        display_row_range: hunk_display_start.row()..end_row,
20507                        multi_buffer_range: Anchor::range_in_buffer(
20508                            hunk.excerpt_id,
20509                            hunk.buffer_id,
20510                            hunk.buffer_range,
20511                        ),
20512                        is_created_file,
20513                    }
20514                };
20515
20516                Some(display_hunk)
20517            })
20518    }
20519
20520    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20521        self.display_snapshot.buffer_snapshot.language_at(position)
20522    }
20523
20524    pub fn is_focused(&self) -> bool {
20525        self.is_focused
20526    }
20527
20528    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20529        self.placeholder_text.as_ref()
20530    }
20531
20532    pub fn scroll_position(&self) -> gpui::Point<f32> {
20533        self.scroll_anchor.scroll_position(&self.display_snapshot)
20534    }
20535
20536    fn gutter_dimensions(
20537        &self,
20538        font_id: FontId,
20539        font_size: Pixels,
20540        max_line_number_width: Pixels,
20541        cx: &App,
20542    ) -> Option<GutterDimensions> {
20543        if !self.show_gutter {
20544            return None;
20545        }
20546
20547        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20548        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20549
20550        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20551            matches!(
20552                ProjectSettings::get_global(cx).git.git_gutter,
20553                Some(GitGutterSetting::TrackedFiles)
20554            )
20555        });
20556        let gutter_settings = EditorSettings::get_global(cx).gutter;
20557        let show_line_numbers = self
20558            .show_line_numbers
20559            .unwrap_or(gutter_settings.line_numbers);
20560        let line_gutter_width = if show_line_numbers {
20561            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20562            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20563            max_line_number_width.max(min_width_for_number_on_gutter)
20564        } else {
20565            0.0.into()
20566        };
20567
20568        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20569        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20570
20571        let git_blame_entries_width =
20572            self.git_blame_gutter_max_author_length
20573                .map(|max_author_length| {
20574                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20575                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20576
20577                    /// The number of characters to dedicate to gaps and margins.
20578                    const SPACING_WIDTH: usize = 4;
20579
20580                    let max_char_count = max_author_length.min(renderer.max_author_length())
20581                        + ::git::SHORT_SHA_LENGTH
20582                        + MAX_RELATIVE_TIMESTAMP.len()
20583                        + SPACING_WIDTH;
20584
20585                    em_advance * max_char_count
20586                });
20587
20588        let is_singleton = self.buffer_snapshot.is_singleton();
20589
20590        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20591        left_padding += if !is_singleton {
20592            em_width * 4.0
20593        } else if show_runnables || show_breakpoints {
20594            em_width * 3.0
20595        } else if show_git_gutter && show_line_numbers {
20596            em_width * 2.0
20597        } else if show_git_gutter || show_line_numbers {
20598            em_width
20599        } else {
20600            px(0.)
20601        };
20602
20603        let shows_folds = is_singleton && gutter_settings.folds;
20604
20605        let right_padding = if shows_folds && show_line_numbers {
20606            em_width * 4.0
20607        } else if shows_folds || (!is_singleton && show_line_numbers) {
20608            em_width * 3.0
20609        } else if show_line_numbers {
20610            em_width
20611        } else {
20612            px(0.)
20613        };
20614
20615        Some(GutterDimensions {
20616            left_padding,
20617            right_padding,
20618            width: line_gutter_width + left_padding + right_padding,
20619            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20620            git_blame_entries_width,
20621        })
20622    }
20623
20624    pub fn render_crease_toggle(
20625        &self,
20626        buffer_row: MultiBufferRow,
20627        row_contains_cursor: bool,
20628        editor: Entity<Editor>,
20629        window: &mut Window,
20630        cx: &mut App,
20631    ) -> Option<AnyElement> {
20632        let folded = self.is_line_folded(buffer_row);
20633        let mut is_foldable = false;
20634
20635        if let Some(crease) = self
20636            .crease_snapshot
20637            .query_row(buffer_row, &self.buffer_snapshot)
20638        {
20639            is_foldable = true;
20640            match crease {
20641                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20642                    if let Some(render_toggle) = render_toggle {
20643                        let toggle_callback =
20644                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20645                                if folded {
20646                                    editor.update(cx, |editor, cx| {
20647                                        editor.fold_at(buffer_row, window, cx)
20648                                    });
20649                                } else {
20650                                    editor.update(cx, |editor, cx| {
20651                                        editor.unfold_at(buffer_row, window, cx)
20652                                    });
20653                                }
20654                            });
20655                        return Some((render_toggle)(
20656                            buffer_row,
20657                            folded,
20658                            toggle_callback,
20659                            window,
20660                            cx,
20661                        ));
20662                    }
20663                }
20664            }
20665        }
20666
20667        is_foldable |= self.starts_indent(buffer_row);
20668
20669        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20670            Some(
20671                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20672                    .toggle_state(folded)
20673                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20674                        if folded {
20675                            this.unfold_at(buffer_row, window, cx);
20676                        } else {
20677                            this.fold_at(buffer_row, window, cx);
20678                        }
20679                    }))
20680                    .into_any_element(),
20681            )
20682        } else {
20683            None
20684        }
20685    }
20686
20687    pub fn render_crease_trailer(
20688        &self,
20689        buffer_row: MultiBufferRow,
20690        window: &mut Window,
20691        cx: &mut App,
20692    ) -> Option<AnyElement> {
20693        let folded = self.is_line_folded(buffer_row);
20694        if let Crease::Inline { render_trailer, .. } = self
20695            .crease_snapshot
20696            .query_row(buffer_row, &self.buffer_snapshot)?
20697        {
20698            let render_trailer = render_trailer.as_ref()?;
20699            Some(render_trailer(buffer_row, folded, window, cx))
20700        } else {
20701            None
20702        }
20703    }
20704}
20705
20706impl Deref for EditorSnapshot {
20707    type Target = DisplaySnapshot;
20708
20709    fn deref(&self) -> &Self::Target {
20710        &self.display_snapshot
20711    }
20712}
20713
20714#[derive(Clone, Debug, PartialEq, Eq)]
20715pub enum EditorEvent {
20716    InputIgnored {
20717        text: Arc<str>,
20718    },
20719    InputHandled {
20720        utf16_range_to_replace: Option<Range<isize>>,
20721        text: Arc<str>,
20722    },
20723    ExcerptsAdded {
20724        buffer: Entity<Buffer>,
20725        predecessor: ExcerptId,
20726        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20727    },
20728    ExcerptsRemoved {
20729        ids: Vec<ExcerptId>,
20730        removed_buffer_ids: Vec<BufferId>,
20731    },
20732    BufferFoldToggled {
20733        ids: Vec<ExcerptId>,
20734        folded: bool,
20735    },
20736    ExcerptsEdited {
20737        ids: Vec<ExcerptId>,
20738    },
20739    ExcerptsExpanded {
20740        ids: Vec<ExcerptId>,
20741    },
20742    BufferEdited,
20743    Edited {
20744        transaction_id: clock::Lamport,
20745    },
20746    Reparsed(BufferId),
20747    Focused,
20748    FocusedIn,
20749    Blurred,
20750    DirtyChanged,
20751    Saved,
20752    TitleChanged,
20753    DiffBaseChanged,
20754    SelectionsChanged {
20755        local: bool,
20756    },
20757    ScrollPositionChanged {
20758        local: bool,
20759        autoscroll: bool,
20760    },
20761    Closed,
20762    TransactionUndone {
20763        transaction_id: clock::Lamport,
20764    },
20765    TransactionBegun {
20766        transaction_id: clock::Lamport,
20767    },
20768    Reloaded,
20769    CursorShapeChanged,
20770    PushedToNavHistory {
20771        anchor: Anchor,
20772        is_deactivate: bool,
20773    },
20774}
20775
20776impl EventEmitter<EditorEvent> for Editor {}
20777
20778impl Focusable for Editor {
20779    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20780        self.focus_handle.clone()
20781    }
20782}
20783
20784impl Render for Editor {
20785    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20786        let settings = ThemeSettings::get_global(cx);
20787
20788        let mut text_style = match self.mode {
20789            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20790                color: cx.theme().colors().editor_foreground,
20791                font_family: settings.ui_font.family.clone(),
20792                font_features: settings.ui_font.features.clone(),
20793                font_fallbacks: settings.ui_font.fallbacks.clone(),
20794                font_size: rems(0.875).into(),
20795                font_weight: settings.ui_font.weight,
20796                line_height: relative(settings.buffer_line_height.value()),
20797                ..Default::default()
20798            },
20799            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20800                color: cx.theme().colors().editor_foreground,
20801                font_family: settings.buffer_font.family.clone(),
20802                font_features: settings.buffer_font.features.clone(),
20803                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20804                font_size: settings.buffer_font_size(cx).into(),
20805                font_weight: settings.buffer_font.weight,
20806                line_height: relative(settings.buffer_line_height.value()),
20807                ..Default::default()
20808            },
20809        };
20810        if let Some(text_style_refinement) = &self.text_style_refinement {
20811            text_style.refine(text_style_refinement)
20812        }
20813
20814        let background = match self.mode {
20815            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20816            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20817            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20818            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20819        };
20820
20821        EditorElement::new(
20822            &cx.entity(),
20823            EditorStyle {
20824                background,
20825                local_player: cx.theme().players().local(),
20826                text: text_style,
20827                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20828                syntax: cx.theme().syntax().clone(),
20829                status: cx.theme().status().clone(),
20830                inlay_hints_style: make_inlay_hints_style(cx),
20831                inline_completion_styles: make_suggestion_styles(cx),
20832                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20833                show_underlines: !self.mode.is_minimap(),
20834            },
20835        )
20836    }
20837}
20838
20839impl EntityInputHandler for Editor {
20840    fn text_for_range(
20841        &mut self,
20842        range_utf16: Range<usize>,
20843        adjusted_range: &mut Option<Range<usize>>,
20844        _: &mut Window,
20845        cx: &mut Context<Self>,
20846    ) -> Option<String> {
20847        let snapshot = self.buffer.read(cx).read(cx);
20848        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20849        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20850        if (start.0..end.0) != range_utf16 {
20851            adjusted_range.replace(start.0..end.0);
20852        }
20853        Some(snapshot.text_for_range(start..end).collect())
20854    }
20855
20856    fn selected_text_range(
20857        &mut self,
20858        ignore_disabled_input: bool,
20859        _: &mut Window,
20860        cx: &mut Context<Self>,
20861    ) -> Option<UTF16Selection> {
20862        // Prevent the IME menu from appearing when holding down an alphabetic key
20863        // while input is disabled.
20864        if !ignore_disabled_input && !self.input_enabled {
20865            return None;
20866        }
20867
20868        let selection = self.selections.newest::<OffsetUtf16>(cx);
20869        let range = selection.range();
20870
20871        Some(UTF16Selection {
20872            range: range.start.0..range.end.0,
20873            reversed: selection.reversed,
20874        })
20875    }
20876
20877    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20878        let snapshot = self.buffer.read(cx).read(cx);
20879        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20880        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20881    }
20882
20883    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20884        self.clear_highlights::<InputComposition>(cx);
20885        self.ime_transaction.take();
20886    }
20887
20888    fn replace_text_in_range(
20889        &mut self,
20890        range_utf16: Option<Range<usize>>,
20891        text: &str,
20892        window: &mut Window,
20893        cx: &mut Context<Self>,
20894    ) {
20895        if !self.input_enabled {
20896            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20897            return;
20898        }
20899
20900        self.transact(window, cx, |this, window, cx| {
20901            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20902                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20903                Some(this.selection_replacement_ranges(range_utf16, cx))
20904            } else {
20905                this.marked_text_ranges(cx)
20906            };
20907
20908            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20909                let newest_selection_id = this.selections.newest_anchor().id;
20910                this.selections
20911                    .all::<OffsetUtf16>(cx)
20912                    .iter()
20913                    .zip(ranges_to_replace.iter())
20914                    .find_map(|(selection, range)| {
20915                        if selection.id == newest_selection_id {
20916                            Some(
20917                                (range.start.0 as isize - selection.head().0 as isize)
20918                                    ..(range.end.0 as isize - selection.head().0 as isize),
20919                            )
20920                        } else {
20921                            None
20922                        }
20923                    })
20924            });
20925
20926            cx.emit(EditorEvent::InputHandled {
20927                utf16_range_to_replace: range_to_replace,
20928                text: text.into(),
20929            });
20930
20931            if let Some(new_selected_ranges) = new_selected_ranges {
20932                this.change_selections(None, window, cx, |selections| {
20933                    selections.select_ranges(new_selected_ranges)
20934                });
20935                this.backspace(&Default::default(), window, cx);
20936            }
20937
20938            this.handle_input(text, window, cx);
20939        });
20940
20941        if let Some(transaction) = self.ime_transaction {
20942            self.buffer.update(cx, |buffer, cx| {
20943                buffer.group_until_transaction(transaction, cx);
20944            });
20945        }
20946
20947        self.unmark_text(window, cx);
20948    }
20949
20950    fn replace_and_mark_text_in_range(
20951        &mut self,
20952        range_utf16: Option<Range<usize>>,
20953        text: &str,
20954        new_selected_range_utf16: Option<Range<usize>>,
20955        window: &mut Window,
20956        cx: &mut Context<Self>,
20957    ) {
20958        if !self.input_enabled {
20959            return;
20960        }
20961
20962        let transaction = self.transact(window, cx, |this, window, cx| {
20963            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20964                let snapshot = this.buffer.read(cx).read(cx);
20965                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20966                    for marked_range in &mut marked_ranges {
20967                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20968                        marked_range.start.0 += relative_range_utf16.start;
20969                        marked_range.start =
20970                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20971                        marked_range.end =
20972                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20973                    }
20974                }
20975                Some(marked_ranges)
20976            } else if let Some(range_utf16) = range_utf16 {
20977                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20978                Some(this.selection_replacement_ranges(range_utf16, cx))
20979            } else {
20980                None
20981            };
20982
20983            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20984                let newest_selection_id = this.selections.newest_anchor().id;
20985                this.selections
20986                    .all::<OffsetUtf16>(cx)
20987                    .iter()
20988                    .zip(ranges_to_replace.iter())
20989                    .find_map(|(selection, range)| {
20990                        if selection.id == newest_selection_id {
20991                            Some(
20992                                (range.start.0 as isize - selection.head().0 as isize)
20993                                    ..(range.end.0 as isize - selection.head().0 as isize),
20994                            )
20995                        } else {
20996                            None
20997                        }
20998                    })
20999            });
21000
21001            cx.emit(EditorEvent::InputHandled {
21002                utf16_range_to_replace: range_to_replace,
21003                text: text.into(),
21004            });
21005
21006            if let Some(ranges) = ranges_to_replace {
21007                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21008            }
21009
21010            let marked_ranges = {
21011                let snapshot = this.buffer.read(cx).read(cx);
21012                this.selections
21013                    .disjoint_anchors()
21014                    .iter()
21015                    .map(|selection| {
21016                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21017                    })
21018                    .collect::<Vec<_>>()
21019            };
21020
21021            if text.is_empty() {
21022                this.unmark_text(window, cx);
21023            } else {
21024                this.highlight_text::<InputComposition>(
21025                    marked_ranges.clone(),
21026                    HighlightStyle {
21027                        underline: Some(UnderlineStyle {
21028                            thickness: px(1.),
21029                            color: None,
21030                            wavy: false,
21031                        }),
21032                        ..Default::default()
21033                    },
21034                    cx,
21035                );
21036            }
21037
21038            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21039            let use_autoclose = this.use_autoclose;
21040            let use_auto_surround = this.use_auto_surround;
21041            this.set_use_autoclose(false);
21042            this.set_use_auto_surround(false);
21043            this.handle_input(text, window, cx);
21044            this.set_use_autoclose(use_autoclose);
21045            this.set_use_auto_surround(use_auto_surround);
21046
21047            if let Some(new_selected_range) = new_selected_range_utf16 {
21048                let snapshot = this.buffer.read(cx).read(cx);
21049                let new_selected_ranges = marked_ranges
21050                    .into_iter()
21051                    .map(|marked_range| {
21052                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21053                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21054                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21055                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21056                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21057                    })
21058                    .collect::<Vec<_>>();
21059
21060                drop(snapshot);
21061                this.change_selections(None, window, cx, |selections| {
21062                    selections.select_ranges(new_selected_ranges)
21063                });
21064            }
21065        });
21066
21067        self.ime_transaction = self.ime_transaction.or(transaction);
21068        if let Some(transaction) = self.ime_transaction {
21069            self.buffer.update(cx, |buffer, cx| {
21070                buffer.group_until_transaction(transaction, cx);
21071            });
21072        }
21073
21074        if self.text_highlights::<InputComposition>(cx).is_none() {
21075            self.ime_transaction.take();
21076        }
21077    }
21078
21079    fn bounds_for_range(
21080        &mut self,
21081        range_utf16: Range<usize>,
21082        element_bounds: gpui::Bounds<Pixels>,
21083        window: &mut Window,
21084        cx: &mut Context<Self>,
21085    ) -> Option<gpui::Bounds<Pixels>> {
21086        let text_layout_details = self.text_layout_details(window);
21087        let gpui::Size {
21088            width: em_width,
21089            height: line_height,
21090        } = self.character_size(window);
21091
21092        let snapshot = self.snapshot(window, cx);
21093        let scroll_position = snapshot.scroll_position();
21094        let scroll_left = scroll_position.x * em_width;
21095
21096        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21097        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21098            + self.gutter_dimensions.width
21099            + self.gutter_dimensions.margin;
21100        let y = line_height * (start.row().as_f32() - scroll_position.y);
21101
21102        Some(Bounds {
21103            origin: element_bounds.origin + point(x, y),
21104            size: size(em_width, line_height),
21105        })
21106    }
21107
21108    fn character_index_for_point(
21109        &mut self,
21110        point: gpui::Point<Pixels>,
21111        _window: &mut Window,
21112        _cx: &mut Context<Self>,
21113    ) -> Option<usize> {
21114        let position_map = self.last_position_map.as_ref()?;
21115        if !position_map.text_hitbox.contains(&point) {
21116            return None;
21117        }
21118        let display_point = position_map.point_for_position(point).previous_valid;
21119        let anchor = position_map
21120            .snapshot
21121            .display_point_to_anchor(display_point, Bias::Left);
21122        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21123        Some(utf16_offset.0)
21124    }
21125}
21126
21127trait SelectionExt {
21128    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21129    fn spanned_rows(
21130        &self,
21131        include_end_if_at_line_start: bool,
21132        map: &DisplaySnapshot,
21133    ) -> Range<MultiBufferRow>;
21134}
21135
21136impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21137    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21138        let start = self
21139            .start
21140            .to_point(&map.buffer_snapshot)
21141            .to_display_point(map);
21142        let end = self
21143            .end
21144            .to_point(&map.buffer_snapshot)
21145            .to_display_point(map);
21146        if self.reversed {
21147            end..start
21148        } else {
21149            start..end
21150        }
21151    }
21152
21153    fn spanned_rows(
21154        &self,
21155        include_end_if_at_line_start: bool,
21156        map: &DisplaySnapshot,
21157    ) -> Range<MultiBufferRow> {
21158        let start = self.start.to_point(&map.buffer_snapshot);
21159        let mut end = self.end.to_point(&map.buffer_snapshot);
21160        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21161            end.row -= 1;
21162        }
21163
21164        let buffer_start = map.prev_line_boundary(start).0;
21165        let buffer_end = map.next_line_boundary(end).0;
21166        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21167    }
21168}
21169
21170impl<T: InvalidationRegion> InvalidationStack<T> {
21171    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21172    where
21173        S: Clone + ToOffset,
21174    {
21175        while let Some(region) = self.last() {
21176            let all_selections_inside_invalidation_ranges =
21177                if selections.len() == region.ranges().len() {
21178                    selections
21179                        .iter()
21180                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21181                        .all(|(selection, invalidation_range)| {
21182                            let head = selection.head().to_offset(buffer);
21183                            invalidation_range.start <= head && invalidation_range.end >= head
21184                        })
21185                } else {
21186                    false
21187                };
21188
21189            if all_selections_inside_invalidation_ranges {
21190                break;
21191            } else {
21192                self.pop();
21193            }
21194        }
21195    }
21196}
21197
21198impl<T> Default for InvalidationStack<T> {
21199    fn default() -> Self {
21200        Self(Default::default())
21201    }
21202}
21203
21204impl<T> Deref for InvalidationStack<T> {
21205    type Target = Vec<T>;
21206
21207    fn deref(&self) -> &Self::Target {
21208        &self.0
21209    }
21210}
21211
21212impl<T> DerefMut for InvalidationStack<T> {
21213    fn deref_mut(&mut self) -> &mut Self::Target {
21214        &mut self.0
21215    }
21216}
21217
21218impl InvalidationRegion for SnippetState {
21219    fn ranges(&self) -> &[Range<Anchor>] {
21220        &self.ranges[self.active_index]
21221    }
21222}
21223
21224fn inline_completion_edit_text(
21225    current_snapshot: &BufferSnapshot,
21226    edits: &[(Range<Anchor>, String)],
21227    edit_preview: &EditPreview,
21228    include_deletions: bool,
21229    cx: &App,
21230) -> HighlightedText {
21231    let edits = edits
21232        .iter()
21233        .map(|(anchor, text)| {
21234            (
21235                anchor.start.text_anchor..anchor.end.text_anchor,
21236                text.clone(),
21237            )
21238        })
21239        .collect::<Vec<_>>();
21240
21241    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21242}
21243
21244pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21245    match severity {
21246        lsp::DiagnosticSeverity::ERROR => colors.error,
21247        lsp::DiagnosticSeverity::WARNING => colors.warning,
21248        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21249        lsp::DiagnosticSeverity::HINT => colors.info,
21250        _ => colors.ignored,
21251    }
21252}
21253
21254pub fn styled_runs_for_code_label<'a>(
21255    label: &'a CodeLabel,
21256    syntax_theme: &'a theme::SyntaxTheme,
21257) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21258    let fade_out = HighlightStyle {
21259        fade_out: Some(0.35),
21260        ..Default::default()
21261    };
21262
21263    let mut prev_end = label.filter_range.end;
21264    label
21265        .runs
21266        .iter()
21267        .enumerate()
21268        .flat_map(move |(ix, (range, highlight_id))| {
21269            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21270                style
21271            } else {
21272                return Default::default();
21273            };
21274            let mut muted_style = style;
21275            muted_style.highlight(fade_out);
21276
21277            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21278            if range.start >= label.filter_range.end {
21279                if range.start > prev_end {
21280                    runs.push((prev_end..range.start, fade_out));
21281                }
21282                runs.push((range.clone(), muted_style));
21283            } else if range.end <= label.filter_range.end {
21284                runs.push((range.clone(), style));
21285            } else {
21286                runs.push((range.start..label.filter_range.end, style));
21287                runs.push((label.filter_range.end..range.end, muted_style));
21288            }
21289            prev_end = cmp::max(prev_end, range.end);
21290
21291            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21292                runs.push((prev_end..label.text.len(), fade_out));
21293            }
21294
21295            runs
21296        })
21297}
21298
21299pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21300    let mut prev_index = 0;
21301    let mut prev_codepoint: Option<char> = None;
21302    text.char_indices()
21303        .chain([(text.len(), '\0')])
21304        .filter_map(move |(index, codepoint)| {
21305            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21306            let is_boundary = index == text.len()
21307                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21308                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21309            if is_boundary {
21310                let chunk = &text[prev_index..index];
21311                prev_index = index;
21312                Some(chunk)
21313            } else {
21314                None
21315            }
21316        })
21317}
21318
21319pub trait RangeToAnchorExt: Sized {
21320    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21321
21322    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21323        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21324        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21325    }
21326}
21327
21328impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21329    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21330        let start_offset = self.start.to_offset(snapshot);
21331        let end_offset = self.end.to_offset(snapshot);
21332        if start_offset == end_offset {
21333            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21334        } else {
21335            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21336        }
21337    }
21338}
21339
21340pub trait RowExt {
21341    fn as_f32(&self) -> f32;
21342
21343    fn next_row(&self) -> Self;
21344
21345    fn previous_row(&self) -> Self;
21346
21347    fn minus(&self, other: Self) -> u32;
21348}
21349
21350impl RowExt for DisplayRow {
21351    fn as_f32(&self) -> f32 {
21352        self.0 as f32
21353    }
21354
21355    fn next_row(&self) -> Self {
21356        Self(self.0 + 1)
21357    }
21358
21359    fn previous_row(&self) -> Self {
21360        Self(self.0.saturating_sub(1))
21361    }
21362
21363    fn minus(&self, other: Self) -> u32 {
21364        self.0 - other.0
21365    }
21366}
21367
21368impl RowExt for MultiBufferRow {
21369    fn as_f32(&self) -> f32 {
21370        self.0 as f32
21371    }
21372
21373    fn next_row(&self) -> Self {
21374        Self(self.0 + 1)
21375    }
21376
21377    fn previous_row(&self) -> Self {
21378        Self(self.0.saturating_sub(1))
21379    }
21380
21381    fn minus(&self, other: Self) -> u32 {
21382        self.0 - other.0
21383    }
21384}
21385
21386trait RowRangeExt {
21387    type Row;
21388
21389    fn len(&self) -> usize;
21390
21391    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21392}
21393
21394impl RowRangeExt for Range<MultiBufferRow> {
21395    type Row = MultiBufferRow;
21396
21397    fn len(&self) -> usize {
21398        (self.end.0 - self.start.0) as usize
21399    }
21400
21401    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21402        (self.start.0..self.end.0).map(MultiBufferRow)
21403    }
21404}
21405
21406impl RowRangeExt for Range<DisplayRow> {
21407    type Row = DisplayRow;
21408
21409    fn len(&self) -> usize {
21410        (self.end.0 - self.start.0) as usize
21411    }
21412
21413    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21414        (self.start.0..self.end.0).map(DisplayRow)
21415    }
21416}
21417
21418/// If select range has more than one line, we
21419/// just point the cursor to range.start.
21420fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21421    if range.start.row == range.end.row {
21422        range
21423    } else {
21424        range.start..range.start
21425    }
21426}
21427pub struct KillRing(ClipboardItem);
21428impl Global for KillRing {}
21429
21430const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21431
21432enum BreakpointPromptEditAction {
21433    Log,
21434    Condition,
21435    HitCondition,
21436}
21437
21438struct BreakpointPromptEditor {
21439    pub(crate) prompt: Entity<Editor>,
21440    editor: WeakEntity<Editor>,
21441    breakpoint_anchor: Anchor,
21442    breakpoint: Breakpoint,
21443    edit_action: BreakpointPromptEditAction,
21444    block_ids: HashSet<CustomBlockId>,
21445    editor_margins: Arc<Mutex<EditorMargins>>,
21446    _subscriptions: Vec<Subscription>,
21447}
21448
21449impl BreakpointPromptEditor {
21450    const MAX_LINES: u8 = 4;
21451
21452    fn new(
21453        editor: WeakEntity<Editor>,
21454        breakpoint_anchor: Anchor,
21455        breakpoint: Breakpoint,
21456        edit_action: BreakpointPromptEditAction,
21457        window: &mut Window,
21458        cx: &mut Context<Self>,
21459    ) -> Self {
21460        let base_text = match edit_action {
21461            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21462            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21463            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21464        }
21465        .map(|msg| msg.to_string())
21466        .unwrap_or_default();
21467
21468        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21469        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21470
21471        let prompt = cx.new(|cx| {
21472            let mut prompt = Editor::new(
21473                EditorMode::AutoHeight {
21474                    max_lines: Self::MAX_LINES as usize,
21475                },
21476                buffer,
21477                None,
21478                window,
21479                cx,
21480            );
21481            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21482            prompt.set_show_cursor_when_unfocused(false, cx);
21483            prompt.set_placeholder_text(
21484                match edit_action {
21485                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21486                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21487                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21488                },
21489                cx,
21490            );
21491
21492            prompt
21493        });
21494
21495        Self {
21496            prompt,
21497            editor,
21498            breakpoint_anchor,
21499            breakpoint,
21500            edit_action,
21501            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21502            block_ids: Default::default(),
21503            _subscriptions: vec![],
21504        }
21505    }
21506
21507    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21508        self.block_ids.extend(block_ids)
21509    }
21510
21511    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21512        if let Some(editor) = self.editor.upgrade() {
21513            let message = self
21514                .prompt
21515                .read(cx)
21516                .buffer
21517                .read(cx)
21518                .as_singleton()
21519                .expect("A multi buffer in breakpoint prompt isn't possible")
21520                .read(cx)
21521                .as_rope()
21522                .to_string();
21523
21524            editor.update(cx, |editor, cx| {
21525                editor.edit_breakpoint_at_anchor(
21526                    self.breakpoint_anchor,
21527                    self.breakpoint.clone(),
21528                    match self.edit_action {
21529                        BreakpointPromptEditAction::Log => {
21530                            BreakpointEditAction::EditLogMessage(message.into())
21531                        }
21532                        BreakpointPromptEditAction::Condition => {
21533                            BreakpointEditAction::EditCondition(message.into())
21534                        }
21535                        BreakpointPromptEditAction::HitCondition => {
21536                            BreakpointEditAction::EditHitCondition(message.into())
21537                        }
21538                    },
21539                    cx,
21540                );
21541
21542                editor.remove_blocks(self.block_ids.clone(), None, cx);
21543                cx.focus_self(window);
21544            });
21545        }
21546    }
21547
21548    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21549        self.editor
21550            .update(cx, |editor, cx| {
21551                editor.remove_blocks(self.block_ids.clone(), None, cx);
21552                window.focus(&editor.focus_handle);
21553            })
21554            .log_err();
21555    }
21556
21557    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21558        let settings = ThemeSettings::get_global(cx);
21559        let text_style = TextStyle {
21560            color: if self.prompt.read(cx).read_only(cx) {
21561                cx.theme().colors().text_disabled
21562            } else {
21563                cx.theme().colors().text
21564            },
21565            font_family: settings.buffer_font.family.clone(),
21566            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21567            font_size: settings.buffer_font_size(cx).into(),
21568            font_weight: settings.buffer_font.weight,
21569            line_height: relative(settings.buffer_line_height.value()),
21570            ..Default::default()
21571        };
21572        EditorElement::new(
21573            &self.prompt,
21574            EditorStyle {
21575                background: cx.theme().colors().editor_background,
21576                local_player: cx.theme().players().local(),
21577                text: text_style,
21578                ..Default::default()
21579            },
21580        )
21581    }
21582}
21583
21584impl Render for BreakpointPromptEditor {
21585    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21586        let editor_margins = *self.editor_margins.lock();
21587        let gutter_dimensions = editor_margins.gutter;
21588        h_flex()
21589            .key_context("Editor")
21590            .bg(cx.theme().colors().editor_background)
21591            .border_y_1()
21592            .border_color(cx.theme().status().info_border)
21593            .size_full()
21594            .py(window.line_height() / 2.5)
21595            .on_action(cx.listener(Self::confirm))
21596            .on_action(cx.listener(Self::cancel))
21597            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21598            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21599    }
21600}
21601
21602impl Focusable for BreakpointPromptEditor {
21603    fn focus_handle(&self, cx: &App) -> FocusHandle {
21604        self.prompt.focus_handle(cx)
21605    }
21606}
21607
21608fn all_edits_insertions_or_deletions(
21609    edits: &Vec<(Range<Anchor>, String)>,
21610    snapshot: &MultiBufferSnapshot,
21611) -> bool {
21612    let mut all_insertions = true;
21613    let mut all_deletions = true;
21614
21615    for (range, new_text) in edits.iter() {
21616        let range_is_empty = range.to_offset(&snapshot).is_empty();
21617        let text_is_empty = new_text.is_empty();
21618
21619        if range_is_empty != text_is_empty {
21620            if range_is_empty {
21621                all_deletions = false;
21622            } else {
21623                all_insertions = false;
21624            }
21625        } else {
21626            return false;
21627        }
21628
21629        if !all_insertions && !all_deletions {
21630            return false;
21631        }
21632    }
21633    all_insertions || all_deletions
21634}
21635
21636struct MissingEditPredictionKeybindingTooltip;
21637
21638impl Render for MissingEditPredictionKeybindingTooltip {
21639    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21640        ui::tooltip_container(window, cx, |container, _, cx| {
21641            container
21642                .flex_shrink_0()
21643                .max_w_80()
21644                .min_h(rems_from_px(124.))
21645                .justify_between()
21646                .child(
21647                    v_flex()
21648                        .flex_1()
21649                        .text_ui_sm(cx)
21650                        .child(Label::new("Conflict with Accept Keybinding"))
21651                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21652                )
21653                .child(
21654                    h_flex()
21655                        .pb_1()
21656                        .gap_1()
21657                        .items_end()
21658                        .w_full()
21659                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21660                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21661                        }))
21662                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21663                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21664                        })),
21665                )
21666        })
21667    }
21668}
21669
21670#[derive(Debug, Clone, Copy, PartialEq)]
21671pub struct LineHighlight {
21672    pub background: Background,
21673    pub border: Option<gpui::Hsla>,
21674    pub include_gutter: bool,
21675    pub type_id: Option<TypeId>,
21676}
21677
21678fn render_diff_hunk_controls(
21679    row: u32,
21680    status: &DiffHunkStatus,
21681    hunk_range: Range<Anchor>,
21682    is_created_file: bool,
21683    line_height: Pixels,
21684    editor: &Entity<Editor>,
21685    _window: &mut Window,
21686    cx: &mut App,
21687) -> AnyElement {
21688    h_flex()
21689        .h(line_height)
21690        .mr_1()
21691        .gap_1()
21692        .px_0p5()
21693        .pb_1()
21694        .border_x_1()
21695        .border_b_1()
21696        .border_color(cx.theme().colors().border_variant)
21697        .rounded_b_lg()
21698        .bg(cx.theme().colors().editor_background)
21699        .gap_1()
21700        .occlude()
21701        .shadow_md()
21702        .child(if status.has_secondary_hunk() {
21703            Button::new(("stage", row as u64), "Stage")
21704                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21705                .tooltip({
21706                    let focus_handle = editor.focus_handle(cx);
21707                    move |window, cx| {
21708                        Tooltip::for_action_in(
21709                            "Stage Hunk",
21710                            &::git::ToggleStaged,
21711                            &focus_handle,
21712                            window,
21713                            cx,
21714                        )
21715                    }
21716                })
21717                .on_click({
21718                    let editor = editor.clone();
21719                    move |_event, _window, cx| {
21720                        editor.update(cx, |editor, cx| {
21721                            editor.stage_or_unstage_diff_hunks(
21722                                true,
21723                                vec![hunk_range.start..hunk_range.start],
21724                                cx,
21725                            );
21726                        });
21727                    }
21728                })
21729        } else {
21730            Button::new(("unstage", row as u64), "Unstage")
21731                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21732                .tooltip({
21733                    let focus_handle = editor.focus_handle(cx);
21734                    move |window, cx| {
21735                        Tooltip::for_action_in(
21736                            "Unstage Hunk",
21737                            &::git::ToggleStaged,
21738                            &focus_handle,
21739                            window,
21740                            cx,
21741                        )
21742                    }
21743                })
21744                .on_click({
21745                    let editor = editor.clone();
21746                    move |_event, _window, cx| {
21747                        editor.update(cx, |editor, cx| {
21748                            editor.stage_or_unstage_diff_hunks(
21749                                false,
21750                                vec![hunk_range.start..hunk_range.start],
21751                                cx,
21752                            );
21753                        });
21754                    }
21755                })
21756        })
21757        .child(
21758            Button::new(("restore", row as u64), "Restore")
21759                .tooltip({
21760                    let focus_handle = editor.focus_handle(cx);
21761                    move |window, cx| {
21762                        Tooltip::for_action_in(
21763                            "Restore Hunk",
21764                            &::git::Restore,
21765                            &focus_handle,
21766                            window,
21767                            cx,
21768                        )
21769                    }
21770                })
21771                .on_click({
21772                    let editor = editor.clone();
21773                    move |_event, window, cx| {
21774                        editor.update(cx, |editor, cx| {
21775                            let snapshot = editor.snapshot(window, cx);
21776                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21777                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21778                        });
21779                    }
21780                })
21781                .disabled(is_created_file),
21782        )
21783        .when(
21784            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21785            |el| {
21786                el.child(
21787                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21788                        .shape(IconButtonShape::Square)
21789                        .icon_size(IconSize::Small)
21790                        // .disabled(!has_multiple_hunks)
21791                        .tooltip({
21792                            let focus_handle = editor.focus_handle(cx);
21793                            move |window, cx| {
21794                                Tooltip::for_action_in(
21795                                    "Next Hunk",
21796                                    &GoToHunk,
21797                                    &focus_handle,
21798                                    window,
21799                                    cx,
21800                                )
21801                            }
21802                        })
21803                        .on_click({
21804                            let editor = editor.clone();
21805                            move |_event, window, cx| {
21806                                editor.update(cx, |editor, cx| {
21807                                    let snapshot = editor.snapshot(window, cx);
21808                                    let position =
21809                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21810                                    editor.go_to_hunk_before_or_after_position(
21811                                        &snapshot,
21812                                        position,
21813                                        Direction::Next,
21814                                        window,
21815                                        cx,
21816                                    );
21817                                    editor.expand_selected_diff_hunks(cx);
21818                                });
21819                            }
21820                        }),
21821                )
21822                .child(
21823                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21824                        .shape(IconButtonShape::Square)
21825                        .icon_size(IconSize::Small)
21826                        // .disabled(!has_multiple_hunks)
21827                        .tooltip({
21828                            let focus_handle = editor.focus_handle(cx);
21829                            move |window, cx| {
21830                                Tooltip::for_action_in(
21831                                    "Previous Hunk",
21832                                    &GoToPreviousHunk,
21833                                    &focus_handle,
21834                                    window,
21835                                    cx,
21836                                )
21837                            }
21838                        })
21839                        .on_click({
21840                            let editor = editor.clone();
21841                            move |_event, window, cx| {
21842                                editor.update(cx, |editor, cx| {
21843                                    let snapshot = editor.snapshot(window, cx);
21844                                    let point =
21845                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21846                                    editor.go_to_hunk_before_or_after_position(
21847                                        &snapshot,
21848                                        point,
21849                                        Direction::Prev,
21850                                        window,
21851                                        cx,
21852                                    );
21853                                    editor.expand_selected_diff_hunks(cx);
21854                                });
21855                            }
21856                        }),
21857                )
21858            },
21859        )
21860        .into_any_element()
21861}