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_code_actions: Option<bool>,
 1076    show_runnables: Option<bool>,
 1077    show_breakpoints: Option<bool>,
 1078    git_blame_gutter_max_author_length: Option<usize>,
 1079    pub display_snapshot: DisplaySnapshot,
 1080    pub placeholder_text: Option<Arc<str>>,
 1081    is_focused: bool,
 1082    scroll_anchor: ScrollAnchor,
 1083    ongoing_scroll: OngoingScroll,
 1084    current_line_highlight: CurrentLineHighlight,
 1085    gutter_hovered: bool,
 1086}
 1087
 1088#[derive(Default, Debug, Clone, Copy)]
 1089pub struct GutterDimensions {
 1090    pub left_padding: Pixels,
 1091    pub right_padding: Pixels,
 1092    pub width: Pixels,
 1093    pub margin: Pixels,
 1094    pub git_blame_entries_width: Option<Pixels>,
 1095}
 1096
 1097impl GutterDimensions {
 1098    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1099        Self {
 1100            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1101            ..Default::default()
 1102        }
 1103    }
 1104
 1105    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1106        -cx.text_system().descent(font_id, font_size)
 1107    }
 1108    /// The full width of the space taken up by the gutter.
 1109    pub fn full_width(&self) -> Pixels {
 1110        self.margin + self.width
 1111    }
 1112
 1113    /// The width of the space reserved for the fold indicators,
 1114    /// use alongside 'justify_end' and `gutter_width` to
 1115    /// right align content with the line numbers
 1116    pub fn fold_area_width(&self) -> Pixels {
 1117        self.margin + self.right_padding
 1118    }
 1119}
 1120
 1121#[derive(Debug)]
 1122pub struct RemoteSelection {
 1123    pub replica_id: ReplicaId,
 1124    pub selection: Selection<Anchor>,
 1125    pub cursor_shape: CursorShape,
 1126    pub collaborator_id: CollaboratorId,
 1127    pub line_mode: bool,
 1128    pub user_name: Option<SharedString>,
 1129    pub color: PlayerColor,
 1130}
 1131
 1132#[derive(Clone, Debug)]
 1133struct SelectionHistoryEntry {
 1134    selections: Arc<[Selection<Anchor>]>,
 1135    select_next_state: Option<SelectNextState>,
 1136    select_prev_state: Option<SelectNextState>,
 1137    add_selections_state: Option<AddSelectionsState>,
 1138}
 1139
 1140enum SelectionHistoryMode {
 1141    Normal,
 1142    Undoing,
 1143    Redoing,
 1144}
 1145
 1146#[derive(Clone, PartialEq, Eq, Hash)]
 1147struct HoveredCursor {
 1148    replica_id: u16,
 1149    selection_id: usize,
 1150}
 1151
 1152impl Default for SelectionHistoryMode {
 1153    fn default() -> Self {
 1154        Self::Normal
 1155    }
 1156}
 1157
 1158#[derive(Default)]
 1159struct SelectionHistory {
 1160    #[allow(clippy::type_complexity)]
 1161    selections_by_transaction:
 1162        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1163    mode: SelectionHistoryMode,
 1164    undo_stack: VecDeque<SelectionHistoryEntry>,
 1165    redo_stack: VecDeque<SelectionHistoryEntry>,
 1166}
 1167
 1168impl SelectionHistory {
 1169    fn insert_transaction(
 1170        &mut self,
 1171        transaction_id: TransactionId,
 1172        selections: Arc<[Selection<Anchor>]>,
 1173    ) {
 1174        self.selections_by_transaction
 1175            .insert(transaction_id, (selections, None));
 1176    }
 1177
 1178    #[allow(clippy::type_complexity)]
 1179    fn transaction(
 1180        &self,
 1181        transaction_id: TransactionId,
 1182    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1183        self.selections_by_transaction.get(&transaction_id)
 1184    }
 1185
 1186    #[allow(clippy::type_complexity)]
 1187    fn transaction_mut(
 1188        &mut self,
 1189        transaction_id: TransactionId,
 1190    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1191        self.selections_by_transaction.get_mut(&transaction_id)
 1192    }
 1193
 1194    fn push(&mut self, entry: SelectionHistoryEntry) {
 1195        if !entry.selections.is_empty() {
 1196            match self.mode {
 1197                SelectionHistoryMode::Normal => {
 1198                    self.push_undo(entry);
 1199                    self.redo_stack.clear();
 1200                }
 1201                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1202                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1203            }
 1204        }
 1205    }
 1206
 1207    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1208        if self
 1209            .undo_stack
 1210            .back()
 1211            .map_or(true, |e| e.selections != entry.selections)
 1212        {
 1213            self.undo_stack.push_back(entry);
 1214            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1215                self.undo_stack.pop_front();
 1216            }
 1217        }
 1218    }
 1219
 1220    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1221        if self
 1222            .redo_stack
 1223            .back()
 1224            .map_or(true, |e| e.selections != entry.selections)
 1225        {
 1226            self.redo_stack.push_back(entry);
 1227            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1228                self.redo_stack.pop_front();
 1229            }
 1230        }
 1231    }
 1232}
 1233
 1234#[derive(Clone, Copy)]
 1235pub struct RowHighlightOptions {
 1236    pub autoscroll: bool,
 1237    pub include_gutter: bool,
 1238}
 1239
 1240impl Default for RowHighlightOptions {
 1241    fn default() -> Self {
 1242        Self {
 1243            autoscroll: Default::default(),
 1244            include_gutter: true,
 1245        }
 1246    }
 1247}
 1248
 1249struct RowHighlight {
 1250    index: usize,
 1251    range: Range<Anchor>,
 1252    color: Hsla,
 1253    options: RowHighlightOptions,
 1254    type_id: TypeId,
 1255}
 1256
 1257#[derive(Clone, Debug)]
 1258struct AddSelectionsState {
 1259    above: bool,
 1260    stack: Vec<usize>,
 1261}
 1262
 1263#[derive(Clone)]
 1264struct SelectNextState {
 1265    query: AhoCorasick,
 1266    wordwise: bool,
 1267    done: bool,
 1268}
 1269
 1270impl std::fmt::Debug for SelectNextState {
 1271    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1272        f.debug_struct(std::any::type_name::<Self>())
 1273            .field("wordwise", &self.wordwise)
 1274            .field("done", &self.done)
 1275            .finish()
 1276    }
 1277}
 1278
 1279#[derive(Debug)]
 1280struct AutocloseRegion {
 1281    selection_id: usize,
 1282    range: Range<Anchor>,
 1283    pair: BracketPair,
 1284}
 1285
 1286#[derive(Debug)]
 1287struct SnippetState {
 1288    ranges: Vec<Vec<Range<Anchor>>>,
 1289    active_index: usize,
 1290    choices: Vec<Option<Vec<String>>>,
 1291}
 1292
 1293#[doc(hidden)]
 1294pub struct RenameState {
 1295    pub range: Range<Anchor>,
 1296    pub old_name: Arc<str>,
 1297    pub editor: Entity<Editor>,
 1298    block_id: CustomBlockId,
 1299}
 1300
 1301struct InvalidationStack<T>(Vec<T>);
 1302
 1303struct RegisteredInlineCompletionProvider {
 1304    provider: Arc<dyn InlineCompletionProviderHandle>,
 1305    _subscription: Subscription,
 1306}
 1307
 1308#[derive(Debug, PartialEq, Eq)]
 1309pub struct ActiveDiagnosticGroup {
 1310    pub active_range: Range<Anchor>,
 1311    pub active_message: String,
 1312    pub group_id: usize,
 1313    pub blocks: HashSet<CustomBlockId>,
 1314}
 1315
 1316#[derive(Debug, PartialEq, Eq)]
 1317
 1318pub(crate) enum ActiveDiagnostic {
 1319    None,
 1320    All,
 1321    Group(ActiveDiagnosticGroup),
 1322}
 1323
 1324#[derive(Serialize, Deserialize, Clone, Debug)]
 1325pub struct ClipboardSelection {
 1326    /// The number of bytes in this selection.
 1327    pub len: usize,
 1328    /// Whether this was a full-line selection.
 1329    pub is_entire_line: bool,
 1330    /// The indentation of the first line when this content was originally copied.
 1331    pub first_line_indent: u32,
 1332}
 1333
 1334// selections, scroll behavior, was newest selection reversed
 1335type SelectSyntaxNodeHistoryState = (
 1336    Box<[Selection<usize>]>,
 1337    SelectSyntaxNodeScrollBehavior,
 1338    bool,
 1339);
 1340
 1341#[derive(Default)]
 1342struct SelectSyntaxNodeHistory {
 1343    stack: Vec<SelectSyntaxNodeHistoryState>,
 1344    // disable temporarily to allow changing selections without losing the stack
 1345    pub disable_clearing: bool,
 1346}
 1347
 1348impl SelectSyntaxNodeHistory {
 1349    pub fn try_clear(&mut self) {
 1350        if !self.disable_clearing {
 1351            self.stack.clear();
 1352        }
 1353    }
 1354
 1355    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1356        self.stack.push(selection);
 1357    }
 1358
 1359    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1360        self.stack.pop()
 1361    }
 1362}
 1363
 1364enum SelectSyntaxNodeScrollBehavior {
 1365    CursorTop,
 1366    FitSelection,
 1367    CursorBottom,
 1368}
 1369
 1370#[derive(Debug)]
 1371pub(crate) struct NavigationData {
 1372    cursor_anchor: Anchor,
 1373    cursor_position: Point,
 1374    scroll_anchor: ScrollAnchor,
 1375    scroll_top_row: u32,
 1376}
 1377
 1378#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1379pub enum GotoDefinitionKind {
 1380    Symbol,
 1381    Declaration,
 1382    Type,
 1383    Implementation,
 1384}
 1385
 1386#[derive(Debug, Clone)]
 1387enum InlayHintRefreshReason {
 1388    ModifiersChanged(bool),
 1389    Toggle(bool),
 1390    SettingsChange(InlayHintSettings),
 1391    NewLinesShown,
 1392    BufferEdited(HashSet<Arc<Language>>),
 1393    RefreshRequested,
 1394    ExcerptsRemoved(Vec<ExcerptId>),
 1395}
 1396
 1397impl InlayHintRefreshReason {
 1398    fn description(&self) -> &'static str {
 1399        match self {
 1400            Self::ModifiersChanged(_) => "modifiers changed",
 1401            Self::Toggle(_) => "toggle",
 1402            Self::SettingsChange(_) => "settings change",
 1403            Self::NewLinesShown => "new lines shown",
 1404            Self::BufferEdited(_) => "buffer edited",
 1405            Self::RefreshRequested => "refresh requested",
 1406            Self::ExcerptsRemoved(_) => "excerpts removed",
 1407        }
 1408    }
 1409}
 1410
 1411pub enum FormatTarget {
 1412    Buffers,
 1413    Ranges(Vec<Range<MultiBufferPoint>>),
 1414}
 1415
 1416pub(crate) struct FocusedBlock {
 1417    id: BlockId,
 1418    focus_handle: WeakFocusHandle,
 1419}
 1420
 1421#[derive(Clone)]
 1422enum JumpData {
 1423    MultiBufferRow {
 1424        row: MultiBufferRow,
 1425        line_offset_from_top: u32,
 1426    },
 1427    MultiBufferPoint {
 1428        excerpt_id: ExcerptId,
 1429        position: Point,
 1430        anchor: text::Anchor,
 1431        line_offset_from_top: u32,
 1432    },
 1433}
 1434
 1435pub enum MultibufferSelectionMode {
 1436    First,
 1437    All,
 1438}
 1439
 1440#[derive(Clone, Copy, Debug, Default)]
 1441pub struct RewrapOptions {
 1442    pub override_language_settings: bool,
 1443    pub preserve_existing_whitespace: bool,
 1444}
 1445
 1446impl Editor {
 1447    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1448        let buffer = cx.new(|cx| Buffer::local("", cx));
 1449        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1450        Self::new(
 1451            EditorMode::SingleLine { auto_width: false },
 1452            buffer,
 1453            None,
 1454            window,
 1455            cx,
 1456        )
 1457    }
 1458
 1459    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1460        let buffer = cx.new(|cx| Buffer::local("", cx));
 1461        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1462        Self::new(EditorMode::full(), buffer, None, window, cx)
 1463    }
 1464
 1465    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1466        let buffer = cx.new(|cx| Buffer::local("", cx));
 1467        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1468        Self::new(
 1469            EditorMode::SingleLine { auto_width: true },
 1470            buffer,
 1471            None,
 1472            window,
 1473            cx,
 1474        )
 1475    }
 1476
 1477    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1478        let buffer = cx.new(|cx| Buffer::local("", cx));
 1479        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1480        Self::new(
 1481            EditorMode::AutoHeight { max_lines },
 1482            buffer,
 1483            None,
 1484            window,
 1485            cx,
 1486        )
 1487    }
 1488
 1489    pub fn for_buffer(
 1490        buffer: Entity<Buffer>,
 1491        project: Option<Entity<Project>>,
 1492        window: &mut Window,
 1493        cx: &mut Context<Self>,
 1494    ) -> Self {
 1495        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1496        Self::new(EditorMode::full(), buffer, project, window, cx)
 1497    }
 1498
 1499    pub fn for_multibuffer(
 1500        buffer: Entity<MultiBuffer>,
 1501        project: Option<Entity<Project>>,
 1502        window: &mut Window,
 1503        cx: &mut Context<Self>,
 1504    ) -> Self {
 1505        Self::new(EditorMode::full(), buffer, project, window, cx)
 1506    }
 1507
 1508    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1509        let mut clone = Self::new(
 1510            self.mode.clone(),
 1511            self.buffer.clone(),
 1512            self.project.clone(),
 1513            window,
 1514            cx,
 1515        );
 1516        self.display_map.update(cx, |display_map, cx| {
 1517            let snapshot = display_map.snapshot(cx);
 1518            clone.display_map.update(cx, |display_map, cx| {
 1519                display_map.set_state(&snapshot, cx);
 1520            });
 1521        });
 1522        clone.folds_did_change(cx);
 1523        clone.selections.clone_state(&self.selections);
 1524        clone.scroll_manager.clone_state(&self.scroll_manager);
 1525        clone.searchable = self.searchable;
 1526        clone.read_only = self.read_only;
 1527        clone
 1528    }
 1529
 1530    pub fn new(
 1531        mode: EditorMode,
 1532        buffer: Entity<MultiBuffer>,
 1533        project: Option<Entity<Project>>,
 1534        window: &mut Window,
 1535        cx: &mut Context<Self>,
 1536    ) -> Self {
 1537        Editor::new_internal(mode, buffer, project, None, window, cx)
 1538    }
 1539
 1540    fn new_internal(
 1541        mode: EditorMode,
 1542        buffer: Entity<MultiBuffer>,
 1543        project: Option<Entity<Project>>,
 1544        display_map: Option<Entity<DisplayMap>>,
 1545        window: &mut Window,
 1546        cx: &mut Context<Self>,
 1547    ) -> Self {
 1548        debug_assert!(
 1549            display_map.is_none() || mode.is_minimap(),
 1550            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1551        );
 1552
 1553        let full_mode = mode.is_full();
 1554        let diagnostics_max_severity = if full_mode {
 1555            EditorSettings::get_global(cx)
 1556                .diagnostics_max_severity
 1557                .unwrap_or(DiagnosticSeverity::Hint)
 1558        } else {
 1559            DiagnosticSeverity::Off
 1560        };
 1561        let style = window.text_style();
 1562        let font_size = style.font_size.to_pixels(window.rem_size());
 1563        let editor = cx.entity().downgrade();
 1564        let fold_placeholder = FoldPlaceholder {
 1565            constrain_width: true,
 1566            render: Arc::new(move |fold_id, fold_range, cx| {
 1567                let editor = editor.clone();
 1568                div()
 1569                    .id(fold_id)
 1570                    .bg(cx.theme().colors().ghost_element_background)
 1571                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1572                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1573                    .rounded_xs()
 1574                    .size_full()
 1575                    .cursor_pointer()
 1576                    .child("")
 1577                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1578                    .on_click(move |_, _window, cx| {
 1579                        editor
 1580                            .update(cx, |editor, cx| {
 1581                                editor.unfold_ranges(
 1582                                    &[fold_range.start..fold_range.end],
 1583                                    true,
 1584                                    false,
 1585                                    cx,
 1586                                );
 1587                                cx.stop_propagation();
 1588                            })
 1589                            .ok();
 1590                    })
 1591                    .into_any()
 1592            }),
 1593            merge_adjacent: true,
 1594            ..FoldPlaceholder::default()
 1595        };
 1596        let display_map = display_map.unwrap_or_else(|| {
 1597            cx.new(|cx| {
 1598                DisplayMap::new(
 1599                    buffer.clone(),
 1600                    style.font(),
 1601                    font_size,
 1602                    None,
 1603                    FILE_HEADER_HEIGHT,
 1604                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1605                    fold_placeholder,
 1606                    diagnostics_max_severity,
 1607                    cx,
 1608                )
 1609            })
 1610        });
 1611
 1612        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1613
 1614        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1615
 1616        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1617            .then(|| language_settings::SoftWrap::None);
 1618
 1619        let mut project_subscriptions = Vec::new();
 1620        if mode.is_full() {
 1621            if let Some(project) = project.as_ref() {
 1622                project_subscriptions.push(cx.subscribe_in(
 1623                    project,
 1624                    window,
 1625                    |editor, _, event, window, cx| match event {
 1626                        project::Event::RefreshCodeLens => {
 1627                            // we always query lens with actions, without storing them, always refreshing them
 1628                        }
 1629                        project::Event::RefreshInlayHints => {
 1630                            editor
 1631                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1632                        }
 1633                        project::Event::SnippetEdit(id, snippet_edits) => {
 1634                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1635                                let focus_handle = editor.focus_handle(cx);
 1636                                if focus_handle.is_focused(window) {
 1637                                    let snapshot = buffer.read(cx).snapshot();
 1638                                    for (range, snippet) in snippet_edits {
 1639                                        let editor_range =
 1640                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1641                                        editor
 1642                                            .insert_snippet(
 1643                                                &[editor_range],
 1644                                                snippet.clone(),
 1645                                                window,
 1646                                                cx,
 1647                                            )
 1648                                            .ok();
 1649                                    }
 1650                                }
 1651                            }
 1652                        }
 1653                        _ => {}
 1654                    },
 1655                ));
 1656                if let Some(task_inventory) = project
 1657                    .read(cx)
 1658                    .task_store()
 1659                    .read(cx)
 1660                    .task_inventory()
 1661                    .cloned()
 1662                {
 1663                    project_subscriptions.push(cx.observe_in(
 1664                        &task_inventory,
 1665                        window,
 1666                        |editor, _, window, cx| {
 1667                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1668                        },
 1669                    ));
 1670                };
 1671
 1672                project_subscriptions.push(cx.subscribe_in(
 1673                    &project.read(cx).breakpoint_store(),
 1674                    window,
 1675                    |editor, _, event, window, cx| match event {
 1676                        BreakpointStoreEvent::ClearDebugLines => {
 1677                            editor.clear_row_highlights::<ActiveDebugLine>();
 1678                            editor.refresh_inline_values(cx);
 1679                        }
 1680                        BreakpointStoreEvent::SetDebugLine => {
 1681                            if editor.go_to_active_debug_line(window, cx) {
 1682                                cx.stop_propagation();
 1683                            }
 1684
 1685                            editor.refresh_inline_values(cx);
 1686                        }
 1687                        _ => {}
 1688                    },
 1689                ));
 1690            }
 1691        }
 1692
 1693        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1694
 1695        let inlay_hint_settings =
 1696            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1697        let focus_handle = cx.focus_handle();
 1698        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1699            .detach();
 1700        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1701            .detach();
 1702        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1703            .detach();
 1704        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1705            .detach();
 1706
 1707        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1708            Some(false)
 1709        } else {
 1710            None
 1711        };
 1712
 1713        let breakpoint_store = match (&mode, project.as_ref()) {
 1714            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1715            _ => None,
 1716        };
 1717
 1718        let mut code_action_providers = Vec::new();
 1719        let mut load_uncommitted_diff = None;
 1720        if let Some(project) = project.clone() {
 1721            load_uncommitted_diff = Some(
 1722                update_uncommitted_diff_for_buffer(
 1723                    cx.entity(),
 1724                    &project,
 1725                    buffer.read(cx).all_buffers(),
 1726                    buffer.clone(),
 1727                    cx,
 1728                )
 1729                .shared(),
 1730            );
 1731            code_action_providers.push(Rc::new(project) as Rc<_>);
 1732        }
 1733
 1734        let mut this = Self {
 1735            focus_handle,
 1736            show_cursor_when_unfocused: false,
 1737            last_focused_descendant: None,
 1738            buffer: buffer.clone(),
 1739            display_map: display_map.clone(),
 1740            selections,
 1741            scroll_manager: ScrollManager::new(cx),
 1742            columnar_selection_tail: None,
 1743            add_selections_state: None,
 1744            select_next_state: None,
 1745            select_prev_state: None,
 1746            selection_history: SelectionHistory::default(),
 1747            autoclose_regions: Vec::new(),
 1748            snippet_stack: InvalidationStack::default(),
 1749            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1750            ime_transaction: None,
 1751            active_diagnostics: ActiveDiagnostic::None,
 1752            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1753            inline_diagnostics_update: Task::ready(()),
 1754            inline_diagnostics: Vec::new(),
 1755            soft_wrap_mode_override,
 1756            diagnostics_max_severity,
 1757            hard_wrap: None,
 1758            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1759            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1760            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1761            project,
 1762            blink_manager: blink_manager.clone(),
 1763            show_local_selections: true,
 1764            show_scrollbars: full_mode,
 1765            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1766            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1767            show_gutter: mode.is_full(),
 1768            show_line_numbers: None,
 1769            use_relative_line_numbers: None,
 1770            disable_expand_excerpt_buttons: false,
 1771            show_git_diff_gutter: None,
 1772            show_code_actions: None,
 1773            show_runnables: None,
 1774            show_breakpoints: None,
 1775            show_wrap_guides: None,
 1776            show_indent_guides,
 1777            placeholder_text: None,
 1778            highlight_order: 0,
 1779            highlighted_rows: HashMap::default(),
 1780            background_highlights: TreeMap::default(),
 1781            gutter_highlights: TreeMap::default(),
 1782            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1783            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1784            nav_history: None,
 1785            context_menu: RefCell::new(None),
 1786            context_menu_options: None,
 1787            mouse_context_menu: None,
 1788            completion_tasks: Vec::new(),
 1789            inline_blame_popover: None,
 1790            signature_help_state: SignatureHelpState::default(),
 1791            auto_signature_help: None,
 1792            find_all_references_task_sources: Vec::new(),
 1793            next_completion_id: 0,
 1794            next_inlay_id: 0,
 1795            code_action_providers,
 1796            available_code_actions: None,
 1797            code_actions_task: None,
 1798            quick_selection_highlight_task: None,
 1799            debounced_selection_highlight_task: None,
 1800            document_highlights_task: None,
 1801            linked_editing_range_task: None,
 1802            pending_rename: None,
 1803            searchable: true,
 1804            cursor_shape: EditorSettings::get_global(cx)
 1805                .cursor_shape
 1806                .unwrap_or_default(),
 1807            current_line_highlight: None,
 1808            autoindent_mode: Some(AutoindentMode::EachLine),
 1809            collapse_matches: false,
 1810            workspace: None,
 1811            input_enabled: true,
 1812            use_modal_editing: mode.is_full(),
 1813            read_only: mode.is_minimap(),
 1814            use_autoclose: true,
 1815            use_auto_surround: true,
 1816            auto_replace_emoji_shortcode: false,
 1817            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1818            leader_id: None,
 1819            remote_id: None,
 1820            hover_state: HoverState::default(),
 1821            pending_mouse_down: None,
 1822            hovered_link_state: None,
 1823            edit_prediction_provider: None,
 1824            active_inline_completion: None,
 1825            stale_inline_completion_in_menu: None,
 1826            edit_prediction_preview: EditPredictionPreview::Inactive {
 1827                released_too_fast: false,
 1828            },
 1829            inline_diagnostics_enabled: mode.is_full(),
 1830            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1831            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1832
 1833            gutter_hovered: false,
 1834            pixel_position_of_newest_cursor: None,
 1835            last_bounds: None,
 1836            last_position_map: None,
 1837            expect_bounds_change: None,
 1838            gutter_dimensions: GutterDimensions::default(),
 1839            style: None,
 1840            show_cursor_names: false,
 1841            hovered_cursors: HashMap::default(),
 1842            next_editor_action_id: EditorActionId::default(),
 1843            editor_actions: Rc::default(),
 1844            inline_completions_hidden_for_vim_mode: false,
 1845            show_inline_completions_override: None,
 1846            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1847            edit_prediction_settings: EditPredictionSettings::Disabled,
 1848            edit_prediction_indent_conflict: false,
 1849            edit_prediction_requires_modifier_in_indent_conflict: true,
 1850            custom_context_menu: None,
 1851            show_git_blame_gutter: false,
 1852            show_git_blame_inline: false,
 1853            show_selection_menu: None,
 1854            show_git_blame_inline_delay_task: None,
 1855            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1856            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1857            serialize_dirty_buffers: !mode.is_minimap()
 1858                && ProjectSettings::get_global(cx)
 1859                    .session
 1860                    .restore_unsaved_buffers,
 1861            blame: None,
 1862            blame_subscription: None,
 1863            tasks: BTreeMap::default(),
 1864
 1865            breakpoint_store,
 1866            gutter_breakpoint_indicator: (None, None),
 1867            _subscriptions: vec![
 1868                cx.observe(&buffer, Self::on_buffer_changed),
 1869                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1870                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1871                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1872                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1873                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1874                cx.observe_window_activation(window, |editor, window, cx| {
 1875                    let active = window.is_window_active();
 1876                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1877                        if active {
 1878                            blink_manager.enable(cx);
 1879                        } else {
 1880                            blink_manager.disable(cx);
 1881                        }
 1882                    });
 1883                }),
 1884            ],
 1885            tasks_update_task: None,
 1886            linked_edit_ranges: Default::default(),
 1887            in_project_search: false,
 1888            previous_search_ranges: None,
 1889            breadcrumb_header: None,
 1890            focused_block: None,
 1891            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1892            addons: HashMap::default(),
 1893            registered_buffers: HashMap::default(),
 1894            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1895            selection_mark_mode: false,
 1896            toggle_fold_multiple_buffers: Task::ready(()),
 1897            serialize_selections: Task::ready(()),
 1898            serialize_folds: Task::ready(()),
 1899            text_style_refinement: None,
 1900            load_diff_task: load_uncommitted_diff,
 1901            temporary_diff_override: false,
 1902            mouse_cursor_hidden: false,
 1903            minimap: None,
 1904            hide_mouse_mode: EditorSettings::get_global(cx)
 1905                .hide_mouse
 1906                .unwrap_or_default(),
 1907            change_list: ChangeList::new(),
 1908            mode,
 1909        };
 1910        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1911            this._subscriptions
 1912                .push(cx.observe(breakpoints, |_, _, cx| {
 1913                    cx.notify();
 1914                }));
 1915        }
 1916        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1917        this._subscriptions.extend(project_subscriptions);
 1918
 1919        this._subscriptions.push(cx.subscribe_in(
 1920            &cx.entity(),
 1921            window,
 1922            |editor, _, e: &EditorEvent, window, cx| match e {
 1923                EditorEvent::ScrollPositionChanged { local, .. } => {
 1924                    if *local {
 1925                        let new_anchor = editor.scroll_manager.anchor();
 1926                        let snapshot = editor.snapshot(window, cx);
 1927                        editor.update_restoration_data(cx, move |data| {
 1928                            data.scroll_position = (
 1929                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1930                                new_anchor.offset,
 1931                            );
 1932                        });
 1933                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1934                        editor.inline_blame_popover.take();
 1935                    }
 1936                }
 1937                EditorEvent::Edited { .. } => {
 1938                    if !vim_enabled(cx) {
 1939                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1940                        let pop_state = editor
 1941                            .change_list
 1942                            .last()
 1943                            .map(|previous| {
 1944                                previous.len() == selections.len()
 1945                                    && previous.iter().enumerate().all(|(ix, p)| {
 1946                                        p.to_display_point(&map).row()
 1947                                            == selections[ix].head().row()
 1948                                    })
 1949                            })
 1950                            .unwrap_or(false);
 1951                        let new_positions = selections
 1952                            .into_iter()
 1953                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1954                            .collect();
 1955                        editor
 1956                            .change_list
 1957                            .push_to_change_list(pop_state, new_positions);
 1958                    }
 1959                }
 1960                _ => (),
 1961            },
 1962        ));
 1963
 1964        if let Some(dap_store) = this
 1965            .project
 1966            .as_ref()
 1967            .map(|project| project.read(cx).dap_store())
 1968        {
 1969            let weak_editor = cx.weak_entity();
 1970
 1971            this._subscriptions
 1972                .push(
 1973                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1974                        let session_entity = cx.entity();
 1975                        weak_editor
 1976                            .update(cx, |editor, cx| {
 1977                                editor._subscriptions.push(
 1978                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1979                                );
 1980                            })
 1981                            .ok();
 1982                    }),
 1983                );
 1984
 1985            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1986                this._subscriptions
 1987                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1988            }
 1989        }
 1990
 1991        this.end_selection(window, cx);
 1992        this.scroll_manager.show_scrollbars(window, cx);
 1993        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1994
 1995        if full_mode {
 1996            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1997            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1998
 1999            if this.git_blame_inline_enabled {
 2000                this.start_git_blame_inline(false, window, cx);
 2001            }
 2002
 2003            this.go_to_active_debug_line(window, cx);
 2004
 2005            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2006                if let Some(project) = this.project.as_ref() {
 2007                    let handle = project.update(cx, |project, cx| {
 2008                        project.register_buffer_with_language_servers(&buffer, cx)
 2009                    });
 2010                    this.registered_buffers
 2011                        .insert(buffer.read(cx).remote_id(), handle);
 2012                }
 2013            }
 2014
 2015            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2016        }
 2017
 2018        this.report_editor_event("Editor Opened", None, cx);
 2019        this
 2020    }
 2021
 2022    pub fn deploy_mouse_context_menu(
 2023        &mut self,
 2024        position: gpui::Point<Pixels>,
 2025        context_menu: Entity<ContextMenu>,
 2026        window: &mut Window,
 2027        cx: &mut Context<Self>,
 2028    ) {
 2029        self.mouse_context_menu = Some(MouseContextMenu::new(
 2030            self,
 2031            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2032            context_menu,
 2033            window,
 2034            cx,
 2035        ));
 2036    }
 2037
 2038    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2039        self.mouse_context_menu
 2040            .as_ref()
 2041            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2042    }
 2043
 2044    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2045        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2046    }
 2047
 2048    fn key_context_internal(
 2049        &self,
 2050        has_active_edit_prediction: bool,
 2051        window: &Window,
 2052        cx: &App,
 2053    ) -> KeyContext {
 2054        let mut key_context = KeyContext::new_with_defaults();
 2055        key_context.add("Editor");
 2056        let mode = match self.mode {
 2057            EditorMode::SingleLine { .. } => "single_line",
 2058            EditorMode::AutoHeight { .. } => "auto_height",
 2059            EditorMode::Minimap { .. } => "minimap",
 2060            EditorMode::Full { .. } => "full",
 2061        };
 2062
 2063        if EditorSettings::jupyter_enabled(cx) {
 2064            key_context.add("jupyter");
 2065        }
 2066
 2067        key_context.set("mode", mode);
 2068        if self.pending_rename.is_some() {
 2069            key_context.add("renaming");
 2070        }
 2071
 2072        match self.context_menu.borrow().as_ref() {
 2073            Some(CodeContextMenu::Completions(_)) => {
 2074                key_context.add("menu");
 2075                key_context.add("showing_completions");
 2076            }
 2077            Some(CodeContextMenu::CodeActions(_)) => {
 2078                key_context.add("menu");
 2079                key_context.add("showing_code_actions")
 2080            }
 2081            None => {}
 2082        }
 2083
 2084        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2085        if !self.focus_handle(cx).contains_focused(window, cx)
 2086            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2087        {
 2088            for addon in self.addons.values() {
 2089                addon.extend_key_context(&mut key_context, cx)
 2090            }
 2091        }
 2092
 2093        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2094            if let Some(extension) = singleton_buffer
 2095                .read(cx)
 2096                .file()
 2097                .and_then(|file| file.path().extension()?.to_str())
 2098            {
 2099                key_context.set("extension", extension.to_string());
 2100            }
 2101        } else {
 2102            key_context.add("multibuffer");
 2103        }
 2104
 2105        if has_active_edit_prediction {
 2106            if self.edit_prediction_in_conflict() {
 2107                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2108            } else {
 2109                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2110                key_context.add("copilot_suggestion");
 2111            }
 2112        }
 2113
 2114        if self.selection_mark_mode {
 2115            key_context.add("selection_mode");
 2116        }
 2117
 2118        key_context
 2119    }
 2120
 2121    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2122        self.mouse_cursor_hidden = match origin {
 2123            HideMouseCursorOrigin::TypingAction => {
 2124                matches!(
 2125                    self.hide_mouse_mode,
 2126                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2127                )
 2128            }
 2129            HideMouseCursorOrigin::MovementAction => {
 2130                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2131            }
 2132        };
 2133    }
 2134
 2135    pub fn edit_prediction_in_conflict(&self) -> bool {
 2136        if !self.show_edit_predictions_in_menu() {
 2137            return false;
 2138        }
 2139
 2140        let showing_completions = self
 2141            .context_menu
 2142            .borrow()
 2143            .as_ref()
 2144            .map_or(false, |context| {
 2145                matches!(context, CodeContextMenu::Completions(_))
 2146            });
 2147
 2148        showing_completions
 2149            || self.edit_prediction_requires_modifier()
 2150            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2151            // bindings to insert tab characters.
 2152            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2153    }
 2154
 2155    pub fn accept_edit_prediction_keybind(
 2156        &self,
 2157        window: &Window,
 2158        cx: &App,
 2159    ) -> AcceptEditPredictionBinding {
 2160        let key_context = self.key_context_internal(true, window, cx);
 2161        let in_conflict = self.edit_prediction_in_conflict();
 2162
 2163        AcceptEditPredictionBinding(
 2164            window
 2165                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2166                .into_iter()
 2167                .filter(|binding| {
 2168                    !in_conflict
 2169                        || binding
 2170                            .keystrokes()
 2171                            .first()
 2172                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2173                })
 2174                .rev()
 2175                .min_by_key(|binding| {
 2176                    binding
 2177                        .keystrokes()
 2178                        .first()
 2179                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2180                }),
 2181        )
 2182    }
 2183
 2184    pub fn new_file(
 2185        workspace: &mut Workspace,
 2186        _: &workspace::NewFile,
 2187        window: &mut Window,
 2188        cx: &mut Context<Workspace>,
 2189    ) {
 2190        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2191            "Failed to create buffer",
 2192            window,
 2193            cx,
 2194            |e, _, _| match e.error_code() {
 2195                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2196                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2197                e.error_tag("required").unwrap_or("the latest version")
 2198            )),
 2199                _ => None,
 2200            },
 2201        );
 2202    }
 2203
 2204    pub fn new_in_workspace(
 2205        workspace: &mut Workspace,
 2206        window: &mut Window,
 2207        cx: &mut Context<Workspace>,
 2208    ) -> Task<Result<Entity<Editor>>> {
 2209        let project = workspace.project().clone();
 2210        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2211
 2212        cx.spawn_in(window, async move |workspace, cx| {
 2213            let buffer = create.await?;
 2214            workspace.update_in(cx, |workspace, window, cx| {
 2215                let editor =
 2216                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2217                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2218                editor
 2219            })
 2220        })
 2221    }
 2222
 2223    fn new_file_vertical(
 2224        workspace: &mut Workspace,
 2225        _: &workspace::NewFileSplitVertical,
 2226        window: &mut Window,
 2227        cx: &mut Context<Workspace>,
 2228    ) {
 2229        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2230    }
 2231
 2232    fn new_file_horizontal(
 2233        workspace: &mut Workspace,
 2234        _: &workspace::NewFileSplitHorizontal,
 2235        window: &mut Window,
 2236        cx: &mut Context<Workspace>,
 2237    ) {
 2238        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2239    }
 2240
 2241    fn new_file_in_direction(
 2242        workspace: &mut Workspace,
 2243        direction: SplitDirection,
 2244        window: &mut Window,
 2245        cx: &mut Context<Workspace>,
 2246    ) {
 2247        let project = workspace.project().clone();
 2248        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2249
 2250        cx.spawn_in(window, async move |workspace, cx| {
 2251            let buffer = create.await?;
 2252            workspace.update_in(cx, move |workspace, window, cx| {
 2253                workspace.split_item(
 2254                    direction,
 2255                    Box::new(
 2256                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2257                    ),
 2258                    window,
 2259                    cx,
 2260                )
 2261            })?;
 2262            anyhow::Ok(())
 2263        })
 2264        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2265            match e.error_code() {
 2266                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2267                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2268                e.error_tag("required").unwrap_or("the latest version")
 2269            )),
 2270                _ => None,
 2271            }
 2272        });
 2273    }
 2274
 2275    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2276        self.leader_id
 2277    }
 2278
 2279    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2280        &self.buffer
 2281    }
 2282
 2283    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2284        self.workspace.as_ref()?.0.upgrade()
 2285    }
 2286
 2287    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2288        self.buffer().read(cx).title(cx)
 2289    }
 2290
 2291    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2292        let git_blame_gutter_max_author_length = self
 2293            .render_git_blame_gutter(cx)
 2294            .then(|| {
 2295                if let Some(blame) = self.blame.as_ref() {
 2296                    let max_author_length =
 2297                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2298                    Some(max_author_length)
 2299                } else {
 2300                    None
 2301                }
 2302            })
 2303            .flatten();
 2304
 2305        EditorSnapshot {
 2306            mode: self.mode.clone(),
 2307            show_gutter: self.show_gutter,
 2308            show_line_numbers: self.show_line_numbers,
 2309            show_git_diff_gutter: self.show_git_diff_gutter,
 2310            show_code_actions: self.show_code_actions,
 2311            show_runnables: self.show_runnables,
 2312            show_breakpoints: self.show_breakpoints,
 2313            git_blame_gutter_max_author_length,
 2314            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2315            scroll_anchor: self.scroll_manager.anchor(),
 2316            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2317            placeholder_text: self.placeholder_text.clone(),
 2318            is_focused: self.focus_handle.is_focused(window),
 2319            current_line_highlight: self
 2320                .current_line_highlight
 2321                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2322            gutter_hovered: self.gutter_hovered,
 2323        }
 2324    }
 2325
 2326    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2327        self.buffer.read(cx).language_at(point, cx)
 2328    }
 2329
 2330    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2331        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2332    }
 2333
 2334    pub fn active_excerpt(
 2335        &self,
 2336        cx: &App,
 2337    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2338        self.buffer
 2339            .read(cx)
 2340            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2341    }
 2342
 2343    pub fn mode(&self) -> &EditorMode {
 2344        &self.mode
 2345    }
 2346
 2347    pub fn set_mode(&mut self, mode: EditorMode) {
 2348        self.mode = mode;
 2349    }
 2350
 2351    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2352        self.collaboration_hub.as_deref()
 2353    }
 2354
 2355    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2356        self.collaboration_hub = Some(hub);
 2357    }
 2358
 2359    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2360        self.in_project_search = in_project_search;
 2361    }
 2362
 2363    pub fn set_custom_context_menu(
 2364        &mut self,
 2365        f: impl 'static
 2366        + Fn(
 2367            &mut Self,
 2368            DisplayPoint,
 2369            &mut Window,
 2370            &mut Context<Self>,
 2371        ) -> Option<Entity<ui::ContextMenu>>,
 2372    ) {
 2373        self.custom_context_menu = Some(Box::new(f))
 2374    }
 2375
 2376    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2377        self.completion_provider = provider;
 2378    }
 2379
 2380    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2381        self.semantics_provider.clone()
 2382    }
 2383
 2384    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2385        self.semantics_provider = provider;
 2386    }
 2387
 2388    pub fn set_edit_prediction_provider<T>(
 2389        &mut self,
 2390        provider: Option<Entity<T>>,
 2391        window: &mut Window,
 2392        cx: &mut Context<Self>,
 2393    ) where
 2394        T: EditPredictionProvider,
 2395    {
 2396        self.edit_prediction_provider =
 2397            provider.map(|provider| RegisteredInlineCompletionProvider {
 2398                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2399                    if this.focus_handle.is_focused(window) {
 2400                        this.update_visible_inline_completion(window, cx);
 2401                    }
 2402                }),
 2403                provider: Arc::new(provider),
 2404            });
 2405        self.update_edit_prediction_settings(cx);
 2406        self.refresh_inline_completion(false, false, window, cx);
 2407    }
 2408
 2409    pub fn placeholder_text(&self) -> Option<&str> {
 2410        self.placeholder_text.as_deref()
 2411    }
 2412
 2413    pub fn set_placeholder_text(
 2414        &mut self,
 2415        placeholder_text: impl Into<Arc<str>>,
 2416        cx: &mut Context<Self>,
 2417    ) {
 2418        let placeholder_text = Some(placeholder_text.into());
 2419        if self.placeholder_text != placeholder_text {
 2420            self.placeholder_text = placeholder_text;
 2421            cx.notify();
 2422        }
 2423    }
 2424
 2425    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2426        self.cursor_shape = cursor_shape;
 2427
 2428        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2429        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2430
 2431        cx.notify();
 2432    }
 2433
 2434    pub fn set_current_line_highlight(
 2435        &mut self,
 2436        current_line_highlight: Option<CurrentLineHighlight>,
 2437    ) {
 2438        self.current_line_highlight = current_line_highlight;
 2439    }
 2440
 2441    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2442        self.collapse_matches = collapse_matches;
 2443    }
 2444
 2445    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2446        let buffers = self.buffer.read(cx).all_buffers();
 2447        let Some(project) = self.project.as_ref() else {
 2448            return;
 2449        };
 2450        project.update(cx, |project, cx| {
 2451            for buffer in buffers {
 2452                self.registered_buffers
 2453                    .entry(buffer.read(cx).remote_id())
 2454                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2455            }
 2456        })
 2457    }
 2458
 2459    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2460        if self.collapse_matches {
 2461            return range.start..range.start;
 2462        }
 2463        range.clone()
 2464    }
 2465
 2466    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2467        if self.display_map.read(cx).clip_at_line_ends != clip {
 2468            self.display_map
 2469                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2470        }
 2471    }
 2472
 2473    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2474        self.input_enabled = input_enabled;
 2475    }
 2476
 2477    pub fn set_inline_completions_hidden_for_vim_mode(
 2478        &mut self,
 2479        hidden: bool,
 2480        window: &mut Window,
 2481        cx: &mut Context<Self>,
 2482    ) {
 2483        if hidden != self.inline_completions_hidden_for_vim_mode {
 2484            self.inline_completions_hidden_for_vim_mode = hidden;
 2485            if hidden {
 2486                self.update_visible_inline_completion(window, cx);
 2487            } else {
 2488                self.refresh_inline_completion(true, false, window, cx);
 2489            }
 2490        }
 2491    }
 2492
 2493    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2494        self.menu_inline_completions_policy = value;
 2495    }
 2496
 2497    pub fn set_autoindent(&mut self, autoindent: bool) {
 2498        if autoindent {
 2499            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2500        } else {
 2501            self.autoindent_mode = None;
 2502        }
 2503    }
 2504
 2505    pub fn read_only(&self, cx: &App) -> bool {
 2506        self.read_only || self.buffer.read(cx).read_only()
 2507    }
 2508
 2509    pub fn set_read_only(&mut self, read_only: bool) {
 2510        self.read_only = read_only;
 2511    }
 2512
 2513    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2514        self.use_autoclose = autoclose;
 2515    }
 2516
 2517    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2518        self.use_auto_surround = auto_surround;
 2519    }
 2520
 2521    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2522        self.auto_replace_emoji_shortcode = auto_replace;
 2523    }
 2524
 2525    pub fn toggle_edit_predictions(
 2526        &mut self,
 2527        _: &ToggleEditPrediction,
 2528        window: &mut Window,
 2529        cx: &mut Context<Self>,
 2530    ) {
 2531        if self.show_inline_completions_override.is_some() {
 2532            self.set_show_edit_predictions(None, window, cx);
 2533        } else {
 2534            let show_edit_predictions = !self.edit_predictions_enabled();
 2535            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2536        }
 2537    }
 2538
 2539    pub fn set_show_edit_predictions(
 2540        &mut self,
 2541        show_edit_predictions: Option<bool>,
 2542        window: &mut Window,
 2543        cx: &mut Context<Self>,
 2544    ) {
 2545        self.show_inline_completions_override = show_edit_predictions;
 2546        self.update_edit_prediction_settings(cx);
 2547
 2548        if let Some(false) = show_edit_predictions {
 2549            self.discard_inline_completion(false, cx);
 2550        } else {
 2551            self.refresh_inline_completion(false, true, window, cx);
 2552        }
 2553    }
 2554
 2555    fn inline_completions_disabled_in_scope(
 2556        &self,
 2557        buffer: &Entity<Buffer>,
 2558        buffer_position: language::Anchor,
 2559        cx: &App,
 2560    ) -> bool {
 2561        let snapshot = buffer.read(cx).snapshot();
 2562        let settings = snapshot.settings_at(buffer_position, cx);
 2563
 2564        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2565            return false;
 2566        };
 2567
 2568        scope.override_name().map_or(false, |scope_name| {
 2569            settings
 2570                .edit_predictions_disabled_in
 2571                .iter()
 2572                .any(|s| s == scope_name)
 2573        })
 2574    }
 2575
 2576    pub fn set_use_modal_editing(&mut self, to: bool) {
 2577        self.use_modal_editing = to;
 2578    }
 2579
 2580    pub fn use_modal_editing(&self) -> bool {
 2581        self.use_modal_editing
 2582    }
 2583
 2584    fn selections_did_change(
 2585        &mut self,
 2586        local: bool,
 2587        old_cursor_position: &Anchor,
 2588        show_completions: bool,
 2589        window: &mut Window,
 2590        cx: &mut Context<Self>,
 2591    ) {
 2592        window.invalidate_character_coordinates();
 2593
 2594        // Copy selections to primary selection buffer
 2595        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2596        if local {
 2597            let selections = self.selections.all::<usize>(cx);
 2598            let buffer_handle = self.buffer.read(cx).read(cx);
 2599
 2600            let mut text = String::new();
 2601            for (index, selection) in selections.iter().enumerate() {
 2602                let text_for_selection = buffer_handle
 2603                    .text_for_range(selection.start..selection.end)
 2604                    .collect::<String>();
 2605
 2606                text.push_str(&text_for_selection);
 2607                if index != selections.len() - 1 {
 2608                    text.push('\n');
 2609                }
 2610            }
 2611
 2612            if !text.is_empty() {
 2613                cx.write_to_primary(ClipboardItem::new_string(text));
 2614            }
 2615        }
 2616
 2617        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2618            self.buffer.update(cx, |buffer, cx| {
 2619                buffer.set_active_selections(
 2620                    &self.selections.disjoint_anchors(),
 2621                    self.selections.line_mode,
 2622                    self.cursor_shape,
 2623                    cx,
 2624                )
 2625            });
 2626        }
 2627        let display_map = self
 2628            .display_map
 2629            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2630        let buffer = &display_map.buffer_snapshot;
 2631        self.add_selections_state = None;
 2632        self.select_next_state = None;
 2633        self.select_prev_state = None;
 2634        self.select_syntax_node_history.try_clear();
 2635        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2636        self.snippet_stack
 2637            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2638        self.take_rename(false, window, cx);
 2639
 2640        let new_cursor_position = self.selections.newest_anchor().head();
 2641
 2642        self.push_to_nav_history(
 2643            *old_cursor_position,
 2644            Some(new_cursor_position.to_point(buffer)),
 2645            false,
 2646            cx,
 2647        );
 2648
 2649        if local {
 2650            let new_cursor_position = self.selections.newest_anchor().head();
 2651            let mut context_menu = self.context_menu.borrow_mut();
 2652            let completion_menu = match context_menu.as_ref() {
 2653                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2654                _ => {
 2655                    *context_menu = None;
 2656                    None
 2657                }
 2658            };
 2659            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2660                if !self.registered_buffers.contains_key(&buffer_id) {
 2661                    if let Some(project) = self.project.as_ref() {
 2662                        project.update(cx, |project, cx| {
 2663                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2664                                return;
 2665                            };
 2666                            self.registered_buffers.insert(
 2667                                buffer_id,
 2668                                project.register_buffer_with_language_servers(&buffer, cx),
 2669                            );
 2670                        })
 2671                    }
 2672                }
 2673            }
 2674
 2675            if let Some(completion_menu) = completion_menu {
 2676                let cursor_position = new_cursor_position.to_offset(buffer);
 2677                let (word_range, kind) =
 2678                    buffer.surrounding_word(completion_menu.initial_position, true);
 2679                if kind == Some(CharKind::Word)
 2680                    && word_range.to_inclusive().contains(&cursor_position)
 2681                {
 2682                    let mut completion_menu = completion_menu.clone();
 2683                    drop(context_menu);
 2684
 2685                    let query = Self::completion_query(buffer, cursor_position);
 2686                    cx.spawn(async move |this, cx| {
 2687                        completion_menu
 2688                            .filter(query.as_deref(), cx.background_executor().clone())
 2689                            .await;
 2690
 2691                        this.update(cx, |this, cx| {
 2692                            let mut context_menu = this.context_menu.borrow_mut();
 2693                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2694                            else {
 2695                                return;
 2696                            };
 2697
 2698                            if menu.id > completion_menu.id {
 2699                                return;
 2700                            }
 2701
 2702                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2703                            drop(context_menu);
 2704                            cx.notify();
 2705                        })
 2706                    })
 2707                    .detach();
 2708
 2709                    if show_completions {
 2710                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2711                    }
 2712                } else {
 2713                    drop(context_menu);
 2714                    self.hide_context_menu(window, cx);
 2715                }
 2716            } else {
 2717                drop(context_menu);
 2718            }
 2719
 2720            hide_hover(self, cx);
 2721
 2722            if old_cursor_position.to_display_point(&display_map).row()
 2723                != new_cursor_position.to_display_point(&display_map).row()
 2724            {
 2725                self.available_code_actions.take();
 2726            }
 2727            self.refresh_code_actions(window, cx);
 2728            self.refresh_document_highlights(cx);
 2729            self.refresh_selected_text_highlights(false, window, cx);
 2730            refresh_matching_bracket_highlights(self, window, cx);
 2731            self.update_visible_inline_completion(window, cx);
 2732            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2733            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2734            self.inline_blame_popover.take();
 2735            if self.git_blame_inline_enabled {
 2736                self.start_inline_blame_timer(window, cx);
 2737            }
 2738        }
 2739
 2740        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2741        cx.emit(EditorEvent::SelectionsChanged { local });
 2742
 2743        let selections = &self.selections.disjoint;
 2744        if selections.len() == 1 {
 2745            cx.emit(SearchEvent::ActiveMatchChanged)
 2746        }
 2747        if local {
 2748            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2749                let inmemory_selections = selections
 2750                    .iter()
 2751                    .map(|s| {
 2752                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2753                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2754                    })
 2755                    .collect();
 2756                self.update_restoration_data(cx, |data| {
 2757                    data.selections = inmemory_selections;
 2758                });
 2759
 2760                if WorkspaceSettings::get(None, cx).restore_on_startup
 2761                    != RestoreOnStartupBehavior::None
 2762                {
 2763                    if let Some(workspace_id) =
 2764                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2765                    {
 2766                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2767                        let selections = selections.clone();
 2768                        let background_executor = cx.background_executor().clone();
 2769                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2770                        self.serialize_selections = cx.background_spawn(async move {
 2771                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2772                    let db_selections = selections
 2773                        .iter()
 2774                        .map(|selection| {
 2775                            (
 2776                                selection.start.to_offset(&snapshot),
 2777                                selection.end.to_offset(&snapshot),
 2778                            )
 2779                        })
 2780                        .collect();
 2781
 2782                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2783                        .await
 2784                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2785                        .log_err();
 2786                });
 2787                    }
 2788                }
 2789            }
 2790        }
 2791
 2792        cx.notify();
 2793    }
 2794
 2795    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2796        use text::ToOffset as _;
 2797        use text::ToPoint as _;
 2798
 2799        if self.mode.is_minimap()
 2800            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2801        {
 2802            return;
 2803        }
 2804
 2805        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2806            return;
 2807        };
 2808
 2809        let snapshot = singleton.read(cx).snapshot();
 2810        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2811            let display_snapshot = display_map.snapshot(cx);
 2812
 2813            display_snapshot
 2814                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2815                .map(|fold| {
 2816                    fold.range.start.text_anchor.to_point(&snapshot)
 2817                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2818                })
 2819                .collect()
 2820        });
 2821        self.update_restoration_data(cx, |data| {
 2822            data.folds = inmemory_folds;
 2823        });
 2824
 2825        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2826            return;
 2827        };
 2828        let background_executor = cx.background_executor().clone();
 2829        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2830        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2831            display_map
 2832                .snapshot(cx)
 2833                .folds_in_range(0..snapshot.len())
 2834                .map(|fold| {
 2835                    (
 2836                        fold.range.start.text_anchor.to_offset(&snapshot),
 2837                        fold.range.end.text_anchor.to_offset(&snapshot),
 2838                    )
 2839                })
 2840                .collect()
 2841        });
 2842        self.serialize_folds = cx.background_spawn(async move {
 2843            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2844            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2845                .await
 2846                .with_context(|| {
 2847                    format!(
 2848                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2849                    )
 2850                })
 2851                .log_err();
 2852        });
 2853    }
 2854
 2855    pub fn sync_selections(
 2856        &mut self,
 2857        other: Entity<Editor>,
 2858        cx: &mut Context<Self>,
 2859    ) -> gpui::Subscription {
 2860        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2861        self.selections.change_with(cx, |selections| {
 2862            selections.select_anchors(other_selections);
 2863        });
 2864
 2865        let other_subscription =
 2866            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2867                EditorEvent::SelectionsChanged { local: true } => {
 2868                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2869                    if other_selections.is_empty() {
 2870                        return;
 2871                    }
 2872                    this.selections.change_with(cx, |selections| {
 2873                        selections.select_anchors(other_selections);
 2874                    });
 2875                }
 2876                _ => {}
 2877            });
 2878
 2879        let this_subscription =
 2880            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2881                EditorEvent::SelectionsChanged { local: true } => {
 2882                    let these_selections = this.selections.disjoint.to_vec();
 2883                    if these_selections.is_empty() {
 2884                        return;
 2885                    }
 2886                    other.update(cx, |other_editor, cx| {
 2887                        other_editor.selections.change_with(cx, |selections| {
 2888                            selections.select_anchors(these_selections);
 2889                        })
 2890                    });
 2891                }
 2892                _ => {}
 2893            });
 2894
 2895        Subscription::join(other_subscription, this_subscription)
 2896    }
 2897
 2898    pub fn change_selections<R>(
 2899        &mut self,
 2900        autoscroll: Option<Autoscroll>,
 2901        window: &mut Window,
 2902        cx: &mut Context<Self>,
 2903        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2904    ) -> R {
 2905        self.change_selections_inner(autoscroll, true, window, cx, change)
 2906    }
 2907
 2908    fn change_selections_inner<R>(
 2909        &mut self,
 2910        autoscroll: Option<Autoscroll>,
 2911        request_completions: bool,
 2912        window: &mut Window,
 2913        cx: &mut Context<Self>,
 2914        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2915    ) -> R {
 2916        let old_cursor_position = self.selections.newest_anchor().head();
 2917        self.push_to_selection_history();
 2918
 2919        let (changed, result) = self.selections.change_with(cx, change);
 2920
 2921        if changed {
 2922            if let Some(autoscroll) = autoscroll {
 2923                self.request_autoscroll(autoscroll, cx);
 2924            }
 2925            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2926
 2927            if self.should_open_signature_help_automatically(
 2928                &old_cursor_position,
 2929                self.signature_help_state.backspace_pressed(),
 2930                cx,
 2931            ) {
 2932                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2933            }
 2934            self.signature_help_state.set_backspace_pressed(false);
 2935        }
 2936
 2937        result
 2938    }
 2939
 2940    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2941    where
 2942        I: IntoIterator<Item = (Range<S>, T)>,
 2943        S: ToOffset,
 2944        T: Into<Arc<str>>,
 2945    {
 2946        if self.read_only(cx) {
 2947            return;
 2948        }
 2949
 2950        self.buffer
 2951            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2952    }
 2953
 2954    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2955    where
 2956        I: IntoIterator<Item = (Range<S>, T)>,
 2957        S: ToOffset,
 2958        T: Into<Arc<str>>,
 2959    {
 2960        if self.read_only(cx) {
 2961            return;
 2962        }
 2963
 2964        self.buffer.update(cx, |buffer, cx| {
 2965            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2966        });
 2967    }
 2968
 2969    pub fn edit_with_block_indent<I, S, T>(
 2970        &mut self,
 2971        edits: I,
 2972        original_indent_columns: Vec<Option<u32>>,
 2973        cx: &mut Context<Self>,
 2974    ) where
 2975        I: IntoIterator<Item = (Range<S>, T)>,
 2976        S: ToOffset,
 2977        T: Into<Arc<str>>,
 2978    {
 2979        if self.read_only(cx) {
 2980            return;
 2981        }
 2982
 2983        self.buffer.update(cx, |buffer, cx| {
 2984            buffer.edit(
 2985                edits,
 2986                Some(AutoindentMode::Block {
 2987                    original_indent_columns,
 2988                }),
 2989                cx,
 2990            )
 2991        });
 2992    }
 2993
 2994    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2995        self.hide_context_menu(window, cx);
 2996
 2997        match phase {
 2998            SelectPhase::Begin {
 2999                position,
 3000                add,
 3001                click_count,
 3002            } => self.begin_selection(position, add, click_count, window, cx),
 3003            SelectPhase::BeginColumnar {
 3004                position,
 3005                goal_column,
 3006                reset,
 3007            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3008            SelectPhase::Extend {
 3009                position,
 3010                click_count,
 3011            } => self.extend_selection(position, click_count, window, cx),
 3012            SelectPhase::Update {
 3013                position,
 3014                goal_column,
 3015                scroll_delta,
 3016            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3017            SelectPhase::End => self.end_selection(window, cx),
 3018        }
 3019    }
 3020
 3021    fn extend_selection(
 3022        &mut self,
 3023        position: DisplayPoint,
 3024        click_count: usize,
 3025        window: &mut Window,
 3026        cx: &mut Context<Self>,
 3027    ) {
 3028        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3029        let tail = self.selections.newest::<usize>(cx).tail();
 3030        self.begin_selection(position, false, click_count, window, cx);
 3031
 3032        let position = position.to_offset(&display_map, Bias::Left);
 3033        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3034
 3035        let mut pending_selection = self
 3036            .selections
 3037            .pending_anchor()
 3038            .expect("extend_selection not called with pending selection");
 3039        if position >= tail {
 3040            pending_selection.start = tail_anchor;
 3041        } else {
 3042            pending_selection.end = tail_anchor;
 3043            pending_selection.reversed = true;
 3044        }
 3045
 3046        let mut pending_mode = self.selections.pending_mode().unwrap();
 3047        match &mut pending_mode {
 3048            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3049            _ => {}
 3050        }
 3051
 3052        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3053
 3054        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3055            s.set_pending(pending_selection, pending_mode)
 3056        });
 3057    }
 3058
 3059    fn begin_selection(
 3060        &mut self,
 3061        position: DisplayPoint,
 3062        add: bool,
 3063        click_count: usize,
 3064        window: &mut Window,
 3065        cx: &mut Context<Self>,
 3066    ) {
 3067        if !self.focus_handle.is_focused(window) {
 3068            self.last_focused_descendant = None;
 3069            window.focus(&self.focus_handle);
 3070        }
 3071
 3072        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3073        let buffer = &display_map.buffer_snapshot;
 3074        let position = display_map.clip_point(position, Bias::Left);
 3075
 3076        let start;
 3077        let end;
 3078        let mode;
 3079        let mut auto_scroll;
 3080        match click_count {
 3081            1 => {
 3082                start = buffer.anchor_before(position.to_point(&display_map));
 3083                end = start;
 3084                mode = SelectMode::Character;
 3085                auto_scroll = true;
 3086            }
 3087            2 => {
 3088                let range = movement::surrounding_word(&display_map, position);
 3089                start = buffer.anchor_before(range.start.to_point(&display_map));
 3090                end = buffer.anchor_before(range.end.to_point(&display_map));
 3091                mode = SelectMode::Word(start..end);
 3092                auto_scroll = true;
 3093            }
 3094            3 => {
 3095                let position = display_map
 3096                    .clip_point(position, Bias::Left)
 3097                    .to_point(&display_map);
 3098                let line_start = display_map.prev_line_boundary(position).0;
 3099                let next_line_start = buffer.clip_point(
 3100                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3101                    Bias::Left,
 3102                );
 3103                start = buffer.anchor_before(line_start);
 3104                end = buffer.anchor_before(next_line_start);
 3105                mode = SelectMode::Line(start..end);
 3106                auto_scroll = true;
 3107            }
 3108            _ => {
 3109                start = buffer.anchor_before(0);
 3110                end = buffer.anchor_before(buffer.len());
 3111                mode = SelectMode::All;
 3112                auto_scroll = false;
 3113            }
 3114        }
 3115        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3116
 3117        let point_to_delete: Option<usize> = {
 3118            let selected_points: Vec<Selection<Point>> =
 3119                self.selections.disjoint_in_range(start..end, cx);
 3120
 3121            if !add || click_count > 1 {
 3122                None
 3123            } else if !selected_points.is_empty() {
 3124                Some(selected_points[0].id)
 3125            } else {
 3126                let clicked_point_already_selected =
 3127                    self.selections.disjoint.iter().find(|selection| {
 3128                        selection.start.to_point(buffer) == start.to_point(buffer)
 3129                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3130                    });
 3131
 3132                clicked_point_already_selected.map(|selection| selection.id)
 3133            }
 3134        };
 3135
 3136        let selections_count = self.selections.count();
 3137
 3138        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3139            if let Some(point_to_delete) = point_to_delete {
 3140                s.delete(point_to_delete);
 3141
 3142                if selections_count == 1 {
 3143                    s.set_pending_anchor_range(start..end, mode);
 3144                }
 3145            } else {
 3146                if !add {
 3147                    s.clear_disjoint();
 3148                }
 3149
 3150                s.set_pending_anchor_range(start..end, mode);
 3151            }
 3152        });
 3153    }
 3154
 3155    fn begin_columnar_selection(
 3156        &mut self,
 3157        position: DisplayPoint,
 3158        goal_column: u32,
 3159        reset: bool,
 3160        window: &mut Window,
 3161        cx: &mut Context<Self>,
 3162    ) {
 3163        if !self.focus_handle.is_focused(window) {
 3164            self.last_focused_descendant = None;
 3165            window.focus(&self.focus_handle);
 3166        }
 3167
 3168        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3169
 3170        if reset {
 3171            let pointer_position = display_map
 3172                .buffer_snapshot
 3173                .anchor_before(position.to_point(&display_map));
 3174
 3175            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3176                s.clear_disjoint();
 3177                s.set_pending_anchor_range(
 3178                    pointer_position..pointer_position,
 3179                    SelectMode::Character,
 3180                );
 3181            });
 3182        }
 3183
 3184        let tail = self.selections.newest::<Point>(cx).tail();
 3185        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3186
 3187        if !reset {
 3188            self.select_columns(
 3189                tail.to_display_point(&display_map),
 3190                position,
 3191                goal_column,
 3192                &display_map,
 3193                window,
 3194                cx,
 3195            );
 3196        }
 3197    }
 3198
 3199    fn update_selection(
 3200        &mut self,
 3201        position: DisplayPoint,
 3202        goal_column: u32,
 3203        scroll_delta: gpui::Point<f32>,
 3204        window: &mut Window,
 3205        cx: &mut Context<Self>,
 3206    ) {
 3207        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3208
 3209        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3210            let tail = tail.to_display_point(&display_map);
 3211            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3212        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3213            let buffer = self.buffer.read(cx).snapshot(cx);
 3214            let head;
 3215            let tail;
 3216            let mode = self.selections.pending_mode().unwrap();
 3217            match &mode {
 3218                SelectMode::Character => {
 3219                    head = position.to_point(&display_map);
 3220                    tail = pending.tail().to_point(&buffer);
 3221                }
 3222                SelectMode::Word(original_range) => {
 3223                    let original_display_range = original_range.start.to_display_point(&display_map)
 3224                        ..original_range.end.to_display_point(&display_map);
 3225                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3226                        ..original_display_range.end.to_point(&display_map);
 3227                    if movement::is_inside_word(&display_map, position)
 3228                        || original_display_range.contains(&position)
 3229                    {
 3230                        let word_range = movement::surrounding_word(&display_map, position);
 3231                        if word_range.start < original_display_range.start {
 3232                            head = word_range.start.to_point(&display_map);
 3233                        } else {
 3234                            head = word_range.end.to_point(&display_map);
 3235                        }
 3236                    } else {
 3237                        head = position.to_point(&display_map);
 3238                    }
 3239
 3240                    if head <= original_buffer_range.start {
 3241                        tail = original_buffer_range.end;
 3242                    } else {
 3243                        tail = original_buffer_range.start;
 3244                    }
 3245                }
 3246                SelectMode::Line(original_range) => {
 3247                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3248
 3249                    let position = display_map
 3250                        .clip_point(position, Bias::Left)
 3251                        .to_point(&display_map);
 3252                    let line_start = display_map.prev_line_boundary(position).0;
 3253                    let next_line_start = buffer.clip_point(
 3254                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3255                        Bias::Left,
 3256                    );
 3257
 3258                    if line_start < original_range.start {
 3259                        head = line_start
 3260                    } else {
 3261                        head = next_line_start
 3262                    }
 3263
 3264                    if head <= original_range.start {
 3265                        tail = original_range.end;
 3266                    } else {
 3267                        tail = original_range.start;
 3268                    }
 3269                }
 3270                SelectMode::All => {
 3271                    return;
 3272                }
 3273            };
 3274
 3275            if head < tail {
 3276                pending.start = buffer.anchor_before(head);
 3277                pending.end = buffer.anchor_before(tail);
 3278                pending.reversed = true;
 3279            } else {
 3280                pending.start = buffer.anchor_before(tail);
 3281                pending.end = buffer.anchor_before(head);
 3282                pending.reversed = false;
 3283            }
 3284
 3285            self.change_selections(None, window, cx, |s| {
 3286                s.set_pending(pending, mode);
 3287            });
 3288        } else {
 3289            log::error!("update_selection dispatched with no pending selection");
 3290            return;
 3291        }
 3292
 3293        self.apply_scroll_delta(scroll_delta, window, cx);
 3294        cx.notify();
 3295    }
 3296
 3297    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3298        self.columnar_selection_tail.take();
 3299        if self.selections.pending_anchor().is_some() {
 3300            let selections = self.selections.all::<usize>(cx);
 3301            self.change_selections(None, window, cx, |s| {
 3302                s.select(selections);
 3303                s.clear_pending();
 3304            });
 3305        }
 3306    }
 3307
 3308    fn select_columns(
 3309        &mut self,
 3310        tail: DisplayPoint,
 3311        head: DisplayPoint,
 3312        goal_column: u32,
 3313        display_map: &DisplaySnapshot,
 3314        window: &mut Window,
 3315        cx: &mut Context<Self>,
 3316    ) {
 3317        let start_row = cmp::min(tail.row(), head.row());
 3318        let end_row = cmp::max(tail.row(), head.row());
 3319        let start_column = cmp::min(tail.column(), goal_column);
 3320        let end_column = cmp::max(tail.column(), goal_column);
 3321        let reversed = start_column < tail.column();
 3322
 3323        let selection_ranges = (start_row.0..=end_row.0)
 3324            .map(DisplayRow)
 3325            .filter_map(|row| {
 3326                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3327                    let start = display_map
 3328                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3329                        .to_point(display_map);
 3330                    let end = display_map
 3331                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3332                        .to_point(display_map);
 3333                    if reversed {
 3334                        Some(end..start)
 3335                    } else {
 3336                        Some(start..end)
 3337                    }
 3338                } else {
 3339                    None
 3340                }
 3341            })
 3342            .collect::<Vec<_>>();
 3343
 3344        self.change_selections(None, window, cx, |s| {
 3345            s.select_ranges(selection_ranges);
 3346        });
 3347        cx.notify();
 3348    }
 3349
 3350    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3351        self.selections
 3352            .all_adjusted(cx)
 3353            .iter()
 3354            .any(|selection| !selection.is_empty())
 3355    }
 3356
 3357    pub fn has_pending_nonempty_selection(&self) -> bool {
 3358        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3359            Some(Selection { start, end, .. }) => start != end,
 3360            None => false,
 3361        };
 3362
 3363        pending_nonempty_selection
 3364            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3365    }
 3366
 3367    pub fn has_pending_selection(&self) -> bool {
 3368        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3369    }
 3370
 3371    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3372        self.selection_mark_mode = false;
 3373
 3374        if self.clear_expanded_diff_hunks(cx) {
 3375            cx.notify();
 3376            return;
 3377        }
 3378        if self.dismiss_menus_and_popups(true, window, cx) {
 3379            return;
 3380        }
 3381
 3382        if self.mode.is_full()
 3383            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3384        {
 3385            return;
 3386        }
 3387
 3388        cx.propagate();
 3389    }
 3390
 3391    pub fn dismiss_menus_and_popups(
 3392        &mut self,
 3393        is_user_requested: bool,
 3394        window: &mut Window,
 3395        cx: &mut Context<Self>,
 3396    ) -> bool {
 3397        if self.take_rename(false, window, cx).is_some() {
 3398            return true;
 3399        }
 3400
 3401        if hide_hover(self, cx) {
 3402            return true;
 3403        }
 3404
 3405        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3406            return true;
 3407        }
 3408
 3409        if self.hide_context_menu(window, cx).is_some() {
 3410            return true;
 3411        }
 3412
 3413        if self.mouse_context_menu.take().is_some() {
 3414            return true;
 3415        }
 3416
 3417        if is_user_requested && self.discard_inline_completion(true, cx) {
 3418            return true;
 3419        }
 3420
 3421        if self.snippet_stack.pop().is_some() {
 3422            return true;
 3423        }
 3424
 3425        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3426            self.dismiss_diagnostics(cx);
 3427            return true;
 3428        }
 3429
 3430        false
 3431    }
 3432
 3433    fn linked_editing_ranges_for(
 3434        &self,
 3435        selection: Range<text::Anchor>,
 3436        cx: &App,
 3437    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3438        if self.linked_edit_ranges.is_empty() {
 3439            return None;
 3440        }
 3441        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3442            selection.end.buffer_id.and_then(|end_buffer_id| {
 3443                if selection.start.buffer_id != Some(end_buffer_id) {
 3444                    return None;
 3445                }
 3446                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3447                let snapshot = buffer.read(cx).snapshot();
 3448                self.linked_edit_ranges
 3449                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3450                    .map(|ranges| (ranges, snapshot, buffer))
 3451            })?;
 3452        use text::ToOffset as TO;
 3453        // find offset from the start of current range to current cursor position
 3454        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3455
 3456        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3457        let start_difference = start_offset - start_byte_offset;
 3458        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3459        let end_difference = end_offset - start_byte_offset;
 3460        // Current range has associated linked ranges.
 3461        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3462        for range in linked_ranges.iter() {
 3463            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3464            let end_offset = start_offset + end_difference;
 3465            let start_offset = start_offset + start_difference;
 3466            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3467                continue;
 3468            }
 3469            if self.selections.disjoint_anchor_ranges().any(|s| {
 3470                if s.start.buffer_id != selection.start.buffer_id
 3471                    || s.end.buffer_id != selection.end.buffer_id
 3472                {
 3473                    return false;
 3474                }
 3475                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3476                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3477            }) {
 3478                continue;
 3479            }
 3480            let start = buffer_snapshot.anchor_after(start_offset);
 3481            let end = buffer_snapshot.anchor_after(end_offset);
 3482            linked_edits
 3483                .entry(buffer.clone())
 3484                .or_default()
 3485                .push(start..end);
 3486        }
 3487        Some(linked_edits)
 3488    }
 3489
 3490    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3491        let text: Arc<str> = text.into();
 3492
 3493        if self.read_only(cx) {
 3494            return;
 3495        }
 3496
 3497        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3498
 3499        let selections = self.selections.all_adjusted(cx);
 3500        let mut bracket_inserted = false;
 3501        let mut edits = Vec::new();
 3502        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3503        let mut new_selections = Vec::with_capacity(selections.len());
 3504        let mut new_autoclose_regions = Vec::new();
 3505        let snapshot = self.buffer.read(cx).read(cx);
 3506        let mut clear_linked_edit_ranges = false;
 3507
 3508        for (selection, autoclose_region) in
 3509            self.selections_with_autoclose_regions(selections, &snapshot)
 3510        {
 3511            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3512                // Determine if the inserted text matches the opening or closing
 3513                // bracket of any of this language's bracket pairs.
 3514                let mut bracket_pair = None;
 3515                let mut is_bracket_pair_start = false;
 3516                let mut is_bracket_pair_end = false;
 3517                if !text.is_empty() {
 3518                    let mut bracket_pair_matching_end = None;
 3519                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3520                    //  and they are removing the character that triggered IME popup.
 3521                    for (pair, enabled) in scope.brackets() {
 3522                        if !pair.close && !pair.surround {
 3523                            continue;
 3524                        }
 3525
 3526                        if enabled && pair.start.ends_with(text.as_ref()) {
 3527                            let prefix_len = pair.start.len() - text.len();
 3528                            let preceding_text_matches_prefix = prefix_len == 0
 3529                                || (selection.start.column >= (prefix_len as u32)
 3530                                    && snapshot.contains_str_at(
 3531                                        Point::new(
 3532                                            selection.start.row,
 3533                                            selection.start.column - (prefix_len as u32),
 3534                                        ),
 3535                                        &pair.start[..prefix_len],
 3536                                    ));
 3537                            if preceding_text_matches_prefix {
 3538                                bracket_pair = Some(pair.clone());
 3539                                is_bracket_pair_start = true;
 3540                                break;
 3541                            }
 3542                        }
 3543                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3544                        {
 3545                            // take first bracket pair matching end, but don't break in case a later bracket
 3546                            // pair matches start
 3547                            bracket_pair_matching_end = Some(pair.clone());
 3548                        }
 3549                    }
 3550                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3551                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3552                        is_bracket_pair_end = true;
 3553                    }
 3554                }
 3555
 3556                if let Some(bracket_pair) = bracket_pair {
 3557                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3558                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3559                    let auto_surround =
 3560                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3561                    if selection.is_empty() {
 3562                        if is_bracket_pair_start {
 3563                            // If the inserted text is a suffix of an opening bracket and the
 3564                            // selection is preceded by the rest of the opening bracket, then
 3565                            // insert the closing bracket.
 3566                            let following_text_allows_autoclose = snapshot
 3567                                .chars_at(selection.start)
 3568                                .next()
 3569                                .map_or(true, |c| scope.should_autoclose_before(c));
 3570
 3571                            let preceding_text_allows_autoclose = selection.start.column == 0
 3572                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3573                                    true,
 3574                                    |c| {
 3575                                        bracket_pair.start != bracket_pair.end
 3576                                            || !snapshot
 3577                                                .char_classifier_at(selection.start)
 3578                                                .is_word(c)
 3579                                    },
 3580                                );
 3581
 3582                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3583                                && bracket_pair.start.len() == 1
 3584                            {
 3585                                let target = bracket_pair.start.chars().next().unwrap();
 3586                                let current_line_count = snapshot
 3587                                    .reversed_chars_at(selection.start)
 3588                                    .take_while(|&c| c != '\n')
 3589                                    .filter(|&c| c == target)
 3590                                    .count();
 3591                                current_line_count % 2 == 1
 3592                            } else {
 3593                                false
 3594                            };
 3595
 3596                            if autoclose
 3597                                && bracket_pair.close
 3598                                && following_text_allows_autoclose
 3599                                && preceding_text_allows_autoclose
 3600                                && !is_closing_quote
 3601                            {
 3602                                let anchor = snapshot.anchor_before(selection.end);
 3603                                new_selections.push((selection.map(|_| anchor), text.len()));
 3604                                new_autoclose_regions.push((
 3605                                    anchor,
 3606                                    text.len(),
 3607                                    selection.id,
 3608                                    bracket_pair.clone(),
 3609                                ));
 3610                                edits.push((
 3611                                    selection.range(),
 3612                                    format!("{}{}", text, bracket_pair.end).into(),
 3613                                ));
 3614                                bracket_inserted = true;
 3615                                continue;
 3616                            }
 3617                        }
 3618
 3619                        if let Some(region) = autoclose_region {
 3620                            // If the selection is followed by an auto-inserted closing bracket,
 3621                            // then don't insert that closing bracket again; just move the selection
 3622                            // past the closing bracket.
 3623                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3624                                && text.as_ref() == region.pair.end.as_str();
 3625                            if should_skip {
 3626                                let anchor = snapshot.anchor_after(selection.end);
 3627                                new_selections
 3628                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3629                                continue;
 3630                            }
 3631                        }
 3632
 3633                        let always_treat_brackets_as_autoclosed = snapshot
 3634                            .language_settings_at(selection.start, cx)
 3635                            .always_treat_brackets_as_autoclosed;
 3636                        if always_treat_brackets_as_autoclosed
 3637                            && is_bracket_pair_end
 3638                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3639                        {
 3640                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3641                            // and the inserted text is a closing bracket and the selection is followed
 3642                            // by the closing bracket then move the selection past the closing bracket.
 3643                            let anchor = snapshot.anchor_after(selection.end);
 3644                            new_selections.push((selection.map(|_| anchor), text.len()));
 3645                            continue;
 3646                        }
 3647                    }
 3648                    // If an opening bracket is 1 character long and is typed while
 3649                    // text is selected, then surround that text with the bracket pair.
 3650                    else if auto_surround
 3651                        && bracket_pair.surround
 3652                        && is_bracket_pair_start
 3653                        && bracket_pair.start.chars().count() == 1
 3654                    {
 3655                        edits.push((selection.start..selection.start, text.clone()));
 3656                        edits.push((
 3657                            selection.end..selection.end,
 3658                            bracket_pair.end.as_str().into(),
 3659                        ));
 3660                        bracket_inserted = true;
 3661                        new_selections.push((
 3662                            Selection {
 3663                                id: selection.id,
 3664                                start: snapshot.anchor_after(selection.start),
 3665                                end: snapshot.anchor_before(selection.end),
 3666                                reversed: selection.reversed,
 3667                                goal: selection.goal,
 3668                            },
 3669                            0,
 3670                        ));
 3671                        continue;
 3672                    }
 3673                }
 3674            }
 3675
 3676            if self.auto_replace_emoji_shortcode
 3677                && selection.is_empty()
 3678                && text.as_ref().ends_with(':')
 3679            {
 3680                if let Some(possible_emoji_short_code) =
 3681                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3682                {
 3683                    if !possible_emoji_short_code.is_empty() {
 3684                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3685                            let emoji_shortcode_start = Point::new(
 3686                                selection.start.row,
 3687                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3688                            );
 3689
 3690                            // Remove shortcode from buffer
 3691                            edits.push((
 3692                                emoji_shortcode_start..selection.start,
 3693                                "".to_string().into(),
 3694                            ));
 3695                            new_selections.push((
 3696                                Selection {
 3697                                    id: selection.id,
 3698                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3699                                    end: snapshot.anchor_before(selection.start),
 3700                                    reversed: selection.reversed,
 3701                                    goal: selection.goal,
 3702                                },
 3703                                0,
 3704                            ));
 3705
 3706                            // Insert emoji
 3707                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3708                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3709                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3710
 3711                            continue;
 3712                        }
 3713                    }
 3714                }
 3715            }
 3716
 3717            // If not handling any auto-close operation, then just replace the selected
 3718            // text with the given input and move the selection to the end of the
 3719            // newly inserted text.
 3720            let anchor = snapshot.anchor_after(selection.end);
 3721            if !self.linked_edit_ranges.is_empty() {
 3722                let start_anchor = snapshot.anchor_before(selection.start);
 3723
 3724                let is_word_char = text.chars().next().map_or(true, |char| {
 3725                    let classifier = snapshot
 3726                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3727                        .ignore_punctuation(true);
 3728                    classifier.is_word(char)
 3729                });
 3730
 3731                if is_word_char {
 3732                    if let Some(ranges) = self
 3733                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3734                    {
 3735                        for (buffer, edits) in ranges {
 3736                            linked_edits
 3737                                .entry(buffer.clone())
 3738                                .or_default()
 3739                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3740                        }
 3741                    }
 3742                } else {
 3743                    clear_linked_edit_ranges = true;
 3744                }
 3745            }
 3746
 3747            new_selections.push((selection.map(|_| anchor), 0));
 3748            edits.push((selection.start..selection.end, text.clone()));
 3749        }
 3750
 3751        drop(snapshot);
 3752
 3753        self.transact(window, cx, |this, window, cx| {
 3754            if clear_linked_edit_ranges {
 3755                this.linked_edit_ranges.clear();
 3756            }
 3757            let initial_buffer_versions =
 3758                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3759
 3760            this.buffer.update(cx, |buffer, cx| {
 3761                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3762            });
 3763            for (buffer, edits) in linked_edits {
 3764                buffer.update(cx, |buffer, cx| {
 3765                    let snapshot = buffer.snapshot();
 3766                    let edits = edits
 3767                        .into_iter()
 3768                        .map(|(range, text)| {
 3769                            use text::ToPoint as TP;
 3770                            let end_point = TP::to_point(&range.end, &snapshot);
 3771                            let start_point = TP::to_point(&range.start, &snapshot);
 3772                            (start_point..end_point, text)
 3773                        })
 3774                        .sorted_by_key(|(range, _)| range.start);
 3775                    buffer.edit(edits, None, cx);
 3776                })
 3777            }
 3778            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3779            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3780            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3781            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3782                .zip(new_selection_deltas)
 3783                .map(|(selection, delta)| Selection {
 3784                    id: selection.id,
 3785                    start: selection.start + delta,
 3786                    end: selection.end + delta,
 3787                    reversed: selection.reversed,
 3788                    goal: SelectionGoal::None,
 3789                })
 3790                .collect::<Vec<_>>();
 3791
 3792            let mut i = 0;
 3793            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3794                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3795                let start = map.buffer_snapshot.anchor_before(position);
 3796                let end = map.buffer_snapshot.anchor_after(position);
 3797                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3798                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3799                        Ordering::Less => i += 1,
 3800                        Ordering::Greater => break,
 3801                        Ordering::Equal => {
 3802                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3803                                Ordering::Less => i += 1,
 3804                                Ordering::Equal => break,
 3805                                Ordering::Greater => break,
 3806                            }
 3807                        }
 3808                    }
 3809                }
 3810                this.autoclose_regions.insert(
 3811                    i,
 3812                    AutocloseRegion {
 3813                        selection_id,
 3814                        range: start..end,
 3815                        pair,
 3816                    },
 3817                );
 3818            }
 3819
 3820            let had_active_inline_completion = this.has_active_inline_completion();
 3821            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3822                s.select(new_selections)
 3823            });
 3824
 3825            if !bracket_inserted {
 3826                if let Some(on_type_format_task) =
 3827                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3828                {
 3829                    on_type_format_task.detach_and_log_err(cx);
 3830                }
 3831            }
 3832
 3833            let editor_settings = EditorSettings::get_global(cx);
 3834            if bracket_inserted
 3835                && (editor_settings.auto_signature_help
 3836                    || editor_settings.show_signature_help_after_edits)
 3837            {
 3838                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3839            }
 3840
 3841            let trigger_in_words =
 3842                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3843            if this.hard_wrap.is_some() {
 3844                let latest: Range<Point> = this.selections.newest(cx).range();
 3845                if latest.is_empty()
 3846                    && this
 3847                        .buffer()
 3848                        .read(cx)
 3849                        .snapshot(cx)
 3850                        .line_len(MultiBufferRow(latest.start.row))
 3851                        == latest.start.column
 3852                {
 3853                    this.rewrap_impl(
 3854                        RewrapOptions {
 3855                            override_language_settings: true,
 3856                            preserve_existing_whitespace: true,
 3857                        },
 3858                        cx,
 3859                    )
 3860                }
 3861            }
 3862            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3863            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3864            this.refresh_inline_completion(true, false, window, cx);
 3865            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3866        });
 3867    }
 3868
 3869    fn find_possible_emoji_shortcode_at_position(
 3870        snapshot: &MultiBufferSnapshot,
 3871        position: Point,
 3872    ) -> Option<String> {
 3873        let mut chars = Vec::new();
 3874        let mut found_colon = false;
 3875        for char in snapshot.reversed_chars_at(position).take(100) {
 3876            // Found a possible emoji shortcode in the middle of the buffer
 3877            if found_colon {
 3878                if char.is_whitespace() {
 3879                    chars.reverse();
 3880                    return Some(chars.iter().collect());
 3881                }
 3882                // If the previous character is not a whitespace, we are in the middle of a word
 3883                // and we only want to complete the shortcode if the word is made up of other emojis
 3884                let mut containing_word = String::new();
 3885                for ch in snapshot
 3886                    .reversed_chars_at(position)
 3887                    .skip(chars.len() + 1)
 3888                    .take(100)
 3889                {
 3890                    if ch.is_whitespace() {
 3891                        break;
 3892                    }
 3893                    containing_word.push(ch);
 3894                }
 3895                let containing_word = containing_word.chars().rev().collect::<String>();
 3896                if util::word_consists_of_emojis(containing_word.as_str()) {
 3897                    chars.reverse();
 3898                    return Some(chars.iter().collect());
 3899                }
 3900            }
 3901
 3902            if char.is_whitespace() || !char.is_ascii() {
 3903                return None;
 3904            }
 3905            if char == ':' {
 3906                found_colon = true;
 3907            } else {
 3908                chars.push(char);
 3909            }
 3910        }
 3911        // Found a possible emoji shortcode at the beginning of the buffer
 3912        chars.reverse();
 3913        Some(chars.iter().collect())
 3914    }
 3915
 3916    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3917        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3918        self.transact(window, cx, |this, window, cx| {
 3919            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3920                let selections = this.selections.all::<usize>(cx);
 3921                let multi_buffer = this.buffer.read(cx);
 3922                let buffer = multi_buffer.snapshot(cx);
 3923                selections
 3924                    .iter()
 3925                    .map(|selection| {
 3926                        let start_point = selection.start.to_point(&buffer);
 3927                        let mut existing_indent =
 3928                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3929                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3930                        let start = selection.start;
 3931                        let end = selection.end;
 3932                        let selection_is_empty = start == end;
 3933                        let language_scope = buffer.language_scope_at(start);
 3934                        let (
 3935                            comment_delimiter,
 3936                            doc_delimiter,
 3937                            insert_extra_newline,
 3938                            indent_on_newline,
 3939                            indent_on_extra_newline,
 3940                        ) = if let Some(language) = &language_scope {
 3941                            let mut insert_extra_newline =
 3942                                insert_extra_newline_brackets(&buffer, start..end, language)
 3943                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3944
 3945                            // Comment extension on newline is allowed only for cursor selections
 3946                            let comment_delimiter = maybe!({
 3947                                if !selection_is_empty {
 3948                                    return None;
 3949                                }
 3950
 3951                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3952                                    return None;
 3953                                }
 3954
 3955                                let delimiters = language.line_comment_prefixes();
 3956                                let max_len_of_delimiter =
 3957                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3958                                let (snapshot, range) =
 3959                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3960
 3961                                let num_of_whitespaces = snapshot
 3962                                    .chars_for_range(range.clone())
 3963                                    .take_while(|c| c.is_whitespace())
 3964                                    .count();
 3965                                let comment_candidate = snapshot
 3966                                    .chars_for_range(range)
 3967                                    .skip(num_of_whitespaces)
 3968                                    .take(max_len_of_delimiter)
 3969                                    .collect::<String>();
 3970                                let (delimiter, trimmed_len) = delimiters
 3971                                    .iter()
 3972                                    .filter_map(|delimiter| {
 3973                                        let prefix = delimiter.trim_end();
 3974                                        if comment_candidate.starts_with(prefix) {
 3975                                            Some((delimiter, prefix.len()))
 3976                                        } else {
 3977                                            None
 3978                                        }
 3979                                    })
 3980                                    .max_by_key(|(_, len)| *len)?;
 3981
 3982                                let cursor_is_placed_after_comment_marker =
 3983                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 3984                                if cursor_is_placed_after_comment_marker {
 3985                                    Some(delimiter.clone())
 3986                                } else {
 3987                                    None
 3988                                }
 3989                            });
 3990
 3991                            let mut indent_on_newline = IndentSize::spaces(0);
 3992                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 3993
 3994                            let doc_delimiter = maybe!({
 3995                                if !selection_is_empty {
 3996                                    return None;
 3997                                }
 3998
 3999                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4000                                    return None;
 4001                                }
 4002
 4003                                let DocumentationConfig {
 4004                                    start: start_tag,
 4005                                    end: end_tag,
 4006                                    prefix: delimiter,
 4007                                    tab_size: len,
 4008                                } = language.documentation()?;
 4009
 4010                                let is_within_block_comment = buffer
 4011                                    .language_scope_at(start_point)
 4012                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4013                                if !is_within_block_comment {
 4014                                    return None;
 4015                                }
 4016
 4017                                let (snapshot, range) =
 4018                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4019
 4020                                let num_of_whitespaces = snapshot
 4021                                    .chars_for_range(range.clone())
 4022                                    .take_while(|c| c.is_whitespace())
 4023                                    .count();
 4024
 4025                                // 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.
 4026                                let column = start_point.column;
 4027                                let cursor_is_after_start_tag = {
 4028                                    let start_tag_len = start_tag.len();
 4029                                    let start_tag_line = snapshot
 4030                                        .chars_for_range(range.clone())
 4031                                        .skip(num_of_whitespaces)
 4032                                        .take(start_tag_len)
 4033                                        .collect::<String>();
 4034                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4035                                        num_of_whitespaces + start_tag_len <= column as usize
 4036                                    } else {
 4037                                        false
 4038                                    }
 4039                                };
 4040
 4041                                let cursor_is_after_delimiter = {
 4042                                    let delimiter_trim = delimiter.trim_end();
 4043                                    let delimiter_line = snapshot
 4044                                        .chars_for_range(range.clone())
 4045                                        .skip(num_of_whitespaces)
 4046                                        .take(delimiter_trim.len())
 4047                                        .collect::<String>();
 4048                                    if delimiter_line.starts_with(delimiter_trim) {
 4049                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4050                                    } else {
 4051                                        false
 4052                                    }
 4053                                };
 4054
 4055                                let cursor_is_before_end_tag_if_exists = {
 4056                                    let mut char_position = 0u32;
 4057                                    let mut end_tag_offset = None;
 4058
 4059                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4060                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4061                                            let chars_before_match =
 4062                                                chunk[..byte_pos].chars().count() as u32;
 4063                                            end_tag_offset =
 4064                                                Some(char_position + chars_before_match);
 4065                                            break 'outer;
 4066                                        }
 4067                                        char_position += chunk.chars().count() as u32;
 4068                                    }
 4069
 4070                                    if let Some(end_tag_offset) = end_tag_offset {
 4071                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4072                                        if cursor_is_after_start_tag {
 4073                                            if cursor_is_before_end_tag {
 4074                                                insert_extra_newline = true;
 4075                                            }
 4076                                            let cursor_is_at_start_of_end_tag =
 4077                                                column == end_tag_offset;
 4078                                            if cursor_is_at_start_of_end_tag {
 4079                                                indent_on_extra_newline.len = (*len).into();
 4080                                            }
 4081                                        }
 4082                                        cursor_is_before_end_tag
 4083                                    } else {
 4084                                        true
 4085                                    }
 4086                                };
 4087
 4088                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4089                                    && cursor_is_before_end_tag_if_exists
 4090                                {
 4091                                    if cursor_is_after_start_tag {
 4092                                        indent_on_newline.len = (*len).into();
 4093                                    }
 4094                                    Some(delimiter.clone())
 4095                                } else {
 4096                                    None
 4097                                }
 4098                            });
 4099
 4100                            (
 4101                                comment_delimiter,
 4102                                doc_delimiter,
 4103                                insert_extra_newline,
 4104                                indent_on_newline,
 4105                                indent_on_extra_newline,
 4106                            )
 4107                        } else {
 4108                            (
 4109                                None,
 4110                                None,
 4111                                false,
 4112                                IndentSize::default(),
 4113                                IndentSize::default(),
 4114                            )
 4115                        };
 4116
 4117                        let prevent_auto_indent = doc_delimiter.is_some();
 4118                        let delimiter = comment_delimiter.or(doc_delimiter);
 4119
 4120                        let capacity_for_delimiter =
 4121                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4122                        let mut new_text = String::with_capacity(
 4123                            1 + capacity_for_delimiter
 4124                                + existing_indent.len as usize
 4125                                + indent_on_newline.len as usize
 4126                                + indent_on_extra_newline.len as usize,
 4127                        );
 4128                        new_text.push('\n');
 4129                        new_text.extend(existing_indent.chars());
 4130                        new_text.extend(indent_on_newline.chars());
 4131
 4132                        if let Some(delimiter) = &delimiter {
 4133                            new_text.push_str(delimiter);
 4134                        }
 4135
 4136                        if insert_extra_newline {
 4137                            new_text.push('\n');
 4138                            new_text.extend(existing_indent.chars());
 4139                            new_text.extend(indent_on_extra_newline.chars());
 4140                        }
 4141
 4142                        let anchor = buffer.anchor_after(end);
 4143                        let new_selection = selection.map(|_| anchor);
 4144                        (
 4145                            ((start..end, new_text), prevent_auto_indent),
 4146                            (insert_extra_newline, new_selection),
 4147                        )
 4148                    })
 4149                    .unzip()
 4150            };
 4151
 4152            let mut auto_indent_edits = Vec::new();
 4153            let mut edits = Vec::new();
 4154            for (edit, prevent_auto_indent) in edits_with_flags {
 4155                if prevent_auto_indent {
 4156                    edits.push(edit);
 4157                } else {
 4158                    auto_indent_edits.push(edit);
 4159                }
 4160            }
 4161            if !edits.is_empty() {
 4162                this.edit(edits, cx);
 4163            }
 4164            if !auto_indent_edits.is_empty() {
 4165                this.edit_with_autoindent(auto_indent_edits, cx);
 4166            }
 4167
 4168            let buffer = this.buffer.read(cx).snapshot(cx);
 4169            let new_selections = selection_info
 4170                .into_iter()
 4171                .map(|(extra_newline_inserted, new_selection)| {
 4172                    let mut cursor = new_selection.end.to_point(&buffer);
 4173                    if extra_newline_inserted {
 4174                        cursor.row -= 1;
 4175                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4176                    }
 4177                    new_selection.map(|_| cursor)
 4178                })
 4179                .collect();
 4180
 4181            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4182                s.select(new_selections)
 4183            });
 4184            this.refresh_inline_completion(true, false, window, cx);
 4185        });
 4186    }
 4187
 4188    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4189        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4190
 4191        let buffer = self.buffer.read(cx);
 4192        let snapshot = buffer.snapshot(cx);
 4193
 4194        let mut edits = Vec::new();
 4195        let mut rows = Vec::new();
 4196
 4197        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4198            let cursor = selection.head();
 4199            let row = cursor.row;
 4200
 4201            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4202
 4203            let newline = "\n".to_string();
 4204            edits.push((start_of_line..start_of_line, newline));
 4205
 4206            rows.push(row + rows_inserted as u32);
 4207        }
 4208
 4209        self.transact(window, cx, |editor, window, cx| {
 4210            editor.edit(edits, cx);
 4211
 4212            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4213                let mut index = 0;
 4214                s.move_cursors_with(|map, _, _| {
 4215                    let row = rows[index];
 4216                    index += 1;
 4217
 4218                    let point = Point::new(row, 0);
 4219                    let boundary = map.next_line_boundary(point).1;
 4220                    let clipped = map.clip_point(boundary, Bias::Left);
 4221
 4222                    (clipped, SelectionGoal::None)
 4223                });
 4224            });
 4225
 4226            let mut indent_edits = Vec::new();
 4227            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4228            for row in rows {
 4229                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4230                for (row, indent) in indents {
 4231                    if indent.len == 0 {
 4232                        continue;
 4233                    }
 4234
 4235                    let text = match indent.kind {
 4236                        IndentKind::Space => " ".repeat(indent.len as usize),
 4237                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4238                    };
 4239                    let point = Point::new(row.0, 0);
 4240                    indent_edits.push((point..point, text));
 4241                }
 4242            }
 4243            editor.edit(indent_edits, cx);
 4244        });
 4245    }
 4246
 4247    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4248        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4249
 4250        let buffer = self.buffer.read(cx);
 4251        let snapshot = buffer.snapshot(cx);
 4252
 4253        let mut edits = Vec::new();
 4254        let mut rows = Vec::new();
 4255        let mut rows_inserted = 0;
 4256
 4257        for selection in self.selections.all_adjusted(cx) {
 4258            let cursor = selection.head();
 4259            let row = cursor.row;
 4260
 4261            let point = Point::new(row + 1, 0);
 4262            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4263
 4264            let newline = "\n".to_string();
 4265            edits.push((start_of_line..start_of_line, newline));
 4266
 4267            rows_inserted += 1;
 4268            rows.push(row + rows_inserted);
 4269        }
 4270
 4271        self.transact(window, cx, |editor, window, cx| {
 4272            editor.edit(edits, cx);
 4273
 4274            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4275                let mut index = 0;
 4276                s.move_cursors_with(|map, _, _| {
 4277                    let row = rows[index];
 4278                    index += 1;
 4279
 4280                    let point = Point::new(row, 0);
 4281                    let boundary = map.next_line_boundary(point).1;
 4282                    let clipped = map.clip_point(boundary, Bias::Left);
 4283
 4284                    (clipped, SelectionGoal::None)
 4285                });
 4286            });
 4287
 4288            let mut indent_edits = Vec::new();
 4289            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4290            for row in rows {
 4291                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4292                for (row, indent) in indents {
 4293                    if indent.len == 0 {
 4294                        continue;
 4295                    }
 4296
 4297                    let text = match indent.kind {
 4298                        IndentKind::Space => " ".repeat(indent.len as usize),
 4299                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4300                    };
 4301                    let point = Point::new(row.0, 0);
 4302                    indent_edits.push((point..point, text));
 4303                }
 4304            }
 4305            editor.edit(indent_edits, cx);
 4306        });
 4307    }
 4308
 4309    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4310        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4311            original_indent_columns: Vec::new(),
 4312        });
 4313        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4314    }
 4315
 4316    fn insert_with_autoindent_mode(
 4317        &mut self,
 4318        text: &str,
 4319        autoindent_mode: Option<AutoindentMode>,
 4320        window: &mut Window,
 4321        cx: &mut Context<Self>,
 4322    ) {
 4323        if self.read_only(cx) {
 4324            return;
 4325        }
 4326
 4327        let text: Arc<str> = text.into();
 4328        self.transact(window, cx, |this, window, cx| {
 4329            let old_selections = this.selections.all_adjusted(cx);
 4330            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4331                let anchors = {
 4332                    let snapshot = buffer.read(cx);
 4333                    old_selections
 4334                        .iter()
 4335                        .map(|s| {
 4336                            let anchor = snapshot.anchor_after(s.head());
 4337                            s.map(|_| anchor)
 4338                        })
 4339                        .collect::<Vec<_>>()
 4340                };
 4341                buffer.edit(
 4342                    old_selections
 4343                        .iter()
 4344                        .map(|s| (s.start..s.end, text.clone())),
 4345                    autoindent_mode,
 4346                    cx,
 4347                );
 4348                anchors
 4349            });
 4350
 4351            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4352                s.select_anchors(selection_anchors);
 4353            });
 4354
 4355            cx.notify();
 4356        });
 4357    }
 4358
 4359    fn trigger_completion_on_input(
 4360        &mut self,
 4361        text: &str,
 4362        trigger_in_words: bool,
 4363        window: &mut Window,
 4364        cx: &mut Context<Self>,
 4365    ) {
 4366        let ignore_completion_provider = self
 4367            .context_menu
 4368            .borrow()
 4369            .as_ref()
 4370            .map(|menu| match menu {
 4371                CodeContextMenu::Completions(completions_menu) => {
 4372                    completions_menu.ignore_completion_provider
 4373                }
 4374                CodeContextMenu::CodeActions(_) => false,
 4375            })
 4376            .unwrap_or(false);
 4377
 4378        if ignore_completion_provider {
 4379            self.show_word_completions(&ShowWordCompletions, window, cx);
 4380        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4381            self.show_completions(
 4382                &ShowCompletions {
 4383                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4384                },
 4385                window,
 4386                cx,
 4387            );
 4388        } else {
 4389            self.hide_context_menu(window, cx);
 4390        }
 4391    }
 4392
 4393    fn is_completion_trigger(
 4394        &self,
 4395        text: &str,
 4396        trigger_in_words: bool,
 4397        cx: &mut Context<Self>,
 4398    ) -> bool {
 4399        let position = self.selections.newest_anchor().head();
 4400        let multibuffer = self.buffer.read(cx);
 4401        let Some(buffer) = position
 4402            .buffer_id
 4403            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4404        else {
 4405            return false;
 4406        };
 4407
 4408        if let Some(completion_provider) = &self.completion_provider {
 4409            completion_provider.is_completion_trigger(
 4410                &buffer,
 4411                position.text_anchor,
 4412                text,
 4413                trigger_in_words,
 4414                cx,
 4415            )
 4416        } else {
 4417            false
 4418        }
 4419    }
 4420
 4421    /// If any empty selections is touching the start of its innermost containing autoclose
 4422    /// region, expand it to select the brackets.
 4423    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4424        let selections = self.selections.all::<usize>(cx);
 4425        let buffer = self.buffer.read(cx).read(cx);
 4426        let new_selections = self
 4427            .selections_with_autoclose_regions(selections, &buffer)
 4428            .map(|(mut selection, region)| {
 4429                if !selection.is_empty() {
 4430                    return selection;
 4431                }
 4432
 4433                if let Some(region) = region {
 4434                    let mut range = region.range.to_offset(&buffer);
 4435                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4436                        range.start -= region.pair.start.len();
 4437                        if buffer.contains_str_at(range.start, &region.pair.start)
 4438                            && buffer.contains_str_at(range.end, &region.pair.end)
 4439                        {
 4440                            range.end += region.pair.end.len();
 4441                            selection.start = range.start;
 4442                            selection.end = range.end;
 4443
 4444                            return selection;
 4445                        }
 4446                    }
 4447                }
 4448
 4449                let always_treat_brackets_as_autoclosed = buffer
 4450                    .language_settings_at(selection.start, cx)
 4451                    .always_treat_brackets_as_autoclosed;
 4452
 4453                if !always_treat_brackets_as_autoclosed {
 4454                    return selection;
 4455                }
 4456
 4457                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4458                    for (pair, enabled) in scope.brackets() {
 4459                        if !enabled || !pair.close {
 4460                            continue;
 4461                        }
 4462
 4463                        if buffer.contains_str_at(selection.start, &pair.end) {
 4464                            let pair_start_len = pair.start.len();
 4465                            if buffer.contains_str_at(
 4466                                selection.start.saturating_sub(pair_start_len),
 4467                                &pair.start,
 4468                            ) {
 4469                                selection.start -= pair_start_len;
 4470                                selection.end += pair.end.len();
 4471
 4472                                return selection;
 4473                            }
 4474                        }
 4475                    }
 4476                }
 4477
 4478                selection
 4479            })
 4480            .collect();
 4481
 4482        drop(buffer);
 4483        self.change_selections(None, window, cx, |selections| {
 4484            selections.select(new_selections)
 4485        });
 4486    }
 4487
 4488    /// Iterate the given selections, and for each one, find the smallest surrounding
 4489    /// autoclose region. This uses the ordering of the selections and the autoclose
 4490    /// regions to avoid repeated comparisons.
 4491    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4492        &'a self,
 4493        selections: impl IntoIterator<Item = Selection<D>>,
 4494        buffer: &'a MultiBufferSnapshot,
 4495    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4496        let mut i = 0;
 4497        let mut regions = self.autoclose_regions.as_slice();
 4498        selections.into_iter().map(move |selection| {
 4499            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4500
 4501            let mut enclosing = None;
 4502            while let Some(pair_state) = regions.get(i) {
 4503                if pair_state.range.end.to_offset(buffer) < range.start {
 4504                    regions = &regions[i + 1..];
 4505                    i = 0;
 4506                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4507                    break;
 4508                } else {
 4509                    if pair_state.selection_id == selection.id {
 4510                        enclosing = Some(pair_state);
 4511                    }
 4512                    i += 1;
 4513                }
 4514            }
 4515
 4516            (selection, enclosing)
 4517        })
 4518    }
 4519
 4520    /// Remove any autoclose regions that no longer contain their selection.
 4521    fn invalidate_autoclose_regions(
 4522        &mut self,
 4523        mut selections: &[Selection<Anchor>],
 4524        buffer: &MultiBufferSnapshot,
 4525    ) {
 4526        self.autoclose_regions.retain(|state| {
 4527            let mut i = 0;
 4528            while let Some(selection) = selections.get(i) {
 4529                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4530                    selections = &selections[1..];
 4531                    continue;
 4532                }
 4533                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4534                    break;
 4535                }
 4536                if selection.id == state.selection_id {
 4537                    return true;
 4538                } else {
 4539                    i += 1;
 4540                }
 4541            }
 4542            false
 4543        });
 4544    }
 4545
 4546    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4547        let offset = position.to_offset(buffer);
 4548        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4549        if offset > word_range.start && kind == Some(CharKind::Word) {
 4550            Some(
 4551                buffer
 4552                    .text_for_range(word_range.start..offset)
 4553                    .collect::<String>(),
 4554            )
 4555        } else {
 4556            None
 4557        }
 4558    }
 4559
 4560    pub fn toggle_inline_values(
 4561        &mut self,
 4562        _: &ToggleInlineValues,
 4563        _: &mut Window,
 4564        cx: &mut Context<Self>,
 4565    ) {
 4566        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4567
 4568        self.refresh_inline_values(cx);
 4569    }
 4570
 4571    pub fn toggle_inlay_hints(
 4572        &mut self,
 4573        _: &ToggleInlayHints,
 4574        _: &mut Window,
 4575        cx: &mut Context<Self>,
 4576    ) {
 4577        self.refresh_inlay_hints(
 4578            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4579            cx,
 4580        );
 4581    }
 4582
 4583    pub fn inlay_hints_enabled(&self) -> bool {
 4584        self.inlay_hint_cache.enabled
 4585    }
 4586
 4587    pub fn inline_values_enabled(&self) -> bool {
 4588        self.inline_value_cache.enabled
 4589    }
 4590
 4591    #[cfg(any(test, feature = "test-support"))]
 4592    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4593        self.display_map
 4594            .read(cx)
 4595            .current_inlays()
 4596            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4597            .cloned()
 4598            .collect()
 4599    }
 4600
 4601    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4602        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4603            return;
 4604        }
 4605
 4606        let reason_description = reason.description();
 4607        let ignore_debounce = matches!(
 4608            reason,
 4609            InlayHintRefreshReason::SettingsChange(_)
 4610                | InlayHintRefreshReason::Toggle(_)
 4611                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4612                | InlayHintRefreshReason::ModifiersChanged(_)
 4613        );
 4614        let (invalidate_cache, required_languages) = match reason {
 4615            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4616                match self.inlay_hint_cache.modifiers_override(enabled) {
 4617                    Some(enabled) => {
 4618                        if enabled {
 4619                            (InvalidationStrategy::RefreshRequested, None)
 4620                        } else {
 4621                            self.splice_inlays(
 4622                                &self
 4623                                    .visible_inlay_hints(cx)
 4624                                    .iter()
 4625                                    .map(|inlay| inlay.id)
 4626                                    .collect::<Vec<InlayId>>(),
 4627                                Vec::new(),
 4628                                cx,
 4629                            );
 4630                            return;
 4631                        }
 4632                    }
 4633                    None => return,
 4634                }
 4635            }
 4636            InlayHintRefreshReason::Toggle(enabled) => {
 4637                if self.inlay_hint_cache.toggle(enabled) {
 4638                    if enabled {
 4639                        (InvalidationStrategy::RefreshRequested, None)
 4640                    } else {
 4641                        self.splice_inlays(
 4642                            &self
 4643                                .visible_inlay_hints(cx)
 4644                                .iter()
 4645                                .map(|inlay| inlay.id)
 4646                                .collect::<Vec<InlayId>>(),
 4647                            Vec::new(),
 4648                            cx,
 4649                        );
 4650                        return;
 4651                    }
 4652                } else {
 4653                    return;
 4654                }
 4655            }
 4656            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4657                match self.inlay_hint_cache.update_settings(
 4658                    &self.buffer,
 4659                    new_settings,
 4660                    self.visible_inlay_hints(cx),
 4661                    cx,
 4662                ) {
 4663                    ControlFlow::Break(Some(InlaySplice {
 4664                        to_remove,
 4665                        to_insert,
 4666                    })) => {
 4667                        self.splice_inlays(&to_remove, to_insert, cx);
 4668                        return;
 4669                    }
 4670                    ControlFlow::Break(None) => return,
 4671                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4672                }
 4673            }
 4674            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4675                if let Some(InlaySplice {
 4676                    to_remove,
 4677                    to_insert,
 4678                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4679                {
 4680                    self.splice_inlays(&to_remove, to_insert, cx);
 4681                }
 4682                self.display_map.update(cx, |display_map, _| {
 4683                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4684                });
 4685                return;
 4686            }
 4687            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4688            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4689                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4690            }
 4691            InlayHintRefreshReason::RefreshRequested => {
 4692                (InvalidationStrategy::RefreshRequested, None)
 4693            }
 4694        };
 4695
 4696        if let Some(InlaySplice {
 4697            to_remove,
 4698            to_insert,
 4699        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4700            reason_description,
 4701            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4702            invalidate_cache,
 4703            ignore_debounce,
 4704            cx,
 4705        ) {
 4706            self.splice_inlays(&to_remove, to_insert, cx);
 4707        }
 4708    }
 4709
 4710    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4711        self.display_map
 4712            .read(cx)
 4713            .current_inlays()
 4714            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4715            .cloned()
 4716            .collect()
 4717    }
 4718
 4719    pub fn excerpts_for_inlay_hints_query(
 4720        &self,
 4721        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4722        cx: &mut Context<Editor>,
 4723    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4724        let Some(project) = self.project.as_ref() else {
 4725            return HashMap::default();
 4726        };
 4727        let project = project.read(cx);
 4728        let multi_buffer = self.buffer().read(cx);
 4729        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4730        let multi_buffer_visible_start = self
 4731            .scroll_manager
 4732            .anchor()
 4733            .anchor
 4734            .to_point(&multi_buffer_snapshot);
 4735        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4736            multi_buffer_visible_start
 4737                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4738            Bias::Left,
 4739        );
 4740        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4741        multi_buffer_snapshot
 4742            .range_to_buffer_ranges(multi_buffer_visible_range)
 4743            .into_iter()
 4744            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4745            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4746                let buffer_file = project::File::from_dyn(buffer.file())?;
 4747                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4748                let worktree_entry = buffer_worktree
 4749                    .read(cx)
 4750                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4751                if worktree_entry.is_ignored {
 4752                    return None;
 4753                }
 4754
 4755                let language = buffer.language()?;
 4756                if let Some(restrict_to_languages) = restrict_to_languages {
 4757                    if !restrict_to_languages.contains(language) {
 4758                        return None;
 4759                    }
 4760                }
 4761                Some((
 4762                    excerpt_id,
 4763                    (
 4764                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4765                        buffer.version().clone(),
 4766                        excerpt_visible_range,
 4767                    ),
 4768                ))
 4769            })
 4770            .collect()
 4771    }
 4772
 4773    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4774        TextLayoutDetails {
 4775            text_system: window.text_system().clone(),
 4776            editor_style: self.style.clone().unwrap(),
 4777            rem_size: window.rem_size(),
 4778            scroll_anchor: self.scroll_manager.anchor(),
 4779            visible_rows: self.visible_line_count(),
 4780            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4781        }
 4782    }
 4783
 4784    pub fn splice_inlays(
 4785        &self,
 4786        to_remove: &[InlayId],
 4787        to_insert: Vec<Inlay>,
 4788        cx: &mut Context<Self>,
 4789    ) {
 4790        self.display_map.update(cx, |display_map, cx| {
 4791            display_map.splice_inlays(to_remove, to_insert, cx)
 4792        });
 4793        cx.notify();
 4794    }
 4795
 4796    fn trigger_on_type_formatting(
 4797        &self,
 4798        input: String,
 4799        window: &mut Window,
 4800        cx: &mut Context<Self>,
 4801    ) -> Option<Task<Result<()>>> {
 4802        if input.len() != 1 {
 4803            return None;
 4804        }
 4805
 4806        let project = self.project.as_ref()?;
 4807        let position = self.selections.newest_anchor().head();
 4808        let (buffer, buffer_position) = self
 4809            .buffer
 4810            .read(cx)
 4811            .text_anchor_for_position(position, cx)?;
 4812
 4813        let settings = language_settings::language_settings(
 4814            buffer
 4815                .read(cx)
 4816                .language_at(buffer_position)
 4817                .map(|l| l.name()),
 4818            buffer.read(cx).file(),
 4819            cx,
 4820        );
 4821        if !settings.use_on_type_format {
 4822            return None;
 4823        }
 4824
 4825        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4826        // hence we do LSP request & edit on host side only — add formats to host's history.
 4827        let push_to_lsp_host_history = true;
 4828        // If this is not the host, append its history with new edits.
 4829        let push_to_client_history = project.read(cx).is_via_collab();
 4830
 4831        let on_type_formatting = project.update(cx, |project, cx| {
 4832            project.on_type_format(
 4833                buffer.clone(),
 4834                buffer_position,
 4835                input,
 4836                push_to_lsp_host_history,
 4837                cx,
 4838            )
 4839        });
 4840        Some(cx.spawn_in(window, async move |editor, cx| {
 4841            if let Some(transaction) = on_type_formatting.await? {
 4842                if push_to_client_history {
 4843                    buffer
 4844                        .update(cx, |buffer, _| {
 4845                            buffer.push_transaction(transaction, Instant::now());
 4846                            buffer.finalize_last_transaction();
 4847                        })
 4848                        .ok();
 4849                }
 4850                editor.update(cx, |editor, cx| {
 4851                    editor.refresh_document_highlights(cx);
 4852                })?;
 4853            }
 4854            Ok(())
 4855        }))
 4856    }
 4857
 4858    pub fn show_word_completions(
 4859        &mut self,
 4860        _: &ShowWordCompletions,
 4861        window: &mut Window,
 4862        cx: &mut Context<Self>,
 4863    ) {
 4864        self.open_completions_menu(true, None, window, cx);
 4865    }
 4866
 4867    pub fn show_completions(
 4868        &mut self,
 4869        options: &ShowCompletions,
 4870        window: &mut Window,
 4871        cx: &mut Context<Self>,
 4872    ) {
 4873        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4874    }
 4875
 4876    fn open_completions_menu(
 4877        &mut self,
 4878        ignore_completion_provider: bool,
 4879        trigger: Option<&str>,
 4880        window: &mut Window,
 4881        cx: &mut Context<Self>,
 4882    ) {
 4883        if self.pending_rename.is_some() {
 4884            return;
 4885        }
 4886        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4887            return;
 4888        }
 4889
 4890        let position = self.selections.newest_anchor().head();
 4891        if position.diff_base_anchor.is_some() {
 4892            return;
 4893        }
 4894        let (buffer, buffer_position) =
 4895            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4896                output
 4897            } else {
 4898                return;
 4899            };
 4900        let buffer_snapshot = buffer.read(cx).snapshot();
 4901        let show_completion_documentation = buffer_snapshot
 4902            .settings_at(buffer_position, cx)
 4903            .show_completion_documentation;
 4904
 4905        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4906
 4907        let trigger_kind = match trigger {
 4908            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4909                CompletionTriggerKind::TRIGGER_CHARACTER
 4910            }
 4911            _ => CompletionTriggerKind::INVOKED,
 4912        };
 4913        let completion_context = CompletionContext {
 4914            trigger_character: trigger.and_then(|trigger| {
 4915                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4916                    Some(String::from(trigger))
 4917                } else {
 4918                    None
 4919                }
 4920            }),
 4921            trigger_kind,
 4922        };
 4923
 4924        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4925        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4926            let word_to_exclude = buffer_snapshot
 4927                .text_for_range(old_range.clone())
 4928                .collect::<String>();
 4929            (
 4930                buffer_snapshot.anchor_before(old_range.start)
 4931                    ..buffer_snapshot.anchor_after(old_range.end),
 4932                Some(word_to_exclude),
 4933            )
 4934        } else {
 4935            (buffer_position..buffer_position, None)
 4936        };
 4937
 4938        let completion_settings = language_settings(
 4939            buffer_snapshot
 4940                .language_at(buffer_position)
 4941                .map(|language| language.name()),
 4942            buffer_snapshot.file(),
 4943            cx,
 4944        )
 4945        .completions;
 4946
 4947        // The document can be large, so stay in reasonable bounds when searching for words,
 4948        // otherwise completion pop-up might be slow to appear.
 4949        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4950        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4951        let min_word_search = buffer_snapshot.clip_point(
 4952            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4953            Bias::Left,
 4954        );
 4955        let max_word_search = buffer_snapshot.clip_point(
 4956            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4957            Bias::Right,
 4958        );
 4959        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4960            ..buffer_snapshot.point_to_offset(max_word_search);
 4961
 4962        let provider = self
 4963            .completion_provider
 4964            .as_ref()
 4965            .filter(|_| !ignore_completion_provider);
 4966        let skip_digits = query
 4967            .as_ref()
 4968            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4969
 4970        let (mut words, provided_completions) = match provider {
 4971            Some(provider) => {
 4972                let completions = provider.completions(
 4973                    position.excerpt_id,
 4974                    &buffer,
 4975                    buffer_position,
 4976                    completion_context,
 4977                    window,
 4978                    cx,
 4979                );
 4980
 4981                let words = match completion_settings.words {
 4982                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4983                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4984                        .background_spawn(async move {
 4985                            buffer_snapshot.words_in_range(WordsQuery {
 4986                                fuzzy_contents: None,
 4987                                range: word_search_range,
 4988                                skip_digits,
 4989                            })
 4990                        }),
 4991                };
 4992
 4993                (words, completions)
 4994            }
 4995            None => (
 4996                cx.background_spawn(async move {
 4997                    buffer_snapshot.words_in_range(WordsQuery {
 4998                        fuzzy_contents: None,
 4999                        range: word_search_range,
 5000                        skip_digits,
 5001                    })
 5002                }),
 5003                Task::ready(Ok(None)),
 5004            ),
 5005        };
 5006
 5007        let sort_completions = provider
 5008            .as_ref()
 5009            .map_or(false, |provider| provider.sort_completions());
 5010
 5011        let filter_completions = provider
 5012            .as_ref()
 5013            .map_or(true, |provider| provider.filter_completions());
 5014
 5015        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5016
 5017        let id = post_inc(&mut self.next_completion_id);
 5018        let task = cx.spawn_in(window, async move |editor, cx| {
 5019            async move {
 5020                editor.update(cx, |this, _| {
 5021                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5022                })?;
 5023
 5024                let mut completions = Vec::new();
 5025                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5026                    completions.extend(provided_completions);
 5027                    if completion_settings.words == WordsCompletionMode::Fallback {
 5028                        words = Task::ready(BTreeMap::default());
 5029                    }
 5030                }
 5031
 5032                let mut words = words.await;
 5033                if let Some(word_to_exclude) = &word_to_exclude {
 5034                    words.remove(word_to_exclude);
 5035                }
 5036                for lsp_completion in &completions {
 5037                    words.remove(&lsp_completion.new_text);
 5038                }
 5039                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5040                    replace_range: old_range.clone(),
 5041                    new_text: word.clone(),
 5042                    label: CodeLabel::plain(word, None),
 5043                    icon_path: None,
 5044                    documentation: None,
 5045                    source: CompletionSource::BufferWord {
 5046                        word_range,
 5047                        resolved: false,
 5048                    },
 5049                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5050                    confirm: None,
 5051                }));
 5052
 5053                let menu = if completions.is_empty() {
 5054                    None
 5055                } else {
 5056                    let mut menu = CompletionsMenu::new(
 5057                        id,
 5058                        sort_completions,
 5059                        show_completion_documentation,
 5060                        ignore_completion_provider,
 5061                        position,
 5062                        buffer.clone(),
 5063                        completions.into(),
 5064                        snippet_sort_order,
 5065                    );
 5066
 5067                    menu.filter(
 5068                        if filter_completions {
 5069                            query.as_deref()
 5070                        } else {
 5071                            None
 5072                        },
 5073                        cx.background_executor().clone(),
 5074                    )
 5075                    .await;
 5076
 5077                    menu.visible().then_some(menu)
 5078                };
 5079
 5080                editor.update_in(cx, |editor, window, cx| {
 5081                    match editor.context_menu.borrow().as_ref() {
 5082                        None => {}
 5083                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5084                            if prev_menu.id > id {
 5085                                return;
 5086                            }
 5087                        }
 5088                        _ => return,
 5089                    }
 5090
 5091                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5092                        let mut menu = menu.unwrap();
 5093                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5094                        crate::hover_popover::hide_hover(editor, cx);
 5095                        *editor.context_menu.borrow_mut() =
 5096                            Some(CodeContextMenu::Completions(menu));
 5097
 5098                        if editor.show_edit_predictions_in_menu() {
 5099                            editor.update_visible_inline_completion(window, cx);
 5100                        } else {
 5101                            editor.discard_inline_completion(false, cx);
 5102                        }
 5103
 5104                        cx.notify();
 5105                    } else if editor.completion_tasks.len() <= 1 {
 5106                        // If there are no more completion tasks and the last menu was
 5107                        // empty, we should hide it.
 5108                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5109                        // If it was already hidden and we don't show inline
 5110                        // completions in the menu, we should also show the
 5111                        // inline-completion when available.
 5112                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5113                            editor.update_visible_inline_completion(window, cx);
 5114                        }
 5115                    }
 5116                })?;
 5117
 5118                anyhow::Ok(())
 5119            }
 5120            .log_err()
 5121            .await
 5122        });
 5123
 5124        self.completion_tasks.push((id, task));
 5125    }
 5126
 5127    #[cfg(feature = "test-support")]
 5128    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5129        let menu = self.context_menu.borrow();
 5130        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5131            let completions = menu.completions.borrow();
 5132            Some(completions.to_vec())
 5133        } else {
 5134            None
 5135        }
 5136    }
 5137
 5138    pub fn confirm_completion(
 5139        &mut self,
 5140        action: &ConfirmCompletion,
 5141        window: &mut Window,
 5142        cx: &mut Context<Self>,
 5143    ) -> Option<Task<Result<()>>> {
 5144        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5145        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5146    }
 5147
 5148    pub fn confirm_completion_insert(
 5149        &mut self,
 5150        _: &ConfirmCompletionInsert,
 5151        window: &mut Window,
 5152        cx: &mut Context<Self>,
 5153    ) -> Option<Task<Result<()>>> {
 5154        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5155        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5156    }
 5157
 5158    pub fn confirm_completion_replace(
 5159        &mut self,
 5160        _: &ConfirmCompletionReplace,
 5161        window: &mut Window,
 5162        cx: &mut Context<Self>,
 5163    ) -> Option<Task<Result<()>>> {
 5164        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5165        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5166    }
 5167
 5168    pub fn compose_completion(
 5169        &mut self,
 5170        action: &ComposeCompletion,
 5171        window: &mut Window,
 5172        cx: &mut Context<Self>,
 5173    ) -> Option<Task<Result<()>>> {
 5174        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5175        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5176    }
 5177
 5178    fn do_completion(
 5179        &mut self,
 5180        item_ix: Option<usize>,
 5181        intent: CompletionIntent,
 5182        window: &mut Window,
 5183        cx: &mut Context<Editor>,
 5184    ) -> Option<Task<Result<()>>> {
 5185        use language::ToOffset as _;
 5186
 5187        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5188        else {
 5189            return None;
 5190        };
 5191
 5192        let candidate_id = {
 5193            let entries = completions_menu.entries.borrow();
 5194            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5195            if self.show_edit_predictions_in_menu() {
 5196                self.discard_inline_completion(true, cx);
 5197            }
 5198            mat.candidate_id
 5199        };
 5200
 5201        let buffer_handle = completions_menu.buffer;
 5202        let completion = completions_menu
 5203            .completions
 5204            .borrow()
 5205            .get(candidate_id)?
 5206            .clone();
 5207        cx.stop_propagation();
 5208
 5209        let snapshot = self.buffer.read(cx).snapshot(cx);
 5210        let newest_anchor = self.selections.newest_anchor();
 5211
 5212        let snippet;
 5213        let new_text;
 5214        if completion.is_snippet() {
 5215            let mut snippet_source = completion.new_text.clone();
 5216            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5217                if scope.prefers_label_for_snippet_in_completion() {
 5218                    if let Some(label) = completion.label() {
 5219                        if matches!(
 5220                            completion.kind(),
 5221                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5222                        ) {
 5223                            snippet_source = label;
 5224                        }
 5225                    }
 5226                }
 5227            }
 5228            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5229            new_text = snippet.as_ref().unwrap().text.clone();
 5230        } else {
 5231            snippet = None;
 5232            new_text = completion.new_text.clone();
 5233        };
 5234
 5235        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5236        let buffer = buffer_handle.read(cx);
 5237        let replace_range_multibuffer = {
 5238            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5239            let multibuffer_anchor = snapshot
 5240                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5241                .unwrap()
 5242                ..snapshot
 5243                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5244                    .unwrap();
 5245            multibuffer_anchor.start.to_offset(&snapshot)
 5246                ..multibuffer_anchor.end.to_offset(&snapshot)
 5247        };
 5248        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5249            return None;
 5250        }
 5251
 5252        let old_text = buffer
 5253            .text_for_range(replace_range.clone())
 5254            .collect::<String>();
 5255        let lookbehind = newest_anchor
 5256            .start
 5257            .text_anchor
 5258            .to_offset(buffer)
 5259            .saturating_sub(replace_range.start);
 5260        let lookahead = replace_range
 5261            .end
 5262            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5263        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5264        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5265
 5266        let selections = self.selections.all::<usize>(cx);
 5267        let mut ranges = Vec::new();
 5268        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5269
 5270        for selection in &selections {
 5271            let range = if selection.id == newest_anchor.id {
 5272                replace_range_multibuffer.clone()
 5273            } else {
 5274                let mut range = selection.range();
 5275
 5276                // if prefix is present, don't duplicate it
 5277                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5278                    range.start = range.start.saturating_sub(lookbehind);
 5279
 5280                    // if suffix is also present, mimic the newest cursor and replace it
 5281                    if selection.id != newest_anchor.id
 5282                        && snapshot.contains_str_at(range.end, suffix)
 5283                    {
 5284                        range.end += lookahead;
 5285                    }
 5286                }
 5287                range
 5288            };
 5289
 5290            ranges.push(range.clone());
 5291
 5292            if !self.linked_edit_ranges.is_empty() {
 5293                let start_anchor = snapshot.anchor_before(range.start);
 5294                let end_anchor = snapshot.anchor_after(range.end);
 5295                if let Some(ranges) = self
 5296                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5297                {
 5298                    for (buffer, edits) in ranges {
 5299                        linked_edits
 5300                            .entry(buffer.clone())
 5301                            .or_default()
 5302                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5303                    }
 5304                }
 5305            }
 5306        }
 5307
 5308        cx.emit(EditorEvent::InputHandled {
 5309            utf16_range_to_replace: None,
 5310            text: new_text.clone().into(),
 5311        });
 5312
 5313        self.transact(window, cx, |this, window, cx| {
 5314            if let Some(mut snippet) = snippet {
 5315                snippet.text = new_text.to_string();
 5316                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5317            } else {
 5318                this.buffer.update(cx, |buffer, cx| {
 5319                    let auto_indent = match completion.insert_text_mode {
 5320                        Some(InsertTextMode::AS_IS) => None,
 5321                        _ => this.autoindent_mode.clone(),
 5322                    };
 5323                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5324                    buffer.edit(edits, auto_indent, cx);
 5325                });
 5326            }
 5327            for (buffer, edits) in linked_edits {
 5328                buffer.update(cx, |buffer, cx| {
 5329                    let snapshot = buffer.snapshot();
 5330                    let edits = edits
 5331                        .into_iter()
 5332                        .map(|(range, text)| {
 5333                            use text::ToPoint as TP;
 5334                            let end_point = TP::to_point(&range.end, &snapshot);
 5335                            let start_point = TP::to_point(&range.start, &snapshot);
 5336                            (start_point..end_point, text)
 5337                        })
 5338                        .sorted_by_key(|(range, _)| range.start);
 5339                    buffer.edit(edits, None, cx);
 5340                })
 5341            }
 5342
 5343            this.refresh_inline_completion(true, false, window, cx);
 5344        });
 5345
 5346        let show_new_completions_on_confirm = completion
 5347            .confirm
 5348            .as_ref()
 5349            .map_or(false, |confirm| confirm(intent, window, cx));
 5350        if show_new_completions_on_confirm {
 5351            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5352        }
 5353
 5354        let provider = self.completion_provider.as_ref()?;
 5355        drop(completion);
 5356        let apply_edits = provider.apply_additional_edits_for_completion(
 5357            buffer_handle,
 5358            completions_menu.completions.clone(),
 5359            candidate_id,
 5360            true,
 5361            cx,
 5362        );
 5363
 5364        let editor_settings = EditorSettings::get_global(cx);
 5365        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5366            // After the code completion is finished, users often want to know what signatures are needed.
 5367            // so we should automatically call signature_help
 5368            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5369        }
 5370
 5371        Some(cx.foreground_executor().spawn(async move {
 5372            apply_edits.await?;
 5373            Ok(())
 5374        }))
 5375    }
 5376
 5377    pub fn toggle_code_actions(
 5378        &mut self,
 5379        action: &ToggleCodeActions,
 5380        window: &mut Window,
 5381        cx: &mut Context<Self>,
 5382    ) {
 5383        let quick_launch = action.quick_launch;
 5384        let mut context_menu = self.context_menu.borrow_mut();
 5385        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5386            if code_actions.deployed_from == action.deployed_from {
 5387                // Toggle if we're selecting the same one
 5388                *context_menu = None;
 5389                cx.notify();
 5390                return;
 5391            } else {
 5392                // Otherwise, clear it and start a new one
 5393                *context_menu = None;
 5394                cx.notify();
 5395            }
 5396        }
 5397        drop(context_menu);
 5398        let snapshot = self.snapshot(window, cx);
 5399        let deployed_from = action.deployed_from.clone();
 5400        let mut task = self.code_actions_task.take();
 5401        let action = action.clone();
 5402        cx.spawn_in(window, async move |editor, cx| {
 5403            while let Some(prev_task) = task {
 5404                prev_task.await.log_err();
 5405                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5406            }
 5407
 5408            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5409                if editor.focus_handle.is_focused(window) {
 5410                    let multibuffer_point = match &action.deployed_from {
 5411                        Some(CodeActionSource::Indicator(row)) => {
 5412                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5413                        }
 5414                        _ => editor.selections.newest::<Point>(cx).head(),
 5415                    };
 5416                    let (buffer, buffer_row) = snapshot
 5417                        .buffer_snapshot
 5418                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5419                        .and_then(|(buffer_snapshot, range)| {
 5420                            editor
 5421                                .buffer
 5422                                .read(cx)
 5423                                .buffer(buffer_snapshot.remote_id())
 5424                                .map(|buffer| (buffer, range.start.row))
 5425                        })?;
 5426                    let (_, code_actions) = editor
 5427                        .available_code_actions
 5428                        .clone()
 5429                        .and_then(|(location, code_actions)| {
 5430                            let snapshot = location.buffer.read(cx).snapshot();
 5431                            let point_range = location.range.to_point(&snapshot);
 5432                            let point_range = point_range.start.row..=point_range.end.row;
 5433                            if point_range.contains(&buffer_row) {
 5434                                Some((location, code_actions))
 5435                            } else {
 5436                                None
 5437                            }
 5438                        })
 5439                        .unzip();
 5440                    let buffer_id = buffer.read(cx).remote_id();
 5441                    let tasks = editor
 5442                        .tasks
 5443                        .get(&(buffer_id, buffer_row))
 5444                        .map(|t| Arc::new(t.to_owned()));
 5445                    if tasks.is_none() && code_actions.is_none() {
 5446                        return None;
 5447                    }
 5448
 5449                    editor.completion_tasks.clear();
 5450                    editor.discard_inline_completion(false, cx);
 5451                    let task_context =
 5452                        tasks
 5453                            .as_ref()
 5454                            .zip(editor.project.clone())
 5455                            .map(|(tasks, project)| {
 5456                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5457                            });
 5458
 5459                    Some(cx.spawn_in(window, async move |editor, cx| {
 5460                        let task_context = match task_context {
 5461                            Some(task_context) => task_context.await,
 5462                            None => None,
 5463                        };
 5464                        let resolved_tasks =
 5465                            tasks
 5466                                .zip(task_context.clone())
 5467                                .map(|(tasks, task_context)| ResolvedTasks {
 5468                                    templates: tasks.resolve(&task_context).collect(),
 5469                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5470                                        multibuffer_point.row,
 5471                                        tasks.column,
 5472                                    )),
 5473                                });
 5474                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5475                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5476                                maybe!({
 5477                                    let project = editor.project.as_ref()?;
 5478                                    let dap_store = project.read(cx).dap_store();
 5479                                    let mut scenarios = vec![];
 5480                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5481                                    let buffer = buffer.read(cx);
 5482                                    let language = buffer.language()?;
 5483                                    let file = buffer.file();
 5484                                    let debug_adapter =
 5485                                        language_settings(language.name().into(), file, cx)
 5486                                            .debuggers
 5487                                            .first()
 5488                                            .map(SharedString::from)
 5489                                            .or_else(|| {
 5490                                                language
 5491                                                    .config()
 5492                                                    .debuggers
 5493                                                    .first()
 5494                                                    .map(SharedString::from)
 5495                                            })?;
 5496
 5497                                    dap_store.update(cx, |dap_store, cx| {
 5498                                        for (_, task) in &resolved_tasks.templates {
 5499                                            if let Some(scenario) = dap_store
 5500                                                .debug_scenario_for_build_task(
 5501                                                    task.original_task().clone(),
 5502                                                    debug_adapter.clone().into(),
 5503                                                    task.display_label().to_owned().into(),
 5504                                                    cx,
 5505                                                )
 5506                                            {
 5507                                                scenarios.push(scenario);
 5508                                            }
 5509                                        }
 5510                                    });
 5511                                    Some(scenarios)
 5512                                })
 5513                                .unwrap_or_default()
 5514                            } else {
 5515                                vec![]
 5516                            }
 5517                        })?;
 5518                        let spawn_straight_away = quick_launch
 5519                            && resolved_tasks
 5520                                .as_ref()
 5521                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5522                            && code_actions
 5523                                .as_ref()
 5524                                .map_or(true, |actions| actions.is_empty())
 5525                            && debug_scenarios.is_empty();
 5526                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5527                            crate::hover_popover::hide_hover(editor, cx);
 5528                            *editor.context_menu.borrow_mut() =
 5529                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5530                                    buffer,
 5531                                    actions: CodeActionContents::new(
 5532                                        resolved_tasks,
 5533                                        code_actions,
 5534                                        debug_scenarios,
 5535                                        task_context.unwrap_or_default(),
 5536                                    ),
 5537                                    selected_item: Default::default(),
 5538                                    scroll_handle: UniformListScrollHandle::default(),
 5539                                    deployed_from,
 5540                                }));
 5541                            if spawn_straight_away {
 5542                                if let Some(task) = editor.confirm_code_action(
 5543                                    &ConfirmCodeAction { item_ix: Some(0) },
 5544                                    window,
 5545                                    cx,
 5546                                ) {
 5547                                    cx.notify();
 5548                                    return task;
 5549                                }
 5550                            }
 5551                            cx.notify();
 5552                            Task::ready(Ok(()))
 5553                        }) {
 5554                            task.await
 5555                        } else {
 5556                            Ok(())
 5557                        }
 5558                    }))
 5559                } else {
 5560                    Some(Task::ready(Ok(())))
 5561                }
 5562            })?;
 5563            if let Some(task) = spawned_test_task {
 5564                task.await?;
 5565            }
 5566
 5567            anyhow::Ok(())
 5568        })
 5569        .detach_and_log_err(cx);
 5570    }
 5571
 5572    pub fn confirm_code_action(
 5573        &mut self,
 5574        action: &ConfirmCodeAction,
 5575        window: &mut Window,
 5576        cx: &mut Context<Self>,
 5577    ) -> Option<Task<Result<()>>> {
 5578        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5579
 5580        let actions_menu =
 5581            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5582                menu
 5583            } else {
 5584                return None;
 5585            };
 5586
 5587        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5588        let action = actions_menu.actions.get(action_ix)?;
 5589        let title = action.label();
 5590        let buffer = actions_menu.buffer;
 5591        let workspace = self.workspace()?;
 5592
 5593        match action {
 5594            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5595                workspace.update(cx, |workspace, cx| {
 5596                    workspace.schedule_resolved_task(
 5597                        task_source_kind,
 5598                        resolved_task,
 5599                        false,
 5600                        window,
 5601                        cx,
 5602                    );
 5603
 5604                    Some(Task::ready(Ok(())))
 5605                })
 5606            }
 5607            CodeActionsItem::CodeAction {
 5608                excerpt_id,
 5609                action,
 5610                provider,
 5611            } => {
 5612                let apply_code_action =
 5613                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5614                let workspace = workspace.downgrade();
 5615                Some(cx.spawn_in(window, async move |editor, cx| {
 5616                    let project_transaction = apply_code_action.await?;
 5617                    Self::open_project_transaction(
 5618                        &editor,
 5619                        workspace,
 5620                        project_transaction,
 5621                        title,
 5622                        cx,
 5623                    )
 5624                    .await
 5625                }))
 5626            }
 5627            CodeActionsItem::DebugScenario(scenario) => {
 5628                let context = actions_menu.actions.context.clone();
 5629
 5630                workspace.update(cx, |workspace, cx| {
 5631                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5632                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5633                });
 5634                Some(Task::ready(Ok(())))
 5635            }
 5636        }
 5637    }
 5638
 5639    pub async fn open_project_transaction(
 5640        this: &WeakEntity<Editor>,
 5641        workspace: WeakEntity<Workspace>,
 5642        transaction: ProjectTransaction,
 5643        title: String,
 5644        cx: &mut AsyncWindowContext,
 5645    ) -> Result<()> {
 5646        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5647        cx.update(|_, cx| {
 5648            entries.sort_unstable_by_key(|(buffer, _)| {
 5649                buffer.read(cx).file().map(|f| f.path().clone())
 5650            });
 5651        })?;
 5652
 5653        // If the project transaction's edits are all contained within this editor, then
 5654        // avoid opening a new editor to display them.
 5655
 5656        if let Some((buffer, transaction)) = entries.first() {
 5657            if entries.len() == 1 {
 5658                let excerpt = this.update(cx, |editor, cx| {
 5659                    editor
 5660                        .buffer()
 5661                        .read(cx)
 5662                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5663                })?;
 5664                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5665                    if excerpted_buffer == *buffer {
 5666                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5667                            let excerpt_range = excerpt_range.to_offset(buffer);
 5668                            buffer
 5669                                .edited_ranges_for_transaction::<usize>(transaction)
 5670                                .all(|range| {
 5671                                    excerpt_range.start <= range.start
 5672                                        && excerpt_range.end >= range.end
 5673                                })
 5674                        })?;
 5675
 5676                        if all_edits_within_excerpt {
 5677                            return Ok(());
 5678                        }
 5679                    }
 5680                }
 5681            }
 5682        } else {
 5683            return Ok(());
 5684        }
 5685
 5686        let mut ranges_to_highlight = Vec::new();
 5687        let excerpt_buffer = cx.new(|cx| {
 5688            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5689            for (buffer_handle, transaction) in &entries {
 5690                let edited_ranges = buffer_handle
 5691                    .read(cx)
 5692                    .edited_ranges_for_transaction::<Point>(transaction)
 5693                    .collect::<Vec<_>>();
 5694                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5695                    PathKey::for_buffer(buffer_handle, cx),
 5696                    buffer_handle.clone(),
 5697                    edited_ranges,
 5698                    DEFAULT_MULTIBUFFER_CONTEXT,
 5699                    cx,
 5700                );
 5701
 5702                ranges_to_highlight.extend(ranges);
 5703            }
 5704            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5705            multibuffer
 5706        })?;
 5707
 5708        workspace.update_in(cx, |workspace, window, cx| {
 5709            let project = workspace.project().clone();
 5710            let editor =
 5711                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5712            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5713            editor.update(cx, |editor, cx| {
 5714                editor.highlight_background::<Self>(
 5715                    &ranges_to_highlight,
 5716                    |theme| theme.editor_highlighted_line_background,
 5717                    cx,
 5718                );
 5719            });
 5720        })?;
 5721
 5722        Ok(())
 5723    }
 5724
 5725    pub fn clear_code_action_providers(&mut self) {
 5726        self.code_action_providers.clear();
 5727        self.available_code_actions.take();
 5728    }
 5729
 5730    pub fn add_code_action_provider(
 5731        &mut self,
 5732        provider: Rc<dyn CodeActionProvider>,
 5733        window: &mut Window,
 5734        cx: &mut Context<Self>,
 5735    ) {
 5736        if self
 5737            .code_action_providers
 5738            .iter()
 5739            .any(|existing_provider| existing_provider.id() == provider.id())
 5740        {
 5741            return;
 5742        }
 5743
 5744        self.code_action_providers.push(provider);
 5745        self.refresh_code_actions(window, cx);
 5746    }
 5747
 5748    pub fn remove_code_action_provider(
 5749        &mut self,
 5750        id: Arc<str>,
 5751        window: &mut Window,
 5752        cx: &mut Context<Self>,
 5753    ) {
 5754        self.code_action_providers
 5755            .retain(|provider| provider.id() != id);
 5756        self.refresh_code_actions(window, cx);
 5757    }
 5758
 5759    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 5760        !self.code_action_providers.is_empty()
 5761            && EditorSettings::get_global(cx).toolbar.code_actions
 5762    }
 5763
 5764    pub fn has_available_code_actions(&self) -> bool {
 5765        self.available_code_actions
 5766            .as_ref()
 5767            .is_some_and(|(_, actions)| !actions.is_empty())
 5768    }
 5769
 5770    fn render_inline_code_actions(
 5771        &self,
 5772        icon_size: ui::IconSize,
 5773        display_row: DisplayRow,
 5774        is_active: bool,
 5775        cx: &mut Context<Self>,
 5776    ) -> AnyElement {
 5777        let show_tooltip = !self.context_menu_visible();
 5778        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 5779            .icon_size(icon_size)
 5780            .shape(ui::IconButtonShape::Square)
 5781            .style(ButtonStyle::Transparent)
 5782            .icon_color(ui::Color::Hidden)
 5783            .toggle_state(is_active)
 5784            .when(show_tooltip, |this| {
 5785                this.tooltip({
 5786                    let focus_handle = self.focus_handle.clone();
 5787                    move |window, cx| {
 5788                        Tooltip::for_action_in(
 5789                            "Toggle Code Actions",
 5790                            &ToggleCodeActions {
 5791                                deployed_from: None,
 5792                                quick_launch: false,
 5793                            },
 5794                            &focus_handle,
 5795                            window,
 5796                            cx,
 5797                        )
 5798                    }
 5799                })
 5800            })
 5801            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 5802                window.focus(&editor.focus_handle(cx));
 5803                editor.toggle_code_actions(
 5804                    &crate::actions::ToggleCodeActions {
 5805                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 5806                            display_row,
 5807                        )),
 5808                        quick_launch: false,
 5809                    },
 5810                    window,
 5811                    cx,
 5812                );
 5813            }))
 5814            .into_any_element()
 5815    }
 5816
 5817    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 5818        &self.context_menu
 5819    }
 5820
 5821    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5822        let newest_selection = self.selections.newest_anchor().clone();
 5823        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5824        let buffer = self.buffer.read(cx);
 5825        if newest_selection.head().diff_base_anchor.is_some() {
 5826            return None;
 5827        }
 5828        let (start_buffer, start) =
 5829            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5830        let (end_buffer, end) =
 5831            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5832        if start_buffer != end_buffer {
 5833            return None;
 5834        }
 5835
 5836        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5837            cx.background_executor()
 5838                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5839                .await;
 5840
 5841            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5842                let providers = this.code_action_providers.clone();
 5843                let tasks = this
 5844                    .code_action_providers
 5845                    .iter()
 5846                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5847                    .collect::<Vec<_>>();
 5848                (providers, tasks)
 5849            })?;
 5850
 5851            let mut actions = Vec::new();
 5852            for (provider, provider_actions) in
 5853                providers.into_iter().zip(future::join_all(tasks).await)
 5854            {
 5855                if let Some(provider_actions) = provider_actions.log_err() {
 5856                    actions.extend(provider_actions.into_iter().map(|action| {
 5857                        AvailableCodeAction {
 5858                            excerpt_id: newest_selection.start.excerpt_id,
 5859                            action,
 5860                            provider: provider.clone(),
 5861                        }
 5862                    }));
 5863                }
 5864            }
 5865
 5866            this.update(cx, |this, cx| {
 5867                this.available_code_actions = if actions.is_empty() {
 5868                    None
 5869                } else {
 5870                    Some((
 5871                        Location {
 5872                            buffer: start_buffer,
 5873                            range: start..end,
 5874                        },
 5875                        actions.into(),
 5876                    ))
 5877                };
 5878                cx.notify();
 5879            })
 5880        }));
 5881        None
 5882    }
 5883
 5884    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5885        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5886            self.show_git_blame_inline = false;
 5887
 5888            self.show_git_blame_inline_delay_task =
 5889                Some(cx.spawn_in(window, async move |this, cx| {
 5890                    cx.background_executor().timer(delay).await;
 5891
 5892                    this.update(cx, |this, cx| {
 5893                        this.show_git_blame_inline = true;
 5894                        cx.notify();
 5895                    })
 5896                    .log_err();
 5897                }));
 5898        }
 5899    }
 5900
 5901    fn show_blame_popover(
 5902        &mut self,
 5903        blame_entry: &BlameEntry,
 5904        position: gpui::Point<Pixels>,
 5905        cx: &mut Context<Self>,
 5906    ) {
 5907        if let Some(state) = &mut self.inline_blame_popover {
 5908            state.hide_task.take();
 5909            cx.notify();
 5910        } else {
 5911            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5912            let show_task = cx.spawn(async move |editor, cx| {
 5913                cx.background_executor()
 5914                    .timer(std::time::Duration::from_millis(delay))
 5915                    .await;
 5916                editor
 5917                    .update(cx, |editor, cx| {
 5918                        if let Some(state) = &mut editor.inline_blame_popover {
 5919                            state.show_task = None;
 5920                            cx.notify();
 5921                        }
 5922                    })
 5923                    .ok();
 5924            });
 5925            let Some(blame) = self.blame.as_ref() else {
 5926                return;
 5927            };
 5928            let blame = blame.read(cx);
 5929            let details = blame.details_for_entry(&blame_entry);
 5930            let markdown = cx.new(|cx| {
 5931                Markdown::new(
 5932                    details
 5933                        .as_ref()
 5934                        .map(|message| message.message.clone())
 5935                        .unwrap_or_default(),
 5936                    None,
 5937                    None,
 5938                    cx,
 5939                )
 5940            });
 5941            self.inline_blame_popover = Some(InlineBlamePopover {
 5942                position,
 5943                show_task: Some(show_task),
 5944                hide_task: None,
 5945                popover_bounds: None,
 5946                popover_state: InlineBlamePopoverState {
 5947                    scroll_handle: ScrollHandle::new(),
 5948                    commit_message: details,
 5949                    markdown,
 5950                },
 5951            });
 5952        }
 5953    }
 5954
 5955    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5956        if let Some(state) = &mut self.inline_blame_popover {
 5957            if state.show_task.is_some() {
 5958                self.inline_blame_popover.take();
 5959                cx.notify();
 5960            } else {
 5961                let hide_task = cx.spawn(async move |editor, cx| {
 5962                    cx.background_executor()
 5963                        .timer(std::time::Duration::from_millis(100))
 5964                        .await;
 5965                    editor
 5966                        .update(cx, |editor, cx| {
 5967                            editor.inline_blame_popover.take();
 5968                            cx.notify();
 5969                        })
 5970                        .ok();
 5971                });
 5972                state.hide_task = Some(hide_task);
 5973            }
 5974        }
 5975    }
 5976
 5977    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5978        if self.pending_rename.is_some() {
 5979            return None;
 5980        }
 5981
 5982        let provider = self.semantics_provider.clone()?;
 5983        let buffer = self.buffer.read(cx);
 5984        let newest_selection = self.selections.newest_anchor().clone();
 5985        let cursor_position = newest_selection.head();
 5986        let (cursor_buffer, cursor_buffer_position) =
 5987            buffer.text_anchor_for_position(cursor_position, cx)?;
 5988        let (tail_buffer, tail_buffer_position) =
 5989            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5990        if cursor_buffer != tail_buffer {
 5991            return None;
 5992        }
 5993
 5994        let snapshot = cursor_buffer.read(cx).snapshot();
 5995        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5996        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5997        if start_word_range != end_word_range {
 5998            self.document_highlights_task.take();
 5999            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6000            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6001            return None;
 6002        }
 6003
 6004        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6005        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6006            cx.background_executor()
 6007                .timer(Duration::from_millis(debounce))
 6008                .await;
 6009
 6010            let highlights = if let Some(highlights) = cx
 6011                .update(|cx| {
 6012                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6013                })
 6014                .ok()
 6015                .flatten()
 6016            {
 6017                highlights.await.log_err()
 6018            } else {
 6019                None
 6020            };
 6021
 6022            if let Some(highlights) = highlights {
 6023                this.update(cx, |this, cx| {
 6024                    if this.pending_rename.is_some() {
 6025                        return;
 6026                    }
 6027
 6028                    let buffer_id = cursor_position.buffer_id;
 6029                    let buffer = this.buffer.read(cx);
 6030                    if !buffer
 6031                        .text_anchor_for_position(cursor_position, cx)
 6032                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6033                    {
 6034                        return;
 6035                    }
 6036
 6037                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6038                    let mut write_ranges = Vec::new();
 6039                    let mut read_ranges = Vec::new();
 6040                    for highlight in highlights {
 6041                        for (excerpt_id, excerpt_range) in
 6042                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6043                        {
 6044                            let start = highlight
 6045                                .range
 6046                                .start
 6047                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6048                            let end = highlight
 6049                                .range
 6050                                .end
 6051                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6052                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6053                                continue;
 6054                            }
 6055
 6056                            let range = Anchor {
 6057                                buffer_id,
 6058                                excerpt_id,
 6059                                text_anchor: start,
 6060                                diff_base_anchor: None,
 6061                            }..Anchor {
 6062                                buffer_id,
 6063                                excerpt_id,
 6064                                text_anchor: end,
 6065                                diff_base_anchor: None,
 6066                            };
 6067                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6068                                write_ranges.push(range);
 6069                            } else {
 6070                                read_ranges.push(range);
 6071                            }
 6072                        }
 6073                    }
 6074
 6075                    this.highlight_background::<DocumentHighlightRead>(
 6076                        &read_ranges,
 6077                        |theme| theme.editor_document_highlight_read_background,
 6078                        cx,
 6079                    );
 6080                    this.highlight_background::<DocumentHighlightWrite>(
 6081                        &write_ranges,
 6082                        |theme| theme.editor_document_highlight_write_background,
 6083                        cx,
 6084                    );
 6085                    cx.notify();
 6086                })
 6087                .log_err();
 6088            }
 6089        }));
 6090        None
 6091    }
 6092
 6093    fn prepare_highlight_query_from_selection(
 6094        &mut self,
 6095        cx: &mut Context<Editor>,
 6096    ) -> Option<(String, Range<Anchor>)> {
 6097        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6098            return None;
 6099        }
 6100        if !EditorSettings::get_global(cx).selection_highlight {
 6101            return None;
 6102        }
 6103        if self.selections.count() != 1 || self.selections.line_mode {
 6104            return None;
 6105        }
 6106        let selection = self.selections.newest::<Point>(cx);
 6107        if selection.is_empty() || selection.start.row != selection.end.row {
 6108            return None;
 6109        }
 6110        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6111        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6112        let query = multi_buffer_snapshot
 6113            .text_for_range(selection_anchor_range.clone())
 6114            .collect::<String>();
 6115        if query.trim().is_empty() {
 6116            return None;
 6117        }
 6118        Some((query, selection_anchor_range))
 6119    }
 6120
 6121    fn update_selection_occurrence_highlights(
 6122        &mut self,
 6123        query_text: String,
 6124        query_range: Range<Anchor>,
 6125        multi_buffer_range_to_query: Range<Point>,
 6126        use_debounce: bool,
 6127        window: &mut Window,
 6128        cx: &mut Context<Editor>,
 6129    ) -> Task<()> {
 6130        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6131        cx.spawn_in(window, async move |editor, cx| {
 6132            if use_debounce {
 6133                cx.background_executor()
 6134                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6135                    .await;
 6136            }
 6137            let match_task = cx.background_spawn(async move {
 6138                let buffer_ranges = multi_buffer_snapshot
 6139                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6140                    .into_iter()
 6141                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6142                let mut match_ranges = Vec::new();
 6143                let Ok(regex) = project::search::SearchQuery::text(
 6144                    query_text.clone(),
 6145                    false,
 6146                    false,
 6147                    false,
 6148                    Default::default(),
 6149                    Default::default(),
 6150                    false,
 6151                    None,
 6152                ) else {
 6153                    return Vec::default();
 6154                };
 6155                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6156                    match_ranges.extend(
 6157                        regex
 6158                            .search(&buffer_snapshot, Some(search_range.clone()))
 6159                            .await
 6160                            .into_iter()
 6161                            .filter_map(|match_range| {
 6162                                let match_start = buffer_snapshot
 6163                                    .anchor_after(search_range.start + match_range.start);
 6164                                let match_end = buffer_snapshot
 6165                                    .anchor_before(search_range.start + match_range.end);
 6166                                let match_anchor_range = Anchor::range_in_buffer(
 6167                                    excerpt_id,
 6168                                    buffer_snapshot.remote_id(),
 6169                                    match_start..match_end,
 6170                                );
 6171                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6172                            }),
 6173                    );
 6174                }
 6175                match_ranges
 6176            });
 6177            let match_ranges = match_task.await;
 6178            editor
 6179                .update_in(cx, |editor, _, cx| {
 6180                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6181                    if !match_ranges.is_empty() {
 6182                        editor.highlight_background::<SelectedTextHighlight>(
 6183                            &match_ranges,
 6184                            |theme| theme.editor_document_highlight_bracket_background,
 6185                            cx,
 6186                        )
 6187                    }
 6188                })
 6189                .log_err();
 6190        })
 6191    }
 6192
 6193    fn refresh_selected_text_highlights(
 6194        &mut self,
 6195        on_buffer_edit: bool,
 6196        window: &mut Window,
 6197        cx: &mut Context<Editor>,
 6198    ) {
 6199        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6200        else {
 6201            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6202            self.quick_selection_highlight_task.take();
 6203            self.debounced_selection_highlight_task.take();
 6204            return;
 6205        };
 6206        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6207        if on_buffer_edit
 6208            || self
 6209                .quick_selection_highlight_task
 6210                .as_ref()
 6211                .map_or(true, |(prev_anchor_range, _)| {
 6212                    prev_anchor_range != &query_range
 6213                })
 6214        {
 6215            let multi_buffer_visible_start = self
 6216                .scroll_manager
 6217                .anchor()
 6218                .anchor
 6219                .to_point(&multi_buffer_snapshot);
 6220            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6221                multi_buffer_visible_start
 6222                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6223                Bias::Left,
 6224            );
 6225            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6226            self.quick_selection_highlight_task = Some((
 6227                query_range.clone(),
 6228                self.update_selection_occurrence_highlights(
 6229                    query_text.clone(),
 6230                    query_range.clone(),
 6231                    multi_buffer_visible_range,
 6232                    false,
 6233                    window,
 6234                    cx,
 6235                ),
 6236            ));
 6237        }
 6238        if on_buffer_edit
 6239            || self
 6240                .debounced_selection_highlight_task
 6241                .as_ref()
 6242                .map_or(true, |(prev_anchor_range, _)| {
 6243                    prev_anchor_range != &query_range
 6244                })
 6245        {
 6246            let multi_buffer_start = multi_buffer_snapshot
 6247                .anchor_before(0)
 6248                .to_point(&multi_buffer_snapshot);
 6249            let multi_buffer_end = multi_buffer_snapshot
 6250                .anchor_after(multi_buffer_snapshot.len())
 6251                .to_point(&multi_buffer_snapshot);
 6252            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6253            self.debounced_selection_highlight_task = Some((
 6254                query_range.clone(),
 6255                self.update_selection_occurrence_highlights(
 6256                    query_text,
 6257                    query_range,
 6258                    multi_buffer_full_range,
 6259                    true,
 6260                    window,
 6261                    cx,
 6262                ),
 6263            ));
 6264        }
 6265    }
 6266
 6267    pub fn refresh_inline_completion(
 6268        &mut self,
 6269        debounce: bool,
 6270        user_requested: bool,
 6271        window: &mut Window,
 6272        cx: &mut Context<Self>,
 6273    ) -> Option<()> {
 6274        let provider = self.edit_prediction_provider()?;
 6275        let cursor = self.selections.newest_anchor().head();
 6276        let (buffer, cursor_buffer_position) =
 6277            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6278
 6279        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6280            self.discard_inline_completion(false, cx);
 6281            return None;
 6282        }
 6283
 6284        if !user_requested
 6285            && (!self.should_show_edit_predictions()
 6286                || !self.is_focused(window)
 6287                || buffer.read(cx).is_empty())
 6288        {
 6289            self.discard_inline_completion(false, cx);
 6290            return None;
 6291        }
 6292
 6293        self.update_visible_inline_completion(window, cx);
 6294        provider.refresh(
 6295            self.project.clone(),
 6296            buffer,
 6297            cursor_buffer_position,
 6298            debounce,
 6299            cx,
 6300        );
 6301        Some(())
 6302    }
 6303
 6304    fn show_edit_predictions_in_menu(&self) -> bool {
 6305        match self.edit_prediction_settings {
 6306            EditPredictionSettings::Disabled => false,
 6307            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6308        }
 6309    }
 6310
 6311    pub fn edit_predictions_enabled(&self) -> bool {
 6312        match self.edit_prediction_settings {
 6313            EditPredictionSettings::Disabled => false,
 6314            EditPredictionSettings::Enabled { .. } => true,
 6315        }
 6316    }
 6317
 6318    fn edit_prediction_requires_modifier(&self) -> bool {
 6319        match self.edit_prediction_settings {
 6320            EditPredictionSettings::Disabled => false,
 6321            EditPredictionSettings::Enabled {
 6322                preview_requires_modifier,
 6323                ..
 6324            } => preview_requires_modifier,
 6325        }
 6326    }
 6327
 6328    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6329        if self.edit_prediction_provider.is_none() {
 6330            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6331        } else {
 6332            let selection = self.selections.newest_anchor();
 6333            let cursor = selection.head();
 6334
 6335            if let Some((buffer, cursor_buffer_position)) =
 6336                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6337            {
 6338                self.edit_prediction_settings =
 6339                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6340            }
 6341        }
 6342    }
 6343
 6344    fn edit_prediction_settings_at_position(
 6345        &self,
 6346        buffer: &Entity<Buffer>,
 6347        buffer_position: language::Anchor,
 6348        cx: &App,
 6349    ) -> EditPredictionSettings {
 6350        if !self.mode.is_full()
 6351            || !self.show_inline_completions_override.unwrap_or(true)
 6352            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6353        {
 6354            return EditPredictionSettings::Disabled;
 6355        }
 6356
 6357        let buffer = buffer.read(cx);
 6358
 6359        let file = buffer.file();
 6360
 6361        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6362            return EditPredictionSettings::Disabled;
 6363        };
 6364
 6365        let by_provider = matches!(
 6366            self.menu_inline_completions_policy,
 6367            MenuInlineCompletionsPolicy::ByProvider
 6368        );
 6369
 6370        let show_in_menu = by_provider
 6371            && self
 6372                .edit_prediction_provider
 6373                .as_ref()
 6374                .map_or(false, |provider| {
 6375                    provider.provider.show_completions_in_menu()
 6376                });
 6377
 6378        let preview_requires_modifier =
 6379            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6380
 6381        EditPredictionSettings::Enabled {
 6382            show_in_menu,
 6383            preview_requires_modifier,
 6384        }
 6385    }
 6386
 6387    fn should_show_edit_predictions(&self) -> bool {
 6388        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6389    }
 6390
 6391    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6392        matches!(
 6393            self.edit_prediction_preview,
 6394            EditPredictionPreview::Active { .. }
 6395        )
 6396    }
 6397
 6398    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6399        let cursor = self.selections.newest_anchor().head();
 6400        if let Some((buffer, cursor_position)) =
 6401            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6402        {
 6403            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6404        } else {
 6405            false
 6406        }
 6407    }
 6408
 6409    pub fn supports_minimap(&self, cx: &App) -> bool {
 6410        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6411    }
 6412
 6413    fn edit_predictions_enabled_in_buffer(
 6414        &self,
 6415        buffer: &Entity<Buffer>,
 6416        buffer_position: language::Anchor,
 6417        cx: &App,
 6418    ) -> bool {
 6419        maybe!({
 6420            if self.read_only(cx) {
 6421                return Some(false);
 6422            }
 6423            let provider = self.edit_prediction_provider()?;
 6424            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6425                return Some(false);
 6426            }
 6427            let buffer = buffer.read(cx);
 6428            let Some(file) = buffer.file() else {
 6429                return Some(true);
 6430            };
 6431            let settings = all_language_settings(Some(file), cx);
 6432            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6433        })
 6434        .unwrap_or(false)
 6435    }
 6436
 6437    fn cycle_inline_completion(
 6438        &mut self,
 6439        direction: Direction,
 6440        window: &mut Window,
 6441        cx: &mut Context<Self>,
 6442    ) -> Option<()> {
 6443        let provider = self.edit_prediction_provider()?;
 6444        let cursor = self.selections.newest_anchor().head();
 6445        let (buffer, cursor_buffer_position) =
 6446            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6447        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6448            return None;
 6449        }
 6450
 6451        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6452        self.update_visible_inline_completion(window, cx);
 6453
 6454        Some(())
 6455    }
 6456
 6457    pub fn show_inline_completion(
 6458        &mut self,
 6459        _: &ShowEditPrediction,
 6460        window: &mut Window,
 6461        cx: &mut Context<Self>,
 6462    ) {
 6463        if !self.has_active_inline_completion() {
 6464            self.refresh_inline_completion(false, true, window, cx);
 6465            return;
 6466        }
 6467
 6468        self.update_visible_inline_completion(window, cx);
 6469    }
 6470
 6471    pub fn display_cursor_names(
 6472        &mut self,
 6473        _: &DisplayCursorNames,
 6474        window: &mut Window,
 6475        cx: &mut Context<Self>,
 6476    ) {
 6477        self.show_cursor_names(window, cx);
 6478    }
 6479
 6480    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6481        self.show_cursor_names = true;
 6482        cx.notify();
 6483        cx.spawn_in(window, async move |this, cx| {
 6484            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6485            this.update(cx, |this, cx| {
 6486                this.show_cursor_names = false;
 6487                cx.notify()
 6488            })
 6489            .ok()
 6490        })
 6491        .detach();
 6492    }
 6493
 6494    pub fn next_edit_prediction(
 6495        &mut self,
 6496        _: &NextEditPrediction,
 6497        window: &mut Window,
 6498        cx: &mut Context<Self>,
 6499    ) {
 6500        if self.has_active_inline_completion() {
 6501            self.cycle_inline_completion(Direction::Next, window, cx);
 6502        } else {
 6503            let is_copilot_disabled = self
 6504                .refresh_inline_completion(false, true, window, cx)
 6505                .is_none();
 6506            if is_copilot_disabled {
 6507                cx.propagate();
 6508            }
 6509        }
 6510    }
 6511
 6512    pub fn previous_edit_prediction(
 6513        &mut self,
 6514        _: &PreviousEditPrediction,
 6515        window: &mut Window,
 6516        cx: &mut Context<Self>,
 6517    ) {
 6518        if self.has_active_inline_completion() {
 6519            self.cycle_inline_completion(Direction::Prev, window, cx);
 6520        } else {
 6521            let is_copilot_disabled = self
 6522                .refresh_inline_completion(false, true, window, cx)
 6523                .is_none();
 6524            if is_copilot_disabled {
 6525                cx.propagate();
 6526            }
 6527        }
 6528    }
 6529
 6530    pub fn accept_edit_prediction(
 6531        &mut self,
 6532        _: &AcceptEditPrediction,
 6533        window: &mut Window,
 6534        cx: &mut Context<Self>,
 6535    ) {
 6536        if self.show_edit_predictions_in_menu() {
 6537            self.hide_context_menu(window, cx);
 6538        }
 6539
 6540        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6541            return;
 6542        };
 6543
 6544        self.report_inline_completion_event(
 6545            active_inline_completion.completion_id.clone(),
 6546            true,
 6547            cx,
 6548        );
 6549
 6550        match &active_inline_completion.completion {
 6551            InlineCompletion::Move { target, .. } => {
 6552                let target = *target;
 6553
 6554                if let Some(position_map) = &self.last_position_map {
 6555                    if position_map
 6556                        .visible_row_range
 6557                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6558                        || !self.edit_prediction_requires_modifier()
 6559                    {
 6560                        self.unfold_ranges(&[target..target], true, false, cx);
 6561                        // Note that this is also done in vim's handler of the Tab action.
 6562                        self.change_selections(
 6563                            Some(Autoscroll::newest()),
 6564                            window,
 6565                            cx,
 6566                            |selections| {
 6567                                selections.select_anchor_ranges([target..target]);
 6568                            },
 6569                        );
 6570                        self.clear_row_highlights::<EditPredictionPreview>();
 6571
 6572                        self.edit_prediction_preview
 6573                            .set_previous_scroll_position(None);
 6574                    } else {
 6575                        self.edit_prediction_preview
 6576                            .set_previous_scroll_position(Some(
 6577                                position_map.snapshot.scroll_anchor,
 6578                            ));
 6579
 6580                        self.highlight_rows::<EditPredictionPreview>(
 6581                            target..target,
 6582                            cx.theme().colors().editor_highlighted_line_background,
 6583                            RowHighlightOptions {
 6584                                autoscroll: true,
 6585                                ..Default::default()
 6586                            },
 6587                            cx,
 6588                        );
 6589                        self.request_autoscroll(Autoscroll::fit(), cx);
 6590                    }
 6591                }
 6592            }
 6593            InlineCompletion::Edit { edits, .. } => {
 6594                if let Some(provider) = self.edit_prediction_provider() {
 6595                    provider.accept(cx);
 6596                }
 6597
 6598                let snapshot = self.buffer.read(cx).snapshot(cx);
 6599                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6600
 6601                self.buffer.update(cx, |buffer, cx| {
 6602                    buffer.edit(edits.iter().cloned(), None, cx)
 6603                });
 6604
 6605                self.change_selections(None, window, cx, |s| {
 6606                    s.select_anchor_ranges([last_edit_end..last_edit_end])
 6607                });
 6608
 6609                self.update_visible_inline_completion(window, cx);
 6610                if self.active_inline_completion.is_none() {
 6611                    self.refresh_inline_completion(true, true, window, cx);
 6612                }
 6613
 6614                cx.notify();
 6615            }
 6616        }
 6617
 6618        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6619    }
 6620
 6621    pub fn accept_partial_inline_completion(
 6622        &mut self,
 6623        _: &AcceptPartialEditPrediction,
 6624        window: &mut Window,
 6625        cx: &mut Context<Self>,
 6626    ) {
 6627        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6628            return;
 6629        };
 6630        if self.selections.count() != 1 {
 6631            return;
 6632        }
 6633
 6634        self.report_inline_completion_event(
 6635            active_inline_completion.completion_id.clone(),
 6636            true,
 6637            cx,
 6638        );
 6639
 6640        match &active_inline_completion.completion {
 6641            InlineCompletion::Move { target, .. } => {
 6642                let target = *target;
 6643                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6644                    selections.select_anchor_ranges([target..target]);
 6645                });
 6646            }
 6647            InlineCompletion::Edit { edits, .. } => {
 6648                // Find an insertion that starts at the cursor position.
 6649                let snapshot = self.buffer.read(cx).snapshot(cx);
 6650                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6651                let insertion = edits.iter().find_map(|(range, text)| {
 6652                    let range = range.to_offset(&snapshot);
 6653                    if range.is_empty() && range.start == cursor_offset {
 6654                        Some(text)
 6655                    } else {
 6656                        None
 6657                    }
 6658                });
 6659
 6660                if let Some(text) = insertion {
 6661                    let mut partial_completion = text
 6662                        .chars()
 6663                        .by_ref()
 6664                        .take_while(|c| c.is_alphabetic())
 6665                        .collect::<String>();
 6666                    if partial_completion.is_empty() {
 6667                        partial_completion = text
 6668                            .chars()
 6669                            .by_ref()
 6670                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6671                            .collect::<String>();
 6672                    }
 6673
 6674                    cx.emit(EditorEvent::InputHandled {
 6675                        utf16_range_to_replace: None,
 6676                        text: partial_completion.clone().into(),
 6677                    });
 6678
 6679                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6680
 6681                    self.refresh_inline_completion(true, true, window, cx);
 6682                    cx.notify();
 6683                } else {
 6684                    self.accept_edit_prediction(&Default::default(), window, cx);
 6685                }
 6686            }
 6687        }
 6688    }
 6689
 6690    fn discard_inline_completion(
 6691        &mut self,
 6692        should_report_inline_completion_event: bool,
 6693        cx: &mut Context<Self>,
 6694    ) -> bool {
 6695        if should_report_inline_completion_event {
 6696            let completion_id = self
 6697                .active_inline_completion
 6698                .as_ref()
 6699                .and_then(|active_completion| active_completion.completion_id.clone());
 6700
 6701            self.report_inline_completion_event(completion_id, false, cx);
 6702        }
 6703
 6704        if let Some(provider) = self.edit_prediction_provider() {
 6705            provider.discard(cx);
 6706        }
 6707
 6708        self.take_active_inline_completion(cx)
 6709    }
 6710
 6711    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6712        let Some(provider) = self.edit_prediction_provider() else {
 6713            return;
 6714        };
 6715
 6716        let Some((_, buffer, _)) = self
 6717            .buffer
 6718            .read(cx)
 6719            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6720        else {
 6721            return;
 6722        };
 6723
 6724        let extension = buffer
 6725            .read(cx)
 6726            .file()
 6727            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6728
 6729        let event_type = match accepted {
 6730            true => "Edit Prediction Accepted",
 6731            false => "Edit Prediction Discarded",
 6732        };
 6733        telemetry::event!(
 6734            event_type,
 6735            provider = provider.name(),
 6736            prediction_id = id,
 6737            suggestion_accepted = accepted,
 6738            file_extension = extension,
 6739        );
 6740    }
 6741
 6742    pub fn has_active_inline_completion(&self) -> bool {
 6743        self.active_inline_completion.is_some()
 6744    }
 6745
 6746    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6747        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6748            return false;
 6749        };
 6750
 6751        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6752        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6753        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6754        true
 6755    }
 6756
 6757    /// Returns true when we're displaying the edit prediction popover below the cursor
 6758    /// like we are not previewing and the LSP autocomplete menu is visible
 6759    /// or we are in `when_holding_modifier` mode.
 6760    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6761        if self.edit_prediction_preview_is_active()
 6762            || !self.show_edit_predictions_in_menu()
 6763            || !self.edit_predictions_enabled()
 6764        {
 6765            return false;
 6766        }
 6767
 6768        if self.has_visible_completions_menu() {
 6769            return true;
 6770        }
 6771
 6772        has_completion && self.edit_prediction_requires_modifier()
 6773    }
 6774
 6775    fn handle_modifiers_changed(
 6776        &mut self,
 6777        modifiers: Modifiers,
 6778        position_map: &PositionMap,
 6779        window: &mut Window,
 6780        cx: &mut Context<Self>,
 6781    ) {
 6782        if self.show_edit_predictions_in_menu() {
 6783            self.update_edit_prediction_preview(&modifiers, window, cx);
 6784        }
 6785
 6786        self.update_selection_mode(&modifiers, position_map, window, cx);
 6787
 6788        let mouse_position = window.mouse_position();
 6789        if !position_map.text_hitbox.is_hovered(window) {
 6790            return;
 6791        }
 6792
 6793        self.update_hovered_link(
 6794            position_map.point_for_position(mouse_position),
 6795            &position_map.snapshot,
 6796            modifiers,
 6797            window,
 6798            cx,
 6799        )
 6800    }
 6801
 6802    fn update_selection_mode(
 6803        &mut self,
 6804        modifiers: &Modifiers,
 6805        position_map: &PositionMap,
 6806        window: &mut Window,
 6807        cx: &mut Context<Self>,
 6808    ) {
 6809        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6810            return;
 6811        }
 6812
 6813        let mouse_position = window.mouse_position();
 6814        let point_for_position = position_map.point_for_position(mouse_position);
 6815        let position = point_for_position.previous_valid;
 6816
 6817        self.select(
 6818            SelectPhase::BeginColumnar {
 6819                position,
 6820                reset: false,
 6821                goal_column: point_for_position.exact_unclipped.column(),
 6822            },
 6823            window,
 6824            cx,
 6825        );
 6826    }
 6827
 6828    fn update_edit_prediction_preview(
 6829        &mut self,
 6830        modifiers: &Modifiers,
 6831        window: &mut Window,
 6832        cx: &mut Context<Self>,
 6833    ) {
 6834        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6835        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6836            return;
 6837        };
 6838
 6839        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6840            if matches!(
 6841                self.edit_prediction_preview,
 6842                EditPredictionPreview::Inactive { .. }
 6843            ) {
 6844                self.edit_prediction_preview = EditPredictionPreview::Active {
 6845                    previous_scroll_position: None,
 6846                    since: Instant::now(),
 6847                };
 6848
 6849                self.update_visible_inline_completion(window, cx);
 6850                cx.notify();
 6851            }
 6852        } else if let EditPredictionPreview::Active {
 6853            previous_scroll_position,
 6854            since,
 6855        } = self.edit_prediction_preview
 6856        {
 6857            if let (Some(previous_scroll_position), Some(position_map)) =
 6858                (previous_scroll_position, self.last_position_map.as_ref())
 6859            {
 6860                self.set_scroll_position(
 6861                    previous_scroll_position
 6862                        .scroll_position(&position_map.snapshot.display_snapshot),
 6863                    window,
 6864                    cx,
 6865                );
 6866            }
 6867
 6868            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6869                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6870            };
 6871            self.clear_row_highlights::<EditPredictionPreview>();
 6872            self.update_visible_inline_completion(window, cx);
 6873            cx.notify();
 6874        }
 6875    }
 6876
 6877    fn update_visible_inline_completion(
 6878        &mut self,
 6879        _window: &mut Window,
 6880        cx: &mut Context<Self>,
 6881    ) -> Option<()> {
 6882        let selection = self.selections.newest_anchor();
 6883        let cursor = selection.head();
 6884        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6885        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6886        let excerpt_id = cursor.excerpt_id;
 6887
 6888        let show_in_menu = self.show_edit_predictions_in_menu();
 6889        let completions_menu_has_precedence = !show_in_menu
 6890            && (self.context_menu.borrow().is_some()
 6891                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6892
 6893        if completions_menu_has_precedence
 6894            || !offset_selection.is_empty()
 6895            || self
 6896                .active_inline_completion
 6897                .as_ref()
 6898                .map_or(false, |completion| {
 6899                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6900                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6901                    !invalidation_range.contains(&offset_selection.head())
 6902                })
 6903        {
 6904            self.discard_inline_completion(false, cx);
 6905            return None;
 6906        }
 6907
 6908        self.take_active_inline_completion(cx);
 6909        let Some(provider) = self.edit_prediction_provider() else {
 6910            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6911            return None;
 6912        };
 6913
 6914        let (buffer, cursor_buffer_position) =
 6915            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6916
 6917        self.edit_prediction_settings =
 6918            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6919
 6920        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6921
 6922        if self.edit_prediction_indent_conflict {
 6923            let cursor_point = cursor.to_point(&multibuffer);
 6924
 6925            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6926
 6927            if let Some((_, indent)) = indents.iter().next() {
 6928                if indent.len == cursor_point.column {
 6929                    self.edit_prediction_indent_conflict = false;
 6930                }
 6931            }
 6932        }
 6933
 6934        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6935        let edits = inline_completion
 6936            .edits
 6937            .into_iter()
 6938            .flat_map(|(range, new_text)| {
 6939                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6940                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6941                Some((start..end, new_text))
 6942            })
 6943            .collect::<Vec<_>>();
 6944        if edits.is_empty() {
 6945            return None;
 6946        }
 6947
 6948        let first_edit_start = edits.first().unwrap().0.start;
 6949        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6950        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6951
 6952        let last_edit_end = edits.last().unwrap().0.end;
 6953        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6954        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6955
 6956        let cursor_row = cursor.to_point(&multibuffer).row;
 6957
 6958        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6959
 6960        let mut inlay_ids = Vec::new();
 6961        let invalidation_row_range;
 6962        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6963            Some(cursor_row..edit_end_row)
 6964        } else if cursor_row > edit_end_row {
 6965            Some(edit_start_row..cursor_row)
 6966        } else {
 6967            None
 6968        };
 6969        let is_move =
 6970            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6971        let completion = if is_move {
 6972            invalidation_row_range =
 6973                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6974            let target = first_edit_start;
 6975            InlineCompletion::Move { target, snapshot }
 6976        } else {
 6977            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6978                && !self.inline_completions_hidden_for_vim_mode;
 6979
 6980            if show_completions_in_buffer {
 6981                if edits
 6982                    .iter()
 6983                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6984                {
 6985                    let mut inlays = Vec::new();
 6986                    for (range, new_text) in &edits {
 6987                        let inlay = Inlay::inline_completion(
 6988                            post_inc(&mut self.next_inlay_id),
 6989                            range.start,
 6990                            new_text.as_str(),
 6991                        );
 6992                        inlay_ids.push(inlay.id);
 6993                        inlays.push(inlay);
 6994                    }
 6995
 6996                    self.splice_inlays(&[], inlays, cx);
 6997                } else {
 6998                    let background_color = cx.theme().status().deleted_background;
 6999                    self.highlight_text::<InlineCompletionHighlight>(
 7000                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7001                        HighlightStyle {
 7002                            background_color: Some(background_color),
 7003                            ..Default::default()
 7004                        },
 7005                        cx,
 7006                    );
 7007                }
 7008            }
 7009
 7010            invalidation_row_range = edit_start_row..edit_end_row;
 7011
 7012            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7013                if provider.show_tab_accept_marker() {
 7014                    EditDisplayMode::TabAccept
 7015                } else {
 7016                    EditDisplayMode::Inline
 7017                }
 7018            } else {
 7019                EditDisplayMode::DiffPopover
 7020            };
 7021
 7022            InlineCompletion::Edit {
 7023                edits,
 7024                edit_preview: inline_completion.edit_preview,
 7025                display_mode,
 7026                snapshot,
 7027            }
 7028        };
 7029
 7030        let invalidation_range = multibuffer
 7031            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7032            ..multibuffer.anchor_after(Point::new(
 7033                invalidation_row_range.end,
 7034                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7035            ));
 7036
 7037        self.stale_inline_completion_in_menu = None;
 7038        self.active_inline_completion = Some(InlineCompletionState {
 7039            inlay_ids,
 7040            completion,
 7041            completion_id: inline_completion.id,
 7042            invalidation_range,
 7043        });
 7044
 7045        cx.notify();
 7046
 7047        Some(())
 7048    }
 7049
 7050    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7051        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7052    }
 7053
 7054    fn clear_tasks(&mut self) {
 7055        self.tasks.clear()
 7056    }
 7057
 7058    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7059        if self.tasks.insert(key, value).is_some() {
 7060            // This case should hopefully be rare, but just in case...
 7061            log::error!(
 7062                "multiple different run targets found on a single line, only the last target will be rendered"
 7063            )
 7064        }
 7065    }
 7066
 7067    /// Get all display points of breakpoints that will be rendered within editor
 7068    ///
 7069    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7070    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7071    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7072    fn active_breakpoints(
 7073        &self,
 7074        range: Range<DisplayRow>,
 7075        window: &mut Window,
 7076        cx: &mut Context<Self>,
 7077    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7078        let mut breakpoint_display_points = HashMap::default();
 7079
 7080        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7081            return breakpoint_display_points;
 7082        };
 7083
 7084        let snapshot = self.snapshot(window, cx);
 7085
 7086        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7087        let Some(project) = self.project.as_ref() else {
 7088            return breakpoint_display_points;
 7089        };
 7090
 7091        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7092            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7093
 7094        for (buffer_snapshot, range, excerpt_id) in
 7095            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7096        {
 7097            let Some(buffer) = project.read_with(cx, |this, cx| {
 7098                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7099            }) else {
 7100                continue;
 7101            };
 7102            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7103                &buffer,
 7104                Some(
 7105                    buffer_snapshot.anchor_before(range.start)
 7106                        ..buffer_snapshot.anchor_after(range.end),
 7107                ),
 7108                buffer_snapshot,
 7109                cx,
 7110            );
 7111            for (breakpoint, state) in breakpoints {
 7112                let multi_buffer_anchor =
 7113                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7114                let position = multi_buffer_anchor
 7115                    .to_point(&multi_buffer_snapshot)
 7116                    .to_display_point(&snapshot);
 7117
 7118                breakpoint_display_points.insert(
 7119                    position.row(),
 7120                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7121                );
 7122            }
 7123        }
 7124
 7125        breakpoint_display_points
 7126    }
 7127
 7128    fn breakpoint_context_menu(
 7129        &self,
 7130        anchor: Anchor,
 7131        window: &mut Window,
 7132        cx: &mut Context<Self>,
 7133    ) -> Entity<ui::ContextMenu> {
 7134        let weak_editor = cx.weak_entity();
 7135        let focus_handle = self.focus_handle(cx);
 7136
 7137        let row = self
 7138            .buffer
 7139            .read(cx)
 7140            .snapshot(cx)
 7141            .summary_for_anchor::<Point>(&anchor)
 7142            .row;
 7143
 7144        let breakpoint = self
 7145            .breakpoint_at_row(row, window, cx)
 7146            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7147
 7148        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7149            "Edit Log Breakpoint"
 7150        } else {
 7151            "Set Log Breakpoint"
 7152        };
 7153
 7154        let condition_breakpoint_msg = if breakpoint
 7155            .as_ref()
 7156            .is_some_and(|bp| bp.1.condition.is_some())
 7157        {
 7158            "Edit Condition Breakpoint"
 7159        } else {
 7160            "Set Condition Breakpoint"
 7161        };
 7162
 7163        let hit_condition_breakpoint_msg = if breakpoint
 7164            .as_ref()
 7165            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7166        {
 7167            "Edit Hit Condition Breakpoint"
 7168        } else {
 7169            "Set Hit Condition Breakpoint"
 7170        };
 7171
 7172        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7173            "Unset Breakpoint"
 7174        } else {
 7175            "Set Breakpoint"
 7176        };
 7177
 7178        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7179            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7180
 7181        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7182            BreakpointState::Enabled => Some("Disable"),
 7183            BreakpointState::Disabled => Some("Enable"),
 7184        });
 7185
 7186        let (anchor, breakpoint) =
 7187            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7188
 7189        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7190            menu.on_blur_subscription(Subscription::new(|| {}))
 7191                .context(focus_handle)
 7192                .when(run_to_cursor, |this| {
 7193                    let weak_editor = weak_editor.clone();
 7194                    this.entry("Run to cursor", None, move |window, cx| {
 7195                        weak_editor
 7196                            .update(cx, |editor, cx| {
 7197                                editor.change_selections(None, window, cx, |s| {
 7198                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7199                                });
 7200                            })
 7201                            .ok();
 7202
 7203                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7204                    })
 7205                    .separator()
 7206                })
 7207                .when_some(toggle_state_msg, |this, msg| {
 7208                    this.entry(msg, None, {
 7209                        let weak_editor = weak_editor.clone();
 7210                        let breakpoint = breakpoint.clone();
 7211                        move |_window, cx| {
 7212                            weak_editor
 7213                                .update(cx, |this, cx| {
 7214                                    this.edit_breakpoint_at_anchor(
 7215                                        anchor,
 7216                                        breakpoint.as_ref().clone(),
 7217                                        BreakpointEditAction::InvertState,
 7218                                        cx,
 7219                                    );
 7220                                })
 7221                                .log_err();
 7222                        }
 7223                    })
 7224                })
 7225                .entry(set_breakpoint_msg, None, {
 7226                    let weak_editor = weak_editor.clone();
 7227                    let breakpoint = breakpoint.clone();
 7228                    move |_window, cx| {
 7229                        weak_editor
 7230                            .update(cx, |this, cx| {
 7231                                this.edit_breakpoint_at_anchor(
 7232                                    anchor,
 7233                                    breakpoint.as_ref().clone(),
 7234                                    BreakpointEditAction::Toggle,
 7235                                    cx,
 7236                                );
 7237                            })
 7238                            .log_err();
 7239                    }
 7240                })
 7241                .entry(log_breakpoint_msg, None, {
 7242                    let breakpoint = breakpoint.clone();
 7243                    let weak_editor = weak_editor.clone();
 7244                    move |window, cx| {
 7245                        weak_editor
 7246                            .update(cx, |this, cx| {
 7247                                this.add_edit_breakpoint_block(
 7248                                    anchor,
 7249                                    breakpoint.as_ref(),
 7250                                    BreakpointPromptEditAction::Log,
 7251                                    window,
 7252                                    cx,
 7253                                );
 7254                            })
 7255                            .log_err();
 7256                    }
 7257                })
 7258                .entry(condition_breakpoint_msg, None, {
 7259                    let breakpoint = breakpoint.clone();
 7260                    let weak_editor = weak_editor.clone();
 7261                    move |window, cx| {
 7262                        weak_editor
 7263                            .update(cx, |this, cx| {
 7264                                this.add_edit_breakpoint_block(
 7265                                    anchor,
 7266                                    breakpoint.as_ref(),
 7267                                    BreakpointPromptEditAction::Condition,
 7268                                    window,
 7269                                    cx,
 7270                                );
 7271                            })
 7272                            .log_err();
 7273                    }
 7274                })
 7275                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7276                    weak_editor
 7277                        .update(cx, |this, cx| {
 7278                            this.add_edit_breakpoint_block(
 7279                                anchor,
 7280                                breakpoint.as_ref(),
 7281                                BreakpointPromptEditAction::HitCondition,
 7282                                window,
 7283                                cx,
 7284                            );
 7285                        })
 7286                        .log_err();
 7287                })
 7288        })
 7289    }
 7290
 7291    fn render_breakpoint(
 7292        &self,
 7293        position: Anchor,
 7294        row: DisplayRow,
 7295        breakpoint: &Breakpoint,
 7296        state: Option<BreakpointSessionState>,
 7297        cx: &mut Context<Self>,
 7298    ) -> IconButton {
 7299        let is_rejected = state.is_some_and(|s| !s.verified);
 7300        // Is it a breakpoint that shows up when hovering over gutter?
 7301        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7302            (false, false),
 7303            |PhantomBreakpointIndicator {
 7304                 is_active,
 7305                 display_row,
 7306                 collides_with_existing_breakpoint,
 7307             }| {
 7308                (
 7309                    is_active && display_row == row,
 7310                    collides_with_existing_breakpoint,
 7311                )
 7312            },
 7313        );
 7314
 7315        let (color, icon) = {
 7316            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7317                (false, false) => ui::IconName::DebugBreakpoint,
 7318                (true, false) => ui::IconName::DebugLogBreakpoint,
 7319                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7320                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7321            };
 7322
 7323            let color = if is_phantom {
 7324                Color::Hint
 7325            } else if is_rejected {
 7326                Color::Disabled
 7327            } else {
 7328                Color::Debugger
 7329            };
 7330
 7331            (color, icon)
 7332        };
 7333
 7334        let breakpoint = Arc::from(breakpoint.clone());
 7335
 7336        let alt_as_text = gpui::Keystroke {
 7337            modifiers: Modifiers::secondary_key(),
 7338            ..Default::default()
 7339        };
 7340        let primary_action_text = if breakpoint.is_disabled() {
 7341            "Enable breakpoint"
 7342        } else if is_phantom && !collides_with_existing {
 7343            "Set breakpoint"
 7344        } else {
 7345            "Unset breakpoint"
 7346        };
 7347        let focus_handle = self.focus_handle.clone();
 7348
 7349        let meta = if is_rejected {
 7350            SharedString::from("No executable code is associated with this line.")
 7351        } else if collides_with_existing && !breakpoint.is_disabled() {
 7352            SharedString::from(format!(
 7353                "{alt_as_text}-click to disable,\nright-click for more options."
 7354            ))
 7355        } else {
 7356            SharedString::from("Right-click for more options.")
 7357        };
 7358        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7359            .icon_size(IconSize::XSmall)
 7360            .size(ui::ButtonSize::None)
 7361            .when(is_rejected, |this| {
 7362                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7363            })
 7364            .icon_color(color)
 7365            .style(ButtonStyle::Transparent)
 7366            .on_click(cx.listener({
 7367                let breakpoint = breakpoint.clone();
 7368
 7369                move |editor, event: &ClickEvent, window, cx| {
 7370                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7371                        BreakpointEditAction::InvertState
 7372                    } else {
 7373                        BreakpointEditAction::Toggle
 7374                    };
 7375
 7376                    window.focus(&editor.focus_handle(cx));
 7377                    editor.edit_breakpoint_at_anchor(
 7378                        position,
 7379                        breakpoint.as_ref().clone(),
 7380                        edit_action,
 7381                        cx,
 7382                    );
 7383                }
 7384            }))
 7385            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7386                editor.set_breakpoint_context_menu(
 7387                    row,
 7388                    Some(position),
 7389                    event.down.position,
 7390                    window,
 7391                    cx,
 7392                );
 7393            }))
 7394            .tooltip(move |window, cx| {
 7395                Tooltip::with_meta_in(
 7396                    primary_action_text,
 7397                    Some(&ToggleBreakpoint),
 7398                    meta.clone(),
 7399                    &focus_handle,
 7400                    window,
 7401                    cx,
 7402                )
 7403            })
 7404    }
 7405
 7406    fn build_tasks_context(
 7407        project: &Entity<Project>,
 7408        buffer: &Entity<Buffer>,
 7409        buffer_row: u32,
 7410        tasks: &Arc<RunnableTasks>,
 7411        cx: &mut Context<Self>,
 7412    ) -> Task<Option<task::TaskContext>> {
 7413        let position = Point::new(buffer_row, tasks.column);
 7414        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7415        let location = Location {
 7416            buffer: buffer.clone(),
 7417            range: range_start..range_start,
 7418        };
 7419        // Fill in the environmental variables from the tree-sitter captures
 7420        let mut captured_task_variables = TaskVariables::default();
 7421        for (capture_name, value) in tasks.extra_variables.clone() {
 7422            captured_task_variables.insert(
 7423                task::VariableName::Custom(capture_name.into()),
 7424                value.clone(),
 7425            );
 7426        }
 7427        project.update(cx, |project, cx| {
 7428            project.task_store().update(cx, |task_store, cx| {
 7429                task_store.task_context_for_location(captured_task_variables, location, cx)
 7430            })
 7431        })
 7432    }
 7433
 7434    pub fn spawn_nearest_task(
 7435        &mut self,
 7436        action: &SpawnNearestTask,
 7437        window: &mut Window,
 7438        cx: &mut Context<Self>,
 7439    ) {
 7440        let Some((workspace, _)) = self.workspace.clone() else {
 7441            return;
 7442        };
 7443        let Some(project) = self.project.clone() else {
 7444            return;
 7445        };
 7446
 7447        // Try to find a closest, enclosing node using tree-sitter that has a
 7448        // task
 7449        let Some((buffer, buffer_row, tasks)) = self
 7450            .find_enclosing_node_task(cx)
 7451            // Or find the task that's closest in row-distance.
 7452            .or_else(|| self.find_closest_task(cx))
 7453        else {
 7454            return;
 7455        };
 7456
 7457        let reveal_strategy = action.reveal;
 7458        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7459        cx.spawn_in(window, async move |_, cx| {
 7460            let context = task_context.await?;
 7461            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7462
 7463            let resolved = &mut resolved_task.resolved;
 7464            resolved.reveal = reveal_strategy;
 7465
 7466            workspace
 7467                .update_in(cx, |workspace, window, cx| {
 7468                    workspace.schedule_resolved_task(
 7469                        task_source_kind,
 7470                        resolved_task,
 7471                        false,
 7472                        window,
 7473                        cx,
 7474                    );
 7475                })
 7476                .ok()
 7477        })
 7478        .detach();
 7479    }
 7480
 7481    fn find_closest_task(
 7482        &mut self,
 7483        cx: &mut Context<Self>,
 7484    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7485        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7486
 7487        let ((buffer_id, row), tasks) = self
 7488            .tasks
 7489            .iter()
 7490            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7491
 7492        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7493        let tasks = Arc::new(tasks.to_owned());
 7494        Some((buffer, *row, tasks))
 7495    }
 7496
 7497    fn find_enclosing_node_task(
 7498        &mut self,
 7499        cx: &mut Context<Self>,
 7500    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7501        let snapshot = self.buffer.read(cx).snapshot(cx);
 7502        let offset = self.selections.newest::<usize>(cx).head();
 7503        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7504        let buffer_id = excerpt.buffer().remote_id();
 7505
 7506        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7507        let mut cursor = layer.node().walk();
 7508
 7509        while cursor.goto_first_child_for_byte(offset).is_some() {
 7510            if cursor.node().end_byte() == offset {
 7511                cursor.goto_next_sibling();
 7512            }
 7513        }
 7514
 7515        // Ascend to the smallest ancestor that contains the range and has a task.
 7516        loop {
 7517            let node = cursor.node();
 7518            let node_range = node.byte_range();
 7519            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7520
 7521            // Check if this node contains our offset
 7522            if node_range.start <= offset && node_range.end >= offset {
 7523                // If it contains offset, check for task
 7524                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7525                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7526                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7527                }
 7528            }
 7529
 7530            if !cursor.goto_parent() {
 7531                break;
 7532            }
 7533        }
 7534        None
 7535    }
 7536
 7537    fn render_run_indicator(
 7538        &self,
 7539        _style: &EditorStyle,
 7540        is_active: bool,
 7541        row: DisplayRow,
 7542        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7543        cx: &mut Context<Self>,
 7544    ) -> IconButton {
 7545        let color = Color::Muted;
 7546        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7547
 7548        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7549            .shape(ui::IconButtonShape::Square)
 7550            .icon_size(IconSize::XSmall)
 7551            .icon_color(color)
 7552            .toggle_state(is_active)
 7553            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7554                let quick_launch = e.down.button == MouseButton::Left;
 7555                window.focus(&editor.focus_handle(cx));
 7556                editor.toggle_code_actions(
 7557                    &ToggleCodeActions {
 7558                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7559                        quick_launch,
 7560                    },
 7561                    window,
 7562                    cx,
 7563                );
 7564            }))
 7565            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7566                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7567            }))
 7568    }
 7569
 7570    pub fn context_menu_visible(&self) -> bool {
 7571        !self.edit_prediction_preview_is_active()
 7572            && self
 7573                .context_menu
 7574                .borrow()
 7575                .as_ref()
 7576                .map_or(false, |menu| menu.visible())
 7577    }
 7578
 7579    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7580        self.context_menu
 7581            .borrow()
 7582            .as_ref()
 7583            .map(|menu| menu.origin())
 7584    }
 7585
 7586    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7587        self.context_menu_options = Some(options);
 7588    }
 7589
 7590    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7591    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7592
 7593    fn render_edit_prediction_popover(
 7594        &mut self,
 7595        text_bounds: &Bounds<Pixels>,
 7596        content_origin: gpui::Point<Pixels>,
 7597        right_margin: Pixels,
 7598        editor_snapshot: &EditorSnapshot,
 7599        visible_row_range: Range<DisplayRow>,
 7600        scroll_top: f32,
 7601        scroll_bottom: f32,
 7602        line_layouts: &[LineWithInvisibles],
 7603        line_height: Pixels,
 7604        scroll_pixel_position: gpui::Point<Pixels>,
 7605        newest_selection_head: Option<DisplayPoint>,
 7606        editor_width: Pixels,
 7607        style: &EditorStyle,
 7608        window: &mut Window,
 7609        cx: &mut App,
 7610    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7611        if self.mode().is_minimap() {
 7612            return None;
 7613        }
 7614        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7615
 7616        if self.edit_prediction_visible_in_cursor_popover(true) {
 7617            return None;
 7618        }
 7619
 7620        match &active_inline_completion.completion {
 7621            InlineCompletion::Move { target, .. } => {
 7622                let target_display_point = target.to_display_point(editor_snapshot);
 7623
 7624                if self.edit_prediction_requires_modifier() {
 7625                    if !self.edit_prediction_preview_is_active() {
 7626                        return None;
 7627                    }
 7628
 7629                    self.render_edit_prediction_modifier_jump_popover(
 7630                        text_bounds,
 7631                        content_origin,
 7632                        visible_row_range,
 7633                        line_layouts,
 7634                        line_height,
 7635                        scroll_pixel_position,
 7636                        newest_selection_head,
 7637                        target_display_point,
 7638                        window,
 7639                        cx,
 7640                    )
 7641                } else {
 7642                    self.render_edit_prediction_eager_jump_popover(
 7643                        text_bounds,
 7644                        content_origin,
 7645                        editor_snapshot,
 7646                        visible_row_range,
 7647                        scroll_top,
 7648                        scroll_bottom,
 7649                        line_height,
 7650                        scroll_pixel_position,
 7651                        target_display_point,
 7652                        editor_width,
 7653                        window,
 7654                        cx,
 7655                    )
 7656                }
 7657            }
 7658            InlineCompletion::Edit {
 7659                display_mode: EditDisplayMode::Inline,
 7660                ..
 7661            } => None,
 7662            InlineCompletion::Edit {
 7663                display_mode: EditDisplayMode::TabAccept,
 7664                edits,
 7665                ..
 7666            } => {
 7667                let range = &edits.first()?.0;
 7668                let target_display_point = range.end.to_display_point(editor_snapshot);
 7669
 7670                self.render_edit_prediction_end_of_line_popover(
 7671                    "Accept",
 7672                    editor_snapshot,
 7673                    visible_row_range,
 7674                    target_display_point,
 7675                    line_height,
 7676                    scroll_pixel_position,
 7677                    content_origin,
 7678                    editor_width,
 7679                    window,
 7680                    cx,
 7681                )
 7682            }
 7683            InlineCompletion::Edit {
 7684                edits,
 7685                edit_preview,
 7686                display_mode: EditDisplayMode::DiffPopover,
 7687                snapshot,
 7688            } => self.render_edit_prediction_diff_popover(
 7689                text_bounds,
 7690                content_origin,
 7691                right_margin,
 7692                editor_snapshot,
 7693                visible_row_range,
 7694                line_layouts,
 7695                line_height,
 7696                scroll_pixel_position,
 7697                newest_selection_head,
 7698                editor_width,
 7699                style,
 7700                edits,
 7701                edit_preview,
 7702                snapshot,
 7703                window,
 7704                cx,
 7705            ),
 7706        }
 7707    }
 7708
 7709    fn render_edit_prediction_modifier_jump_popover(
 7710        &mut self,
 7711        text_bounds: &Bounds<Pixels>,
 7712        content_origin: gpui::Point<Pixels>,
 7713        visible_row_range: Range<DisplayRow>,
 7714        line_layouts: &[LineWithInvisibles],
 7715        line_height: Pixels,
 7716        scroll_pixel_position: gpui::Point<Pixels>,
 7717        newest_selection_head: Option<DisplayPoint>,
 7718        target_display_point: DisplayPoint,
 7719        window: &mut Window,
 7720        cx: &mut App,
 7721    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7722        let scrolled_content_origin =
 7723            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7724
 7725        const SCROLL_PADDING_Y: Pixels = px(12.);
 7726
 7727        if target_display_point.row() < visible_row_range.start {
 7728            return self.render_edit_prediction_scroll_popover(
 7729                |_| SCROLL_PADDING_Y,
 7730                IconName::ArrowUp,
 7731                visible_row_range,
 7732                line_layouts,
 7733                newest_selection_head,
 7734                scrolled_content_origin,
 7735                window,
 7736                cx,
 7737            );
 7738        } else if target_display_point.row() >= visible_row_range.end {
 7739            return self.render_edit_prediction_scroll_popover(
 7740                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7741                IconName::ArrowDown,
 7742                visible_row_range,
 7743                line_layouts,
 7744                newest_selection_head,
 7745                scrolled_content_origin,
 7746                window,
 7747                cx,
 7748            );
 7749        }
 7750
 7751        const POLE_WIDTH: Pixels = px(2.);
 7752
 7753        let line_layout =
 7754            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7755        let target_column = target_display_point.column() as usize;
 7756
 7757        let target_x = line_layout.x_for_index(target_column);
 7758        let target_y =
 7759            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7760
 7761        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7762
 7763        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7764        border_color.l += 0.001;
 7765
 7766        let mut element = v_flex()
 7767            .items_end()
 7768            .when(flag_on_right, |el| el.items_start())
 7769            .child(if flag_on_right {
 7770                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7771                    .rounded_bl(px(0.))
 7772                    .rounded_tl(px(0.))
 7773                    .border_l_2()
 7774                    .border_color(border_color)
 7775            } else {
 7776                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7777                    .rounded_br(px(0.))
 7778                    .rounded_tr(px(0.))
 7779                    .border_r_2()
 7780                    .border_color(border_color)
 7781            })
 7782            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7783            .into_any();
 7784
 7785        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7786
 7787        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7788            - point(
 7789                if flag_on_right {
 7790                    POLE_WIDTH
 7791                } else {
 7792                    size.width - POLE_WIDTH
 7793                },
 7794                size.height - line_height,
 7795            );
 7796
 7797        origin.x = origin.x.max(content_origin.x);
 7798
 7799        element.prepaint_at(origin, window, cx);
 7800
 7801        Some((element, origin))
 7802    }
 7803
 7804    fn render_edit_prediction_scroll_popover(
 7805        &mut self,
 7806        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7807        scroll_icon: IconName,
 7808        visible_row_range: Range<DisplayRow>,
 7809        line_layouts: &[LineWithInvisibles],
 7810        newest_selection_head: Option<DisplayPoint>,
 7811        scrolled_content_origin: gpui::Point<Pixels>,
 7812        window: &mut Window,
 7813        cx: &mut App,
 7814    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7815        let mut element = self
 7816            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7817            .into_any();
 7818
 7819        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7820
 7821        let cursor = newest_selection_head?;
 7822        let cursor_row_layout =
 7823            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7824        let cursor_column = cursor.column() as usize;
 7825
 7826        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7827
 7828        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7829
 7830        element.prepaint_at(origin, window, cx);
 7831        Some((element, origin))
 7832    }
 7833
 7834    fn render_edit_prediction_eager_jump_popover(
 7835        &mut self,
 7836        text_bounds: &Bounds<Pixels>,
 7837        content_origin: gpui::Point<Pixels>,
 7838        editor_snapshot: &EditorSnapshot,
 7839        visible_row_range: Range<DisplayRow>,
 7840        scroll_top: f32,
 7841        scroll_bottom: f32,
 7842        line_height: Pixels,
 7843        scroll_pixel_position: gpui::Point<Pixels>,
 7844        target_display_point: DisplayPoint,
 7845        editor_width: Pixels,
 7846        window: &mut Window,
 7847        cx: &mut App,
 7848    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7849        if target_display_point.row().as_f32() < scroll_top {
 7850            let mut element = self
 7851                .render_edit_prediction_line_popover(
 7852                    "Jump to Edit",
 7853                    Some(IconName::ArrowUp),
 7854                    window,
 7855                    cx,
 7856                )?
 7857                .into_any();
 7858
 7859            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7860            let offset = point(
 7861                (text_bounds.size.width - size.width) / 2.,
 7862                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7863            );
 7864
 7865            let origin = text_bounds.origin + offset;
 7866            element.prepaint_at(origin, window, cx);
 7867            Some((element, origin))
 7868        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7869            let mut element = self
 7870                .render_edit_prediction_line_popover(
 7871                    "Jump to Edit",
 7872                    Some(IconName::ArrowDown),
 7873                    window,
 7874                    cx,
 7875                )?
 7876                .into_any();
 7877
 7878            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7879            let offset = point(
 7880                (text_bounds.size.width - size.width) / 2.,
 7881                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7882            );
 7883
 7884            let origin = text_bounds.origin + offset;
 7885            element.prepaint_at(origin, window, cx);
 7886            Some((element, origin))
 7887        } else {
 7888            self.render_edit_prediction_end_of_line_popover(
 7889                "Jump to Edit",
 7890                editor_snapshot,
 7891                visible_row_range,
 7892                target_display_point,
 7893                line_height,
 7894                scroll_pixel_position,
 7895                content_origin,
 7896                editor_width,
 7897                window,
 7898                cx,
 7899            )
 7900        }
 7901    }
 7902
 7903    fn render_edit_prediction_end_of_line_popover(
 7904        self: &mut Editor,
 7905        label: &'static str,
 7906        editor_snapshot: &EditorSnapshot,
 7907        visible_row_range: Range<DisplayRow>,
 7908        target_display_point: DisplayPoint,
 7909        line_height: Pixels,
 7910        scroll_pixel_position: gpui::Point<Pixels>,
 7911        content_origin: gpui::Point<Pixels>,
 7912        editor_width: Pixels,
 7913        window: &mut Window,
 7914        cx: &mut App,
 7915    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7916        let target_line_end = DisplayPoint::new(
 7917            target_display_point.row(),
 7918            editor_snapshot.line_len(target_display_point.row()),
 7919        );
 7920
 7921        let mut element = self
 7922            .render_edit_prediction_line_popover(label, None, window, cx)?
 7923            .into_any();
 7924
 7925        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7926
 7927        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7928
 7929        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7930        let mut origin = start_point
 7931            + line_origin
 7932            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7933        origin.x = origin.x.max(content_origin.x);
 7934
 7935        let max_x = content_origin.x + editor_width - size.width;
 7936
 7937        if origin.x > max_x {
 7938            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7939
 7940            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7941                origin.y += offset;
 7942                IconName::ArrowUp
 7943            } else {
 7944                origin.y -= offset;
 7945                IconName::ArrowDown
 7946            };
 7947
 7948            element = self
 7949                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7950                .into_any();
 7951
 7952            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7953
 7954            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7955        }
 7956
 7957        element.prepaint_at(origin, window, cx);
 7958        Some((element, origin))
 7959    }
 7960
 7961    fn render_edit_prediction_diff_popover(
 7962        self: &Editor,
 7963        text_bounds: &Bounds<Pixels>,
 7964        content_origin: gpui::Point<Pixels>,
 7965        right_margin: Pixels,
 7966        editor_snapshot: &EditorSnapshot,
 7967        visible_row_range: Range<DisplayRow>,
 7968        line_layouts: &[LineWithInvisibles],
 7969        line_height: Pixels,
 7970        scroll_pixel_position: gpui::Point<Pixels>,
 7971        newest_selection_head: Option<DisplayPoint>,
 7972        editor_width: Pixels,
 7973        style: &EditorStyle,
 7974        edits: &Vec<(Range<Anchor>, String)>,
 7975        edit_preview: &Option<language::EditPreview>,
 7976        snapshot: &language::BufferSnapshot,
 7977        window: &mut Window,
 7978        cx: &mut App,
 7979    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7980        let edit_start = edits
 7981            .first()
 7982            .unwrap()
 7983            .0
 7984            .start
 7985            .to_display_point(editor_snapshot);
 7986        let edit_end = edits
 7987            .last()
 7988            .unwrap()
 7989            .0
 7990            .end
 7991            .to_display_point(editor_snapshot);
 7992
 7993        let is_visible = visible_row_range.contains(&edit_start.row())
 7994            || visible_row_range.contains(&edit_end.row());
 7995        if !is_visible {
 7996            return None;
 7997        }
 7998
 7999        let highlighted_edits =
 8000            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8001
 8002        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8003        let line_count = highlighted_edits.text.lines().count();
 8004
 8005        const BORDER_WIDTH: Pixels = px(1.);
 8006
 8007        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8008        let has_keybind = keybind.is_some();
 8009
 8010        let mut element = h_flex()
 8011            .items_start()
 8012            .child(
 8013                h_flex()
 8014                    .bg(cx.theme().colors().editor_background)
 8015                    .border(BORDER_WIDTH)
 8016                    .shadow_sm()
 8017                    .border_color(cx.theme().colors().border)
 8018                    .rounded_l_lg()
 8019                    .when(line_count > 1, |el| el.rounded_br_lg())
 8020                    .pr_1()
 8021                    .child(styled_text),
 8022            )
 8023            .child(
 8024                h_flex()
 8025                    .h(line_height + BORDER_WIDTH * 2.)
 8026                    .px_1p5()
 8027                    .gap_1()
 8028                    // Workaround: For some reason, there's a gap if we don't do this
 8029                    .ml(-BORDER_WIDTH)
 8030                    .shadow(smallvec![gpui::BoxShadow {
 8031                        color: gpui::black().opacity(0.05),
 8032                        offset: point(px(1.), px(1.)),
 8033                        blur_radius: px(2.),
 8034                        spread_radius: px(0.),
 8035                    }])
 8036                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8037                    .border(BORDER_WIDTH)
 8038                    .border_color(cx.theme().colors().border)
 8039                    .rounded_r_lg()
 8040                    .id("edit_prediction_diff_popover_keybind")
 8041                    .when(!has_keybind, |el| {
 8042                        let status_colors = cx.theme().status();
 8043
 8044                        el.bg(status_colors.error_background)
 8045                            .border_color(status_colors.error.opacity(0.6))
 8046                            .child(Icon::new(IconName::Info).color(Color::Error))
 8047                            .cursor_default()
 8048                            .hoverable_tooltip(move |_window, cx| {
 8049                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8050                            })
 8051                    })
 8052                    .children(keybind),
 8053            )
 8054            .into_any();
 8055
 8056        let longest_row =
 8057            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8058        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8059            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8060        } else {
 8061            layout_line(
 8062                longest_row,
 8063                editor_snapshot,
 8064                style,
 8065                editor_width,
 8066                |_| false,
 8067                window,
 8068                cx,
 8069            )
 8070            .width
 8071        };
 8072
 8073        let viewport_bounds =
 8074            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8075                right: -right_margin,
 8076                ..Default::default()
 8077            });
 8078
 8079        let x_after_longest =
 8080            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8081                - scroll_pixel_position.x;
 8082
 8083        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8084
 8085        // Fully visible if it can be displayed within the window (allow overlapping other
 8086        // panes). However, this is only allowed if the popover starts within text_bounds.
 8087        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8088            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8089
 8090        let mut origin = if can_position_to_the_right {
 8091            point(
 8092                x_after_longest,
 8093                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8094                    - scroll_pixel_position.y,
 8095            )
 8096        } else {
 8097            let cursor_row = newest_selection_head.map(|head| head.row());
 8098            let above_edit = edit_start
 8099                .row()
 8100                .0
 8101                .checked_sub(line_count as u32)
 8102                .map(DisplayRow);
 8103            let below_edit = Some(edit_end.row() + 1);
 8104            let above_cursor =
 8105                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8106            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8107
 8108            // Place the edit popover adjacent to the edit if there is a location
 8109            // available that is onscreen and does not obscure the cursor. Otherwise,
 8110            // place it adjacent to the cursor.
 8111            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8112                .into_iter()
 8113                .flatten()
 8114                .find(|&start_row| {
 8115                    let end_row = start_row + line_count as u32;
 8116                    visible_row_range.contains(&start_row)
 8117                        && visible_row_range.contains(&end_row)
 8118                        && cursor_row.map_or(true, |cursor_row| {
 8119                            !((start_row..end_row).contains(&cursor_row))
 8120                        })
 8121                })?;
 8122
 8123            content_origin
 8124                + point(
 8125                    -scroll_pixel_position.x,
 8126                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8127                )
 8128        };
 8129
 8130        origin.x -= BORDER_WIDTH;
 8131
 8132        window.defer_draw(element, origin, 1);
 8133
 8134        // Do not return an element, since it will already be drawn due to defer_draw.
 8135        None
 8136    }
 8137
 8138    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8139        px(30.)
 8140    }
 8141
 8142    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8143        if self.read_only(cx) {
 8144            cx.theme().players().read_only()
 8145        } else {
 8146            self.style.as_ref().unwrap().local_player
 8147        }
 8148    }
 8149
 8150    fn render_edit_prediction_accept_keybind(
 8151        &self,
 8152        window: &mut Window,
 8153        cx: &App,
 8154    ) -> Option<AnyElement> {
 8155        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8156        let accept_keystroke = accept_binding.keystroke()?;
 8157
 8158        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8159
 8160        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8161            Color::Accent
 8162        } else {
 8163            Color::Muted
 8164        };
 8165
 8166        h_flex()
 8167            .px_0p5()
 8168            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8169            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8170            .text_size(TextSize::XSmall.rems(cx))
 8171            .child(h_flex().children(ui::render_modifiers(
 8172                &accept_keystroke.modifiers,
 8173                PlatformStyle::platform(),
 8174                Some(modifiers_color),
 8175                Some(IconSize::XSmall.rems().into()),
 8176                true,
 8177            )))
 8178            .when(is_platform_style_mac, |parent| {
 8179                parent.child(accept_keystroke.key.clone())
 8180            })
 8181            .when(!is_platform_style_mac, |parent| {
 8182                parent.child(
 8183                    Key::new(
 8184                        util::capitalize(&accept_keystroke.key),
 8185                        Some(Color::Default),
 8186                    )
 8187                    .size(Some(IconSize::XSmall.rems().into())),
 8188                )
 8189            })
 8190            .into_any()
 8191            .into()
 8192    }
 8193
 8194    fn render_edit_prediction_line_popover(
 8195        &self,
 8196        label: impl Into<SharedString>,
 8197        icon: Option<IconName>,
 8198        window: &mut Window,
 8199        cx: &App,
 8200    ) -> Option<Stateful<Div>> {
 8201        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8202
 8203        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8204        let has_keybind = keybind.is_some();
 8205
 8206        let result = h_flex()
 8207            .id("ep-line-popover")
 8208            .py_0p5()
 8209            .pl_1()
 8210            .pr(padding_right)
 8211            .gap_1()
 8212            .rounded_md()
 8213            .border_1()
 8214            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8215            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8216            .shadow_sm()
 8217            .when(!has_keybind, |el| {
 8218                let status_colors = cx.theme().status();
 8219
 8220                el.bg(status_colors.error_background)
 8221                    .border_color(status_colors.error.opacity(0.6))
 8222                    .pl_2()
 8223                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8224                    .cursor_default()
 8225                    .hoverable_tooltip(move |_window, cx| {
 8226                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8227                    })
 8228            })
 8229            .children(keybind)
 8230            .child(
 8231                Label::new(label)
 8232                    .size(LabelSize::Small)
 8233                    .when(!has_keybind, |el| {
 8234                        el.color(cx.theme().status().error.into()).strikethrough()
 8235                    }),
 8236            )
 8237            .when(!has_keybind, |el| {
 8238                el.child(
 8239                    h_flex().ml_1().child(
 8240                        Icon::new(IconName::Info)
 8241                            .size(IconSize::Small)
 8242                            .color(cx.theme().status().error.into()),
 8243                    ),
 8244                )
 8245            })
 8246            .when_some(icon, |element, icon| {
 8247                element.child(
 8248                    div()
 8249                        .mt(px(1.5))
 8250                        .child(Icon::new(icon).size(IconSize::Small)),
 8251                )
 8252            });
 8253
 8254        Some(result)
 8255    }
 8256
 8257    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8258        let accent_color = cx.theme().colors().text_accent;
 8259        let editor_bg_color = cx.theme().colors().editor_background;
 8260        editor_bg_color.blend(accent_color.opacity(0.1))
 8261    }
 8262
 8263    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8264        let accent_color = cx.theme().colors().text_accent;
 8265        let editor_bg_color = cx.theme().colors().editor_background;
 8266        editor_bg_color.blend(accent_color.opacity(0.6))
 8267    }
 8268
 8269    fn render_edit_prediction_cursor_popover(
 8270        &self,
 8271        min_width: Pixels,
 8272        max_width: Pixels,
 8273        cursor_point: Point,
 8274        style: &EditorStyle,
 8275        accept_keystroke: Option<&gpui::Keystroke>,
 8276        _window: &Window,
 8277        cx: &mut Context<Editor>,
 8278    ) -> Option<AnyElement> {
 8279        let provider = self.edit_prediction_provider.as_ref()?;
 8280
 8281        if provider.provider.needs_terms_acceptance(cx) {
 8282            return Some(
 8283                h_flex()
 8284                    .min_w(min_width)
 8285                    .flex_1()
 8286                    .px_2()
 8287                    .py_1()
 8288                    .gap_3()
 8289                    .elevation_2(cx)
 8290                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8291                    .id("accept-terms")
 8292                    .cursor_pointer()
 8293                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8294                    .on_click(cx.listener(|this, _event, window, cx| {
 8295                        cx.stop_propagation();
 8296                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8297                        window.dispatch_action(
 8298                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8299                            cx,
 8300                        );
 8301                    }))
 8302                    .child(
 8303                        h_flex()
 8304                            .flex_1()
 8305                            .gap_2()
 8306                            .child(Icon::new(IconName::ZedPredict))
 8307                            .child(Label::new("Accept Terms of Service"))
 8308                            .child(div().w_full())
 8309                            .child(
 8310                                Icon::new(IconName::ArrowUpRight)
 8311                                    .color(Color::Muted)
 8312                                    .size(IconSize::Small),
 8313                            )
 8314                            .into_any_element(),
 8315                    )
 8316                    .into_any(),
 8317            );
 8318        }
 8319
 8320        let is_refreshing = provider.provider.is_refreshing(cx);
 8321
 8322        fn pending_completion_container() -> Div {
 8323            h_flex()
 8324                .h_full()
 8325                .flex_1()
 8326                .gap_2()
 8327                .child(Icon::new(IconName::ZedPredict))
 8328        }
 8329
 8330        let completion = match &self.active_inline_completion {
 8331            Some(prediction) => {
 8332                if !self.has_visible_completions_menu() {
 8333                    const RADIUS: Pixels = px(6.);
 8334                    const BORDER_WIDTH: Pixels = px(1.);
 8335
 8336                    return Some(
 8337                        h_flex()
 8338                            .elevation_2(cx)
 8339                            .border(BORDER_WIDTH)
 8340                            .border_color(cx.theme().colors().border)
 8341                            .when(accept_keystroke.is_none(), |el| {
 8342                                el.border_color(cx.theme().status().error)
 8343                            })
 8344                            .rounded(RADIUS)
 8345                            .rounded_tl(px(0.))
 8346                            .overflow_hidden()
 8347                            .child(div().px_1p5().child(match &prediction.completion {
 8348                                InlineCompletion::Move { target, snapshot } => {
 8349                                    use text::ToPoint as _;
 8350                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8351                                    {
 8352                                        Icon::new(IconName::ZedPredictDown)
 8353                                    } else {
 8354                                        Icon::new(IconName::ZedPredictUp)
 8355                                    }
 8356                                }
 8357                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8358                            }))
 8359                            .child(
 8360                                h_flex()
 8361                                    .gap_1()
 8362                                    .py_1()
 8363                                    .px_2()
 8364                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8365                                    .border_l_1()
 8366                                    .border_color(cx.theme().colors().border)
 8367                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8368                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8369                                        el.child(
 8370                                            Label::new("Hold")
 8371                                                .size(LabelSize::Small)
 8372                                                .when(accept_keystroke.is_none(), |el| {
 8373                                                    el.strikethrough()
 8374                                                })
 8375                                                .line_height_style(LineHeightStyle::UiLabel),
 8376                                        )
 8377                                    })
 8378                                    .id("edit_prediction_cursor_popover_keybind")
 8379                                    .when(accept_keystroke.is_none(), |el| {
 8380                                        let status_colors = cx.theme().status();
 8381
 8382                                        el.bg(status_colors.error_background)
 8383                                            .border_color(status_colors.error.opacity(0.6))
 8384                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8385                                            .cursor_default()
 8386                                            .hoverable_tooltip(move |_window, cx| {
 8387                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8388                                                    .into()
 8389                                            })
 8390                                    })
 8391                                    .when_some(
 8392                                        accept_keystroke.as_ref(),
 8393                                        |el, accept_keystroke| {
 8394                                            el.child(h_flex().children(ui::render_modifiers(
 8395                                                &accept_keystroke.modifiers,
 8396                                                PlatformStyle::platform(),
 8397                                                Some(Color::Default),
 8398                                                Some(IconSize::XSmall.rems().into()),
 8399                                                false,
 8400                                            )))
 8401                                        },
 8402                                    ),
 8403                            )
 8404                            .into_any(),
 8405                    );
 8406                }
 8407
 8408                self.render_edit_prediction_cursor_popover_preview(
 8409                    prediction,
 8410                    cursor_point,
 8411                    style,
 8412                    cx,
 8413                )?
 8414            }
 8415
 8416            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8417                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8418                    stale_completion,
 8419                    cursor_point,
 8420                    style,
 8421                    cx,
 8422                )?,
 8423
 8424                None => {
 8425                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8426                }
 8427            },
 8428
 8429            None => pending_completion_container().child(Label::new("No Prediction")),
 8430        };
 8431
 8432        let completion = if is_refreshing {
 8433            completion
 8434                .with_animation(
 8435                    "loading-completion",
 8436                    Animation::new(Duration::from_secs(2))
 8437                        .repeat()
 8438                        .with_easing(pulsating_between(0.4, 0.8)),
 8439                    |label, delta| label.opacity(delta),
 8440                )
 8441                .into_any_element()
 8442        } else {
 8443            completion.into_any_element()
 8444        };
 8445
 8446        let has_completion = self.active_inline_completion.is_some();
 8447
 8448        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8449        Some(
 8450            h_flex()
 8451                .min_w(min_width)
 8452                .max_w(max_width)
 8453                .flex_1()
 8454                .elevation_2(cx)
 8455                .border_color(cx.theme().colors().border)
 8456                .child(
 8457                    div()
 8458                        .flex_1()
 8459                        .py_1()
 8460                        .px_2()
 8461                        .overflow_hidden()
 8462                        .child(completion),
 8463                )
 8464                .when_some(accept_keystroke, |el, accept_keystroke| {
 8465                    if !accept_keystroke.modifiers.modified() {
 8466                        return el;
 8467                    }
 8468
 8469                    el.child(
 8470                        h_flex()
 8471                            .h_full()
 8472                            .border_l_1()
 8473                            .rounded_r_lg()
 8474                            .border_color(cx.theme().colors().border)
 8475                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8476                            .gap_1()
 8477                            .py_1()
 8478                            .px_2()
 8479                            .child(
 8480                                h_flex()
 8481                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8482                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8483                                    .child(h_flex().children(ui::render_modifiers(
 8484                                        &accept_keystroke.modifiers,
 8485                                        PlatformStyle::platform(),
 8486                                        Some(if !has_completion {
 8487                                            Color::Muted
 8488                                        } else {
 8489                                            Color::Default
 8490                                        }),
 8491                                        None,
 8492                                        false,
 8493                                    ))),
 8494                            )
 8495                            .child(Label::new("Preview").into_any_element())
 8496                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8497                    )
 8498                })
 8499                .into_any(),
 8500        )
 8501    }
 8502
 8503    fn render_edit_prediction_cursor_popover_preview(
 8504        &self,
 8505        completion: &InlineCompletionState,
 8506        cursor_point: Point,
 8507        style: &EditorStyle,
 8508        cx: &mut Context<Editor>,
 8509    ) -> Option<Div> {
 8510        use text::ToPoint as _;
 8511
 8512        fn render_relative_row_jump(
 8513            prefix: impl Into<String>,
 8514            current_row: u32,
 8515            target_row: u32,
 8516        ) -> Div {
 8517            let (row_diff, arrow) = if target_row < current_row {
 8518                (current_row - target_row, IconName::ArrowUp)
 8519            } else {
 8520                (target_row - current_row, IconName::ArrowDown)
 8521            };
 8522
 8523            h_flex()
 8524                .child(
 8525                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8526                        .color(Color::Muted)
 8527                        .size(LabelSize::Small),
 8528                )
 8529                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8530        }
 8531
 8532        match &completion.completion {
 8533            InlineCompletion::Move {
 8534                target, snapshot, ..
 8535            } => Some(
 8536                h_flex()
 8537                    .px_2()
 8538                    .gap_2()
 8539                    .flex_1()
 8540                    .child(
 8541                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8542                            Icon::new(IconName::ZedPredictDown)
 8543                        } else {
 8544                            Icon::new(IconName::ZedPredictUp)
 8545                        },
 8546                    )
 8547                    .child(Label::new("Jump to Edit")),
 8548            ),
 8549
 8550            InlineCompletion::Edit {
 8551                edits,
 8552                edit_preview,
 8553                snapshot,
 8554                display_mode: _,
 8555            } => {
 8556                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8557
 8558                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8559                    &snapshot,
 8560                    &edits,
 8561                    edit_preview.as_ref()?,
 8562                    true,
 8563                    cx,
 8564                )
 8565                .first_line_preview();
 8566
 8567                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8568                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8569
 8570                let preview = h_flex()
 8571                    .gap_1()
 8572                    .min_w_16()
 8573                    .child(styled_text)
 8574                    .when(has_more_lines, |parent| parent.child(""));
 8575
 8576                let left = if first_edit_row != cursor_point.row {
 8577                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8578                        .into_any_element()
 8579                } else {
 8580                    Icon::new(IconName::ZedPredict).into_any_element()
 8581                };
 8582
 8583                Some(
 8584                    h_flex()
 8585                        .h_full()
 8586                        .flex_1()
 8587                        .gap_2()
 8588                        .pr_1()
 8589                        .overflow_x_hidden()
 8590                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8591                        .child(left)
 8592                        .child(preview),
 8593                )
 8594            }
 8595        }
 8596    }
 8597
 8598    pub fn render_context_menu(
 8599        &self,
 8600        style: &EditorStyle,
 8601        max_height_in_lines: u32,
 8602        window: &mut Window,
 8603        cx: &mut Context<Editor>,
 8604    ) -> Option<AnyElement> {
 8605        let menu = self.context_menu.borrow();
 8606        let menu = menu.as_ref()?;
 8607        if !menu.visible() {
 8608            return None;
 8609        };
 8610        Some(menu.render(style, max_height_in_lines, window, cx))
 8611    }
 8612
 8613    fn render_context_menu_aside(
 8614        &mut self,
 8615        max_size: Size<Pixels>,
 8616        window: &mut Window,
 8617        cx: &mut Context<Editor>,
 8618    ) -> Option<AnyElement> {
 8619        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8620            if menu.visible() {
 8621                menu.render_aside(self, max_size, window, cx)
 8622            } else {
 8623                None
 8624            }
 8625        })
 8626    }
 8627
 8628    fn hide_context_menu(
 8629        &mut self,
 8630        window: &mut Window,
 8631        cx: &mut Context<Self>,
 8632    ) -> Option<CodeContextMenu> {
 8633        cx.notify();
 8634        self.completion_tasks.clear();
 8635        let context_menu = self.context_menu.borrow_mut().take();
 8636        self.stale_inline_completion_in_menu.take();
 8637        self.update_visible_inline_completion(window, cx);
 8638        context_menu
 8639    }
 8640
 8641    fn show_snippet_choices(
 8642        &mut self,
 8643        choices: &Vec<String>,
 8644        selection: Range<Anchor>,
 8645        cx: &mut Context<Self>,
 8646    ) {
 8647        if selection.start.buffer_id.is_none() {
 8648            return;
 8649        }
 8650        let buffer_id = selection.start.buffer_id.unwrap();
 8651        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8652        let id = post_inc(&mut self.next_completion_id);
 8653        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8654
 8655        if let Some(buffer) = buffer {
 8656            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8657                CompletionsMenu::new_snippet_choices(
 8658                    id,
 8659                    true,
 8660                    choices,
 8661                    selection,
 8662                    buffer,
 8663                    snippet_sort_order,
 8664                ),
 8665            ));
 8666        }
 8667    }
 8668
 8669    pub fn insert_snippet(
 8670        &mut self,
 8671        insertion_ranges: &[Range<usize>],
 8672        snippet: Snippet,
 8673        window: &mut Window,
 8674        cx: &mut Context<Self>,
 8675    ) -> Result<()> {
 8676        struct Tabstop<T> {
 8677            is_end_tabstop: bool,
 8678            ranges: Vec<Range<T>>,
 8679            choices: Option<Vec<String>>,
 8680        }
 8681
 8682        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8683            let snippet_text: Arc<str> = snippet.text.clone().into();
 8684            let edits = insertion_ranges
 8685                .iter()
 8686                .cloned()
 8687                .map(|range| (range, snippet_text.clone()));
 8688            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8689
 8690            let snapshot = &*buffer.read(cx);
 8691            let snippet = &snippet;
 8692            snippet
 8693                .tabstops
 8694                .iter()
 8695                .map(|tabstop| {
 8696                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8697                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8698                    });
 8699                    let mut tabstop_ranges = tabstop
 8700                        .ranges
 8701                        .iter()
 8702                        .flat_map(|tabstop_range| {
 8703                            let mut delta = 0_isize;
 8704                            insertion_ranges.iter().map(move |insertion_range| {
 8705                                let insertion_start = insertion_range.start as isize + delta;
 8706                                delta +=
 8707                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8708
 8709                                let start = ((insertion_start + tabstop_range.start) as usize)
 8710                                    .min(snapshot.len());
 8711                                let end = ((insertion_start + tabstop_range.end) as usize)
 8712                                    .min(snapshot.len());
 8713                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8714                            })
 8715                        })
 8716                        .collect::<Vec<_>>();
 8717                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8718
 8719                    Tabstop {
 8720                        is_end_tabstop,
 8721                        ranges: tabstop_ranges,
 8722                        choices: tabstop.choices.clone(),
 8723                    }
 8724                })
 8725                .collect::<Vec<_>>()
 8726        });
 8727        if let Some(tabstop) = tabstops.first() {
 8728            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8729                s.select_ranges(tabstop.ranges.iter().cloned());
 8730            });
 8731
 8732            if let Some(choices) = &tabstop.choices {
 8733                if let Some(selection) = tabstop.ranges.first() {
 8734                    self.show_snippet_choices(choices, selection.clone(), cx)
 8735                }
 8736            }
 8737
 8738            // If we're already at the last tabstop and it's at the end of the snippet,
 8739            // we're done, we don't need to keep the state around.
 8740            if !tabstop.is_end_tabstop {
 8741                let choices = tabstops
 8742                    .iter()
 8743                    .map(|tabstop| tabstop.choices.clone())
 8744                    .collect();
 8745
 8746                let ranges = tabstops
 8747                    .into_iter()
 8748                    .map(|tabstop| tabstop.ranges)
 8749                    .collect::<Vec<_>>();
 8750
 8751                self.snippet_stack.push(SnippetState {
 8752                    active_index: 0,
 8753                    ranges,
 8754                    choices,
 8755                });
 8756            }
 8757
 8758            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8759            if self.autoclose_regions.is_empty() {
 8760                let snapshot = self.buffer.read(cx).snapshot(cx);
 8761                for selection in &mut self.selections.all::<Point>(cx) {
 8762                    let selection_head = selection.head();
 8763                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8764                        continue;
 8765                    };
 8766
 8767                    let mut bracket_pair = None;
 8768                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8769                    let prev_chars = snapshot
 8770                        .reversed_chars_at(selection_head)
 8771                        .collect::<String>();
 8772                    for (pair, enabled) in scope.brackets() {
 8773                        if enabled
 8774                            && pair.close
 8775                            && prev_chars.starts_with(pair.start.as_str())
 8776                            && next_chars.starts_with(pair.end.as_str())
 8777                        {
 8778                            bracket_pair = Some(pair.clone());
 8779                            break;
 8780                        }
 8781                    }
 8782                    if let Some(pair) = bracket_pair {
 8783                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8784                        let autoclose_enabled =
 8785                            self.use_autoclose && snapshot_settings.use_autoclose;
 8786                        if autoclose_enabled {
 8787                            let start = snapshot.anchor_after(selection_head);
 8788                            let end = snapshot.anchor_after(selection_head);
 8789                            self.autoclose_regions.push(AutocloseRegion {
 8790                                selection_id: selection.id,
 8791                                range: start..end,
 8792                                pair,
 8793                            });
 8794                        }
 8795                    }
 8796                }
 8797            }
 8798        }
 8799        Ok(())
 8800    }
 8801
 8802    pub fn move_to_next_snippet_tabstop(
 8803        &mut self,
 8804        window: &mut Window,
 8805        cx: &mut Context<Self>,
 8806    ) -> bool {
 8807        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8808    }
 8809
 8810    pub fn move_to_prev_snippet_tabstop(
 8811        &mut self,
 8812        window: &mut Window,
 8813        cx: &mut Context<Self>,
 8814    ) -> bool {
 8815        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8816    }
 8817
 8818    pub fn move_to_snippet_tabstop(
 8819        &mut self,
 8820        bias: Bias,
 8821        window: &mut Window,
 8822        cx: &mut Context<Self>,
 8823    ) -> bool {
 8824        if let Some(mut snippet) = self.snippet_stack.pop() {
 8825            match bias {
 8826                Bias::Left => {
 8827                    if snippet.active_index > 0 {
 8828                        snippet.active_index -= 1;
 8829                    } else {
 8830                        self.snippet_stack.push(snippet);
 8831                        return false;
 8832                    }
 8833                }
 8834                Bias::Right => {
 8835                    if snippet.active_index + 1 < snippet.ranges.len() {
 8836                        snippet.active_index += 1;
 8837                    } else {
 8838                        self.snippet_stack.push(snippet);
 8839                        return false;
 8840                    }
 8841                }
 8842            }
 8843            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8844                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8845                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8846                });
 8847
 8848                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8849                    if let Some(selection) = current_ranges.first() {
 8850                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8851                    }
 8852                }
 8853
 8854                // If snippet state is not at the last tabstop, push it back on the stack
 8855                if snippet.active_index + 1 < snippet.ranges.len() {
 8856                    self.snippet_stack.push(snippet);
 8857                }
 8858                return true;
 8859            }
 8860        }
 8861
 8862        false
 8863    }
 8864
 8865    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8866        self.transact(window, cx, |this, window, cx| {
 8867            this.select_all(&SelectAll, window, cx);
 8868            this.insert("", window, cx);
 8869        });
 8870    }
 8871
 8872    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8873        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8874        self.transact(window, cx, |this, window, cx| {
 8875            this.select_autoclose_pair(window, cx);
 8876            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8877            if !this.linked_edit_ranges.is_empty() {
 8878                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8879                let snapshot = this.buffer.read(cx).snapshot(cx);
 8880
 8881                for selection in selections.iter() {
 8882                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8883                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8884                    if selection_start.buffer_id != selection_end.buffer_id {
 8885                        continue;
 8886                    }
 8887                    if let Some(ranges) =
 8888                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8889                    {
 8890                        for (buffer, entries) in ranges {
 8891                            linked_ranges.entry(buffer).or_default().extend(entries);
 8892                        }
 8893                    }
 8894                }
 8895            }
 8896
 8897            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8898            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8899            for selection in &mut selections {
 8900                if selection.is_empty() {
 8901                    let old_head = selection.head();
 8902                    let mut new_head =
 8903                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8904                            .to_point(&display_map);
 8905                    if let Some((buffer, line_buffer_range)) = display_map
 8906                        .buffer_snapshot
 8907                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8908                    {
 8909                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8910                        let indent_len = match indent_size.kind {
 8911                            IndentKind::Space => {
 8912                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8913                            }
 8914                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8915                        };
 8916                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8917                            let indent_len = indent_len.get();
 8918                            new_head = cmp::min(
 8919                                new_head,
 8920                                MultiBufferPoint::new(
 8921                                    old_head.row,
 8922                                    ((old_head.column - 1) / indent_len) * indent_len,
 8923                                ),
 8924                            );
 8925                        }
 8926                    }
 8927
 8928                    selection.set_head(new_head, SelectionGoal::None);
 8929                }
 8930            }
 8931
 8932            this.signature_help_state.set_backspace_pressed(true);
 8933            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8934                s.select(selections)
 8935            });
 8936            this.insert("", window, cx);
 8937            let empty_str: Arc<str> = Arc::from("");
 8938            for (buffer, edits) in linked_ranges {
 8939                let snapshot = buffer.read(cx).snapshot();
 8940                use text::ToPoint as TP;
 8941
 8942                let edits = edits
 8943                    .into_iter()
 8944                    .map(|range| {
 8945                        let end_point = TP::to_point(&range.end, &snapshot);
 8946                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8947
 8948                        if end_point == start_point {
 8949                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8950                                .saturating_sub(1);
 8951                            start_point =
 8952                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8953                        };
 8954
 8955                        (start_point..end_point, empty_str.clone())
 8956                    })
 8957                    .sorted_by_key(|(range, _)| range.start)
 8958                    .collect::<Vec<_>>();
 8959                buffer.update(cx, |this, cx| {
 8960                    this.edit(edits, None, cx);
 8961                })
 8962            }
 8963            this.refresh_inline_completion(true, false, window, cx);
 8964            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8965        });
 8966    }
 8967
 8968    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8969        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8970        self.transact(window, cx, |this, window, cx| {
 8971            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8972                s.move_with(|map, selection| {
 8973                    if selection.is_empty() {
 8974                        let cursor = movement::right(map, selection.head());
 8975                        selection.end = cursor;
 8976                        selection.reversed = true;
 8977                        selection.goal = SelectionGoal::None;
 8978                    }
 8979                })
 8980            });
 8981            this.insert("", window, cx);
 8982            this.refresh_inline_completion(true, false, window, cx);
 8983        });
 8984    }
 8985
 8986    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8987        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8988        if self.move_to_prev_snippet_tabstop(window, cx) {
 8989            return;
 8990        }
 8991        self.outdent(&Outdent, window, cx);
 8992    }
 8993
 8994    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8995        if self.move_to_next_snippet_tabstop(window, cx) {
 8996            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8997            return;
 8998        }
 8999        if self.read_only(cx) {
 9000            return;
 9001        }
 9002        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9003        let mut selections = self.selections.all_adjusted(cx);
 9004        let buffer = self.buffer.read(cx);
 9005        let snapshot = buffer.snapshot(cx);
 9006        let rows_iter = selections.iter().map(|s| s.head().row);
 9007        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9008
 9009        let has_some_cursor_in_whitespace = selections
 9010            .iter()
 9011            .filter(|selection| selection.is_empty())
 9012            .any(|selection| {
 9013                let cursor = selection.head();
 9014                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9015                cursor.column < current_indent.len
 9016            });
 9017
 9018        let mut edits = Vec::new();
 9019        let mut prev_edited_row = 0;
 9020        let mut row_delta = 0;
 9021        for selection in &mut selections {
 9022            if selection.start.row != prev_edited_row {
 9023                row_delta = 0;
 9024            }
 9025            prev_edited_row = selection.end.row;
 9026
 9027            // If the selection is non-empty, then increase the indentation of the selected lines.
 9028            if !selection.is_empty() {
 9029                row_delta =
 9030                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9031                continue;
 9032            }
 9033
 9034            let cursor = selection.head();
 9035            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9036            if let Some(suggested_indent) =
 9037                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9038            {
 9039                // Don't do anything if already at suggested indent
 9040                // and there is any other cursor which is not
 9041                if has_some_cursor_in_whitespace
 9042                    && cursor.column == current_indent.len
 9043                    && current_indent.len == suggested_indent.len
 9044                {
 9045                    continue;
 9046                }
 9047
 9048                // Adjust line and move cursor to suggested indent
 9049                // if cursor is not at suggested indent
 9050                if cursor.column < suggested_indent.len
 9051                    && cursor.column <= current_indent.len
 9052                    && current_indent.len <= suggested_indent.len
 9053                {
 9054                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9055                    selection.end = selection.start;
 9056                    if row_delta == 0 {
 9057                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9058                            cursor.row,
 9059                            current_indent,
 9060                            suggested_indent,
 9061                        ));
 9062                        row_delta = suggested_indent.len - current_indent.len;
 9063                    }
 9064                    continue;
 9065                }
 9066
 9067                // If current indent is more than suggested indent
 9068                // only move cursor to current indent and skip indent
 9069                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9070                    selection.start = Point::new(cursor.row, current_indent.len);
 9071                    selection.end = selection.start;
 9072                    continue;
 9073                }
 9074            }
 9075
 9076            // Otherwise, insert a hard or soft tab.
 9077            let settings = buffer.language_settings_at(cursor, cx);
 9078            let tab_size = if settings.hard_tabs {
 9079                IndentSize::tab()
 9080            } else {
 9081                let tab_size = settings.tab_size.get();
 9082                let indent_remainder = snapshot
 9083                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9084                    .flat_map(str::chars)
 9085                    .fold(row_delta % tab_size, |counter: u32, c| {
 9086                        if c == '\t' {
 9087                            0
 9088                        } else {
 9089                            (counter + 1) % tab_size
 9090                        }
 9091                    });
 9092
 9093                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9094                IndentSize::spaces(chars_to_next_tab_stop)
 9095            };
 9096            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9097            selection.end = selection.start;
 9098            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9099            row_delta += tab_size.len;
 9100        }
 9101
 9102        self.transact(window, cx, |this, window, cx| {
 9103            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9104            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9105                s.select(selections)
 9106            });
 9107            this.refresh_inline_completion(true, false, window, cx);
 9108        });
 9109    }
 9110
 9111    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9112        if self.read_only(cx) {
 9113            return;
 9114        }
 9115        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9116        let mut selections = self.selections.all::<Point>(cx);
 9117        let mut prev_edited_row = 0;
 9118        let mut row_delta = 0;
 9119        let mut edits = Vec::new();
 9120        let buffer = self.buffer.read(cx);
 9121        let snapshot = buffer.snapshot(cx);
 9122        for selection in &mut selections {
 9123            if selection.start.row != prev_edited_row {
 9124                row_delta = 0;
 9125            }
 9126            prev_edited_row = selection.end.row;
 9127
 9128            row_delta =
 9129                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9130        }
 9131
 9132        self.transact(window, cx, |this, window, cx| {
 9133            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9134            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9135                s.select(selections)
 9136            });
 9137        });
 9138    }
 9139
 9140    fn indent_selection(
 9141        buffer: &MultiBuffer,
 9142        snapshot: &MultiBufferSnapshot,
 9143        selection: &mut Selection<Point>,
 9144        edits: &mut Vec<(Range<Point>, String)>,
 9145        delta_for_start_row: u32,
 9146        cx: &App,
 9147    ) -> u32 {
 9148        let settings = buffer.language_settings_at(selection.start, cx);
 9149        let tab_size = settings.tab_size.get();
 9150        let indent_kind = if settings.hard_tabs {
 9151            IndentKind::Tab
 9152        } else {
 9153            IndentKind::Space
 9154        };
 9155        let mut start_row = selection.start.row;
 9156        let mut end_row = selection.end.row + 1;
 9157
 9158        // If a selection ends at the beginning of a line, don't indent
 9159        // that last line.
 9160        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9161            end_row -= 1;
 9162        }
 9163
 9164        // Avoid re-indenting a row that has already been indented by a
 9165        // previous selection, but still update this selection's column
 9166        // to reflect that indentation.
 9167        if delta_for_start_row > 0 {
 9168            start_row += 1;
 9169            selection.start.column += delta_for_start_row;
 9170            if selection.end.row == selection.start.row {
 9171                selection.end.column += delta_for_start_row;
 9172            }
 9173        }
 9174
 9175        let mut delta_for_end_row = 0;
 9176        let has_multiple_rows = start_row + 1 != end_row;
 9177        for row in start_row..end_row {
 9178            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9179            let indent_delta = match (current_indent.kind, indent_kind) {
 9180                (IndentKind::Space, IndentKind::Space) => {
 9181                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9182                    IndentSize::spaces(columns_to_next_tab_stop)
 9183                }
 9184                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9185                (_, IndentKind::Tab) => IndentSize::tab(),
 9186            };
 9187
 9188            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9189                0
 9190            } else {
 9191                selection.start.column
 9192            };
 9193            let row_start = Point::new(row, start);
 9194            edits.push((
 9195                row_start..row_start,
 9196                indent_delta.chars().collect::<String>(),
 9197            ));
 9198
 9199            // Update this selection's endpoints to reflect the indentation.
 9200            if row == selection.start.row {
 9201                selection.start.column += indent_delta.len;
 9202            }
 9203            if row == selection.end.row {
 9204                selection.end.column += indent_delta.len;
 9205                delta_for_end_row = indent_delta.len;
 9206            }
 9207        }
 9208
 9209        if selection.start.row == selection.end.row {
 9210            delta_for_start_row + delta_for_end_row
 9211        } else {
 9212            delta_for_end_row
 9213        }
 9214    }
 9215
 9216    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9217        if self.read_only(cx) {
 9218            return;
 9219        }
 9220        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9221        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9222        let selections = self.selections.all::<Point>(cx);
 9223        let mut deletion_ranges = Vec::new();
 9224        let mut last_outdent = None;
 9225        {
 9226            let buffer = self.buffer.read(cx);
 9227            let snapshot = buffer.snapshot(cx);
 9228            for selection in &selections {
 9229                let settings = buffer.language_settings_at(selection.start, cx);
 9230                let tab_size = settings.tab_size.get();
 9231                let mut rows = selection.spanned_rows(false, &display_map);
 9232
 9233                // Avoid re-outdenting a row that has already been outdented by a
 9234                // previous selection.
 9235                if let Some(last_row) = last_outdent {
 9236                    if last_row == rows.start {
 9237                        rows.start = rows.start.next_row();
 9238                    }
 9239                }
 9240                let has_multiple_rows = rows.len() > 1;
 9241                for row in rows.iter_rows() {
 9242                    let indent_size = snapshot.indent_size_for_line(row);
 9243                    if indent_size.len > 0 {
 9244                        let deletion_len = match indent_size.kind {
 9245                            IndentKind::Space => {
 9246                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9247                                if columns_to_prev_tab_stop == 0 {
 9248                                    tab_size
 9249                                } else {
 9250                                    columns_to_prev_tab_stop
 9251                                }
 9252                            }
 9253                            IndentKind::Tab => 1,
 9254                        };
 9255                        let start = if has_multiple_rows
 9256                            || deletion_len > selection.start.column
 9257                            || indent_size.len < selection.start.column
 9258                        {
 9259                            0
 9260                        } else {
 9261                            selection.start.column - deletion_len
 9262                        };
 9263                        deletion_ranges.push(
 9264                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9265                        );
 9266                        last_outdent = Some(row);
 9267                    }
 9268                }
 9269            }
 9270        }
 9271
 9272        self.transact(window, cx, |this, window, cx| {
 9273            this.buffer.update(cx, |buffer, cx| {
 9274                let empty_str: Arc<str> = Arc::default();
 9275                buffer.edit(
 9276                    deletion_ranges
 9277                        .into_iter()
 9278                        .map(|range| (range, empty_str.clone())),
 9279                    None,
 9280                    cx,
 9281                );
 9282            });
 9283            let selections = this.selections.all::<usize>(cx);
 9284            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9285                s.select(selections)
 9286            });
 9287        });
 9288    }
 9289
 9290    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9291        if self.read_only(cx) {
 9292            return;
 9293        }
 9294        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9295        let selections = self
 9296            .selections
 9297            .all::<usize>(cx)
 9298            .into_iter()
 9299            .map(|s| s.range());
 9300
 9301        self.transact(window, cx, |this, window, cx| {
 9302            this.buffer.update(cx, |buffer, cx| {
 9303                buffer.autoindent_ranges(selections, cx);
 9304            });
 9305            let selections = this.selections.all::<usize>(cx);
 9306            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9307                s.select(selections)
 9308            });
 9309        });
 9310    }
 9311
 9312    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9313        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9314        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9315        let selections = self.selections.all::<Point>(cx);
 9316
 9317        let mut new_cursors = Vec::new();
 9318        let mut edit_ranges = Vec::new();
 9319        let mut selections = selections.iter().peekable();
 9320        while let Some(selection) = selections.next() {
 9321            let mut rows = selection.spanned_rows(false, &display_map);
 9322            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9323
 9324            // Accumulate contiguous regions of rows that we want to delete.
 9325            while let Some(next_selection) = selections.peek() {
 9326                let next_rows = next_selection.spanned_rows(false, &display_map);
 9327                if next_rows.start <= rows.end {
 9328                    rows.end = next_rows.end;
 9329                    selections.next().unwrap();
 9330                } else {
 9331                    break;
 9332                }
 9333            }
 9334
 9335            let buffer = &display_map.buffer_snapshot;
 9336            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9337            let edit_end;
 9338            let cursor_buffer_row;
 9339            if buffer.max_point().row >= rows.end.0 {
 9340                // If there's a line after the range, delete the \n from the end of the row range
 9341                // and position the cursor on the next line.
 9342                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9343                cursor_buffer_row = rows.end;
 9344            } else {
 9345                // If there isn't a line after the range, delete the \n from the line before the
 9346                // start of the row range and position the cursor there.
 9347                edit_start = edit_start.saturating_sub(1);
 9348                edit_end = buffer.len();
 9349                cursor_buffer_row = rows.start.previous_row();
 9350            }
 9351
 9352            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9353            *cursor.column_mut() =
 9354                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9355
 9356            new_cursors.push((
 9357                selection.id,
 9358                buffer.anchor_after(cursor.to_point(&display_map)),
 9359            ));
 9360            edit_ranges.push(edit_start..edit_end);
 9361        }
 9362
 9363        self.transact(window, cx, |this, window, cx| {
 9364            let buffer = this.buffer.update(cx, |buffer, cx| {
 9365                let empty_str: Arc<str> = Arc::default();
 9366                buffer.edit(
 9367                    edit_ranges
 9368                        .into_iter()
 9369                        .map(|range| (range, empty_str.clone())),
 9370                    None,
 9371                    cx,
 9372                );
 9373                buffer.snapshot(cx)
 9374            });
 9375            let new_selections = new_cursors
 9376                .into_iter()
 9377                .map(|(id, cursor)| {
 9378                    let cursor = cursor.to_point(&buffer);
 9379                    Selection {
 9380                        id,
 9381                        start: cursor,
 9382                        end: cursor,
 9383                        reversed: false,
 9384                        goal: SelectionGoal::None,
 9385                    }
 9386                })
 9387                .collect();
 9388
 9389            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9390                s.select(new_selections);
 9391            });
 9392        });
 9393    }
 9394
 9395    pub fn join_lines_impl(
 9396        &mut self,
 9397        insert_whitespace: bool,
 9398        window: &mut Window,
 9399        cx: &mut Context<Self>,
 9400    ) {
 9401        if self.read_only(cx) {
 9402            return;
 9403        }
 9404        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9405        for selection in self.selections.all::<Point>(cx) {
 9406            let start = MultiBufferRow(selection.start.row);
 9407            // Treat single line selections as if they include the next line. Otherwise this action
 9408            // would do nothing for single line selections individual cursors.
 9409            let end = if selection.start.row == selection.end.row {
 9410                MultiBufferRow(selection.start.row + 1)
 9411            } else {
 9412                MultiBufferRow(selection.end.row)
 9413            };
 9414
 9415            if let Some(last_row_range) = row_ranges.last_mut() {
 9416                if start <= last_row_range.end {
 9417                    last_row_range.end = end;
 9418                    continue;
 9419                }
 9420            }
 9421            row_ranges.push(start..end);
 9422        }
 9423
 9424        let snapshot = self.buffer.read(cx).snapshot(cx);
 9425        let mut cursor_positions = Vec::new();
 9426        for row_range in &row_ranges {
 9427            let anchor = snapshot.anchor_before(Point::new(
 9428                row_range.end.previous_row().0,
 9429                snapshot.line_len(row_range.end.previous_row()),
 9430            ));
 9431            cursor_positions.push(anchor..anchor);
 9432        }
 9433
 9434        self.transact(window, cx, |this, window, cx| {
 9435            for row_range in row_ranges.into_iter().rev() {
 9436                for row in row_range.iter_rows().rev() {
 9437                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9438                    let next_line_row = row.next_row();
 9439                    let indent = snapshot.indent_size_for_line(next_line_row);
 9440                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9441
 9442                    let replace =
 9443                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9444                            " "
 9445                        } else {
 9446                            ""
 9447                        };
 9448
 9449                    this.buffer.update(cx, |buffer, cx| {
 9450                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9451                    });
 9452                }
 9453            }
 9454
 9455            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9456                s.select_anchor_ranges(cursor_positions)
 9457            });
 9458        });
 9459    }
 9460
 9461    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9462        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9463        self.join_lines_impl(true, window, cx);
 9464    }
 9465
 9466    pub fn sort_lines_case_sensitive(
 9467        &mut self,
 9468        _: &SortLinesCaseSensitive,
 9469        window: &mut Window,
 9470        cx: &mut Context<Self>,
 9471    ) {
 9472        self.manipulate_lines(window, cx, |lines| lines.sort())
 9473    }
 9474
 9475    pub fn sort_lines_case_insensitive(
 9476        &mut self,
 9477        _: &SortLinesCaseInsensitive,
 9478        window: &mut Window,
 9479        cx: &mut Context<Self>,
 9480    ) {
 9481        self.manipulate_lines(window, cx, |lines| {
 9482            lines.sort_by_key(|line| line.to_lowercase())
 9483        })
 9484    }
 9485
 9486    pub fn unique_lines_case_insensitive(
 9487        &mut self,
 9488        _: &UniqueLinesCaseInsensitive,
 9489        window: &mut Window,
 9490        cx: &mut Context<Self>,
 9491    ) {
 9492        self.manipulate_lines(window, cx, |lines| {
 9493            let mut seen = HashSet::default();
 9494            lines.retain(|line| seen.insert(line.to_lowercase()));
 9495        })
 9496    }
 9497
 9498    pub fn unique_lines_case_sensitive(
 9499        &mut self,
 9500        _: &UniqueLinesCaseSensitive,
 9501        window: &mut Window,
 9502        cx: &mut Context<Self>,
 9503    ) {
 9504        self.manipulate_lines(window, cx, |lines| {
 9505            let mut seen = HashSet::default();
 9506            lines.retain(|line| seen.insert(*line));
 9507        })
 9508    }
 9509
 9510    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9511        let Some(project) = self.project.clone() else {
 9512            return;
 9513        };
 9514        self.reload(project, window, cx)
 9515            .detach_and_notify_err(window, cx);
 9516    }
 9517
 9518    pub fn restore_file(
 9519        &mut self,
 9520        _: &::git::RestoreFile,
 9521        window: &mut Window,
 9522        cx: &mut Context<Self>,
 9523    ) {
 9524        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9525        let mut buffer_ids = HashSet::default();
 9526        let snapshot = self.buffer().read(cx).snapshot(cx);
 9527        for selection in self.selections.all::<usize>(cx) {
 9528            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9529        }
 9530
 9531        let buffer = self.buffer().read(cx);
 9532        let ranges = buffer_ids
 9533            .into_iter()
 9534            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9535            .collect::<Vec<_>>();
 9536
 9537        self.restore_hunks_in_ranges(ranges, window, cx);
 9538    }
 9539
 9540    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9541        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9542        let selections = self
 9543            .selections
 9544            .all(cx)
 9545            .into_iter()
 9546            .map(|s| s.range())
 9547            .collect();
 9548        self.restore_hunks_in_ranges(selections, window, cx);
 9549    }
 9550
 9551    pub fn restore_hunks_in_ranges(
 9552        &mut self,
 9553        ranges: Vec<Range<Point>>,
 9554        window: &mut Window,
 9555        cx: &mut Context<Editor>,
 9556    ) {
 9557        let mut revert_changes = HashMap::default();
 9558        let chunk_by = self
 9559            .snapshot(window, cx)
 9560            .hunks_for_ranges(ranges)
 9561            .into_iter()
 9562            .chunk_by(|hunk| hunk.buffer_id);
 9563        for (buffer_id, hunks) in &chunk_by {
 9564            let hunks = hunks.collect::<Vec<_>>();
 9565            for hunk in &hunks {
 9566                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9567            }
 9568            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9569        }
 9570        drop(chunk_by);
 9571        if !revert_changes.is_empty() {
 9572            self.transact(window, cx, |editor, window, cx| {
 9573                editor.restore(revert_changes, window, cx);
 9574            });
 9575        }
 9576    }
 9577
 9578    pub fn open_active_item_in_terminal(
 9579        &mut self,
 9580        _: &OpenInTerminal,
 9581        window: &mut Window,
 9582        cx: &mut Context<Self>,
 9583    ) {
 9584        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9585            let project_path = buffer.read(cx).project_path(cx)?;
 9586            let project = self.project.as_ref()?.read(cx);
 9587            let entry = project.entry_for_path(&project_path, cx)?;
 9588            let parent = match &entry.canonical_path {
 9589                Some(canonical_path) => canonical_path.to_path_buf(),
 9590                None => project.absolute_path(&project_path, cx)?,
 9591            }
 9592            .parent()?
 9593            .to_path_buf();
 9594            Some(parent)
 9595        }) {
 9596            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9597        }
 9598    }
 9599
 9600    fn set_breakpoint_context_menu(
 9601        &mut self,
 9602        display_row: DisplayRow,
 9603        position: Option<Anchor>,
 9604        clicked_point: gpui::Point<Pixels>,
 9605        window: &mut Window,
 9606        cx: &mut Context<Self>,
 9607    ) {
 9608        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9609            return;
 9610        }
 9611        let source = self
 9612            .buffer
 9613            .read(cx)
 9614            .snapshot(cx)
 9615            .anchor_before(Point::new(display_row.0, 0u32));
 9616
 9617        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9618
 9619        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9620            self,
 9621            source,
 9622            clicked_point,
 9623            context_menu,
 9624            window,
 9625            cx,
 9626        );
 9627    }
 9628
 9629    fn add_edit_breakpoint_block(
 9630        &mut self,
 9631        anchor: Anchor,
 9632        breakpoint: &Breakpoint,
 9633        edit_action: BreakpointPromptEditAction,
 9634        window: &mut Window,
 9635        cx: &mut Context<Self>,
 9636    ) {
 9637        let weak_editor = cx.weak_entity();
 9638        let bp_prompt = cx.new(|cx| {
 9639            BreakpointPromptEditor::new(
 9640                weak_editor,
 9641                anchor,
 9642                breakpoint.clone(),
 9643                edit_action,
 9644                window,
 9645                cx,
 9646            )
 9647        });
 9648
 9649        let height = bp_prompt.update(cx, |this, cx| {
 9650            this.prompt
 9651                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9652        });
 9653        let cloned_prompt = bp_prompt.clone();
 9654        let blocks = vec![BlockProperties {
 9655            style: BlockStyle::Sticky,
 9656            placement: BlockPlacement::Above(anchor),
 9657            height: Some(height),
 9658            render: Arc::new(move |cx| {
 9659                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9660                cloned_prompt.clone().into_any_element()
 9661            }),
 9662            priority: 0,
 9663            render_in_minimap: true,
 9664        }];
 9665
 9666        let focus_handle = bp_prompt.focus_handle(cx);
 9667        window.focus(&focus_handle);
 9668
 9669        let block_ids = self.insert_blocks(blocks, None, cx);
 9670        bp_prompt.update(cx, |prompt, _| {
 9671            prompt.add_block_ids(block_ids);
 9672        });
 9673    }
 9674
 9675    pub(crate) fn breakpoint_at_row(
 9676        &self,
 9677        row: u32,
 9678        window: &mut Window,
 9679        cx: &mut Context<Self>,
 9680    ) -> Option<(Anchor, Breakpoint)> {
 9681        let snapshot = self.snapshot(window, cx);
 9682        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9683
 9684        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9685    }
 9686
 9687    pub(crate) fn breakpoint_at_anchor(
 9688        &self,
 9689        breakpoint_position: Anchor,
 9690        snapshot: &EditorSnapshot,
 9691        cx: &mut Context<Self>,
 9692    ) -> Option<(Anchor, Breakpoint)> {
 9693        let project = self.project.clone()?;
 9694
 9695        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9696            snapshot
 9697                .buffer_snapshot
 9698                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9699        })?;
 9700
 9701        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9702        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9703        let buffer_snapshot = buffer.read(cx).snapshot();
 9704
 9705        let row = buffer_snapshot
 9706            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9707            .row;
 9708
 9709        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9710        let anchor_end = snapshot
 9711            .buffer_snapshot
 9712            .anchor_after(Point::new(row, line_len));
 9713
 9714        let bp = self
 9715            .breakpoint_store
 9716            .as_ref()?
 9717            .read_with(cx, |breakpoint_store, cx| {
 9718                breakpoint_store
 9719                    .breakpoints(
 9720                        &buffer,
 9721                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9722                        &buffer_snapshot,
 9723                        cx,
 9724                    )
 9725                    .next()
 9726                    .and_then(|(bp, _)| {
 9727                        let breakpoint_row = buffer_snapshot
 9728                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9729                            .row;
 9730
 9731                        if breakpoint_row == row {
 9732                            snapshot
 9733                                .buffer_snapshot
 9734                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9735                                .map(|position| (position, bp.bp.clone()))
 9736                        } else {
 9737                            None
 9738                        }
 9739                    })
 9740            });
 9741        bp
 9742    }
 9743
 9744    pub fn edit_log_breakpoint(
 9745        &mut self,
 9746        _: &EditLogBreakpoint,
 9747        window: &mut Window,
 9748        cx: &mut Context<Self>,
 9749    ) {
 9750        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9751            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9752                message: None,
 9753                state: BreakpointState::Enabled,
 9754                condition: None,
 9755                hit_condition: None,
 9756            });
 9757
 9758            self.add_edit_breakpoint_block(
 9759                anchor,
 9760                &breakpoint,
 9761                BreakpointPromptEditAction::Log,
 9762                window,
 9763                cx,
 9764            );
 9765        }
 9766    }
 9767
 9768    fn breakpoints_at_cursors(
 9769        &self,
 9770        window: &mut Window,
 9771        cx: &mut Context<Self>,
 9772    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9773        let snapshot = self.snapshot(window, cx);
 9774        let cursors = self
 9775            .selections
 9776            .disjoint_anchors()
 9777            .into_iter()
 9778            .map(|selection| {
 9779                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9780
 9781                let breakpoint_position = self
 9782                    .breakpoint_at_row(cursor_position.row, window, cx)
 9783                    .map(|bp| bp.0)
 9784                    .unwrap_or_else(|| {
 9785                        snapshot
 9786                            .display_snapshot
 9787                            .buffer_snapshot
 9788                            .anchor_after(Point::new(cursor_position.row, 0))
 9789                    });
 9790
 9791                let breakpoint = self
 9792                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9793                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9794
 9795                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9796            })
 9797            // 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.
 9798            .collect::<HashMap<Anchor, _>>();
 9799
 9800        cursors.into_iter().collect()
 9801    }
 9802
 9803    pub fn enable_breakpoint(
 9804        &mut self,
 9805        _: &crate::actions::EnableBreakpoint,
 9806        window: &mut Window,
 9807        cx: &mut Context<Self>,
 9808    ) {
 9809        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9810            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9811                continue;
 9812            };
 9813            self.edit_breakpoint_at_anchor(
 9814                anchor,
 9815                breakpoint,
 9816                BreakpointEditAction::InvertState,
 9817                cx,
 9818            );
 9819        }
 9820    }
 9821
 9822    pub fn disable_breakpoint(
 9823        &mut self,
 9824        _: &crate::actions::DisableBreakpoint,
 9825        window: &mut Window,
 9826        cx: &mut Context<Self>,
 9827    ) {
 9828        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9829            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9830                continue;
 9831            };
 9832            self.edit_breakpoint_at_anchor(
 9833                anchor,
 9834                breakpoint,
 9835                BreakpointEditAction::InvertState,
 9836                cx,
 9837            );
 9838        }
 9839    }
 9840
 9841    pub fn toggle_breakpoint(
 9842        &mut self,
 9843        _: &crate::actions::ToggleBreakpoint,
 9844        window: &mut Window,
 9845        cx: &mut Context<Self>,
 9846    ) {
 9847        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9848            if let Some(breakpoint) = breakpoint {
 9849                self.edit_breakpoint_at_anchor(
 9850                    anchor,
 9851                    breakpoint,
 9852                    BreakpointEditAction::Toggle,
 9853                    cx,
 9854                );
 9855            } else {
 9856                self.edit_breakpoint_at_anchor(
 9857                    anchor,
 9858                    Breakpoint::new_standard(),
 9859                    BreakpointEditAction::Toggle,
 9860                    cx,
 9861                );
 9862            }
 9863        }
 9864    }
 9865
 9866    pub fn edit_breakpoint_at_anchor(
 9867        &mut self,
 9868        breakpoint_position: Anchor,
 9869        breakpoint: Breakpoint,
 9870        edit_action: BreakpointEditAction,
 9871        cx: &mut Context<Self>,
 9872    ) {
 9873        let Some(breakpoint_store) = &self.breakpoint_store else {
 9874            return;
 9875        };
 9876
 9877        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9878            if breakpoint_position == Anchor::min() {
 9879                self.buffer()
 9880                    .read(cx)
 9881                    .excerpt_buffer_ids()
 9882                    .into_iter()
 9883                    .next()
 9884            } else {
 9885                None
 9886            }
 9887        }) else {
 9888            return;
 9889        };
 9890
 9891        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9892            return;
 9893        };
 9894
 9895        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9896            breakpoint_store.toggle_breakpoint(
 9897                buffer,
 9898                BreakpointWithPosition {
 9899                    position: breakpoint_position.text_anchor,
 9900                    bp: breakpoint,
 9901                },
 9902                edit_action,
 9903                cx,
 9904            );
 9905        });
 9906
 9907        cx.notify();
 9908    }
 9909
 9910    #[cfg(any(test, feature = "test-support"))]
 9911    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9912        self.breakpoint_store.clone()
 9913    }
 9914
 9915    pub fn prepare_restore_change(
 9916        &self,
 9917        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9918        hunk: &MultiBufferDiffHunk,
 9919        cx: &mut App,
 9920    ) -> Option<()> {
 9921        if hunk.is_created_file() {
 9922            return None;
 9923        }
 9924        let buffer = self.buffer.read(cx);
 9925        let diff = buffer.diff_for(hunk.buffer_id)?;
 9926        let buffer = buffer.buffer(hunk.buffer_id)?;
 9927        let buffer = buffer.read(cx);
 9928        let original_text = diff
 9929            .read(cx)
 9930            .base_text()
 9931            .as_rope()
 9932            .slice(hunk.diff_base_byte_range.clone());
 9933        let buffer_snapshot = buffer.snapshot();
 9934        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9935        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9936            probe
 9937                .0
 9938                .start
 9939                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9940                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9941        }) {
 9942            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9943            Some(())
 9944        } else {
 9945            None
 9946        }
 9947    }
 9948
 9949    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9950        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9951    }
 9952
 9953    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9954        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9955    }
 9956
 9957    fn manipulate_lines<Fn>(
 9958        &mut self,
 9959        window: &mut Window,
 9960        cx: &mut Context<Self>,
 9961        mut callback: Fn,
 9962    ) where
 9963        Fn: FnMut(&mut Vec<&str>),
 9964    {
 9965        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9966
 9967        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9968        let buffer = self.buffer.read(cx).snapshot(cx);
 9969
 9970        let mut edits = Vec::new();
 9971
 9972        let selections = self.selections.all::<Point>(cx);
 9973        let mut selections = selections.iter().peekable();
 9974        let mut contiguous_row_selections = Vec::new();
 9975        let mut new_selections = Vec::new();
 9976        let mut added_lines = 0;
 9977        let mut removed_lines = 0;
 9978
 9979        while let Some(selection) = selections.next() {
 9980            let (start_row, end_row) = consume_contiguous_rows(
 9981                &mut contiguous_row_selections,
 9982                selection,
 9983                &display_map,
 9984                &mut selections,
 9985            );
 9986
 9987            let start_point = Point::new(start_row.0, 0);
 9988            let end_point = Point::new(
 9989                end_row.previous_row().0,
 9990                buffer.line_len(end_row.previous_row()),
 9991            );
 9992            let text = buffer
 9993                .text_for_range(start_point..end_point)
 9994                .collect::<String>();
 9995
 9996            let mut lines = text.split('\n').collect_vec();
 9997
 9998            let lines_before = lines.len();
 9999            callback(&mut lines);
10000            let lines_after = lines.len();
10001
10002            edits.push((start_point..end_point, lines.join("\n")));
10003
10004            // Selections must change based on added and removed line count
10005            let start_row =
10006                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10007            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10008            new_selections.push(Selection {
10009                id: selection.id,
10010                start: start_row,
10011                end: end_row,
10012                goal: SelectionGoal::None,
10013                reversed: selection.reversed,
10014            });
10015
10016            if lines_after > lines_before {
10017                added_lines += lines_after - lines_before;
10018            } else if lines_before > lines_after {
10019                removed_lines += lines_before - lines_after;
10020            }
10021        }
10022
10023        self.transact(window, cx, |this, window, cx| {
10024            let buffer = this.buffer.update(cx, |buffer, cx| {
10025                buffer.edit(edits, None, cx);
10026                buffer.snapshot(cx)
10027            });
10028
10029            // Recalculate offsets on newly edited buffer
10030            let new_selections = new_selections
10031                .iter()
10032                .map(|s| {
10033                    let start_point = Point::new(s.start.0, 0);
10034                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10035                    Selection {
10036                        id: s.id,
10037                        start: buffer.point_to_offset(start_point),
10038                        end: buffer.point_to_offset(end_point),
10039                        goal: s.goal,
10040                        reversed: s.reversed,
10041                    }
10042                })
10043                .collect();
10044
10045            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10046                s.select(new_selections);
10047            });
10048
10049            this.request_autoscroll(Autoscroll::fit(), cx);
10050        });
10051    }
10052
10053    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10054        self.manipulate_text(window, cx, |text| {
10055            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10056            if has_upper_case_characters {
10057                text.to_lowercase()
10058            } else {
10059                text.to_uppercase()
10060            }
10061        })
10062    }
10063
10064    pub fn convert_to_upper_case(
10065        &mut self,
10066        _: &ConvertToUpperCase,
10067        window: &mut Window,
10068        cx: &mut Context<Self>,
10069    ) {
10070        self.manipulate_text(window, cx, |text| text.to_uppercase())
10071    }
10072
10073    pub fn convert_to_lower_case(
10074        &mut self,
10075        _: &ConvertToLowerCase,
10076        window: &mut Window,
10077        cx: &mut Context<Self>,
10078    ) {
10079        self.manipulate_text(window, cx, |text| text.to_lowercase())
10080    }
10081
10082    pub fn convert_to_title_case(
10083        &mut self,
10084        _: &ConvertToTitleCase,
10085        window: &mut Window,
10086        cx: &mut Context<Self>,
10087    ) {
10088        self.manipulate_text(window, cx, |text| {
10089            text.split('\n')
10090                .map(|line| line.to_case(Case::Title))
10091                .join("\n")
10092        })
10093    }
10094
10095    pub fn convert_to_snake_case(
10096        &mut self,
10097        _: &ConvertToSnakeCase,
10098        window: &mut Window,
10099        cx: &mut Context<Self>,
10100    ) {
10101        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10102    }
10103
10104    pub fn convert_to_kebab_case(
10105        &mut self,
10106        _: &ConvertToKebabCase,
10107        window: &mut Window,
10108        cx: &mut Context<Self>,
10109    ) {
10110        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10111    }
10112
10113    pub fn convert_to_upper_camel_case(
10114        &mut self,
10115        _: &ConvertToUpperCamelCase,
10116        window: &mut Window,
10117        cx: &mut Context<Self>,
10118    ) {
10119        self.manipulate_text(window, cx, |text| {
10120            text.split('\n')
10121                .map(|line| line.to_case(Case::UpperCamel))
10122                .join("\n")
10123        })
10124    }
10125
10126    pub fn convert_to_lower_camel_case(
10127        &mut self,
10128        _: &ConvertToLowerCamelCase,
10129        window: &mut Window,
10130        cx: &mut Context<Self>,
10131    ) {
10132        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10133    }
10134
10135    pub fn convert_to_opposite_case(
10136        &mut self,
10137        _: &ConvertToOppositeCase,
10138        window: &mut Window,
10139        cx: &mut Context<Self>,
10140    ) {
10141        self.manipulate_text(window, cx, |text| {
10142            text.chars()
10143                .fold(String::with_capacity(text.len()), |mut t, c| {
10144                    if c.is_uppercase() {
10145                        t.extend(c.to_lowercase());
10146                    } else {
10147                        t.extend(c.to_uppercase());
10148                    }
10149                    t
10150                })
10151        })
10152    }
10153
10154    pub fn convert_to_rot13(
10155        &mut self,
10156        _: &ConvertToRot13,
10157        window: &mut Window,
10158        cx: &mut Context<Self>,
10159    ) {
10160        self.manipulate_text(window, cx, |text| {
10161            text.chars()
10162                .map(|c| match c {
10163                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10164                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10165                    _ => c,
10166                })
10167                .collect()
10168        })
10169    }
10170
10171    pub fn convert_to_rot47(
10172        &mut self,
10173        _: &ConvertToRot47,
10174        window: &mut Window,
10175        cx: &mut Context<Self>,
10176    ) {
10177        self.manipulate_text(window, cx, |text| {
10178            text.chars()
10179                .map(|c| {
10180                    let code_point = c as u32;
10181                    if code_point >= 33 && code_point <= 126 {
10182                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10183                    }
10184                    c
10185                })
10186                .collect()
10187        })
10188    }
10189
10190    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10191    where
10192        Fn: FnMut(&str) -> String,
10193    {
10194        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10195        let buffer = self.buffer.read(cx).snapshot(cx);
10196
10197        let mut new_selections = Vec::new();
10198        let mut edits = Vec::new();
10199        let mut selection_adjustment = 0i32;
10200
10201        for selection in self.selections.all::<usize>(cx) {
10202            let selection_is_empty = selection.is_empty();
10203
10204            let (start, end) = if selection_is_empty {
10205                let word_range = movement::surrounding_word(
10206                    &display_map,
10207                    selection.start.to_display_point(&display_map),
10208                );
10209                let start = word_range.start.to_offset(&display_map, Bias::Left);
10210                let end = word_range.end.to_offset(&display_map, Bias::Left);
10211                (start, end)
10212            } else {
10213                (selection.start, selection.end)
10214            };
10215
10216            let text = buffer.text_for_range(start..end).collect::<String>();
10217            let old_length = text.len() as i32;
10218            let text = callback(&text);
10219
10220            new_selections.push(Selection {
10221                start: (start as i32 - selection_adjustment) as usize,
10222                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10223                goal: SelectionGoal::None,
10224                ..selection
10225            });
10226
10227            selection_adjustment += old_length - text.len() as i32;
10228
10229            edits.push((start..end, text));
10230        }
10231
10232        self.transact(window, cx, |this, window, cx| {
10233            this.buffer.update(cx, |buffer, cx| {
10234                buffer.edit(edits, None, cx);
10235            });
10236
10237            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10238                s.select(new_selections);
10239            });
10240
10241            this.request_autoscroll(Autoscroll::fit(), cx);
10242        });
10243    }
10244
10245    pub fn duplicate(
10246        &mut self,
10247        upwards: bool,
10248        whole_lines: bool,
10249        window: &mut Window,
10250        cx: &mut Context<Self>,
10251    ) {
10252        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10253
10254        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10255        let buffer = &display_map.buffer_snapshot;
10256        let selections = self.selections.all::<Point>(cx);
10257
10258        let mut edits = Vec::new();
10259        let mut selections_iter = selections.iter().peekable();
10260        while let Some(selection) = selections_iter.next() {
10261            let mut rows = selection.spanned_rows(false, &display_map);
10262            // duplicate line-wise
10263            if whole_lines || selection.start == selection.end {
10264                // Avoid duplicating the same lines twice.
10265                while let Some(next_selection) = selections_iter.peek() {
10266                    let next_rows = next_selection.spanned_rows(false, &display_map);
10267                    if next_rows.start < rows.end {
10268                        rows.end = next_rows.end;
10269                        selections_iter.next().unwrap();
10270                    } else {
10271                        break;
10272                    }
10273                }
10274
10275                // Copy the text from the selected row region and splice it either at the start
10276                // or end of the region.
10277                let start = Point::new(rows.start.0, 0);
10278                let end = Point::new(
10279                    rows.end.previous_row().0,
10280                    buffer.line_len(rows.end.previous_row()),
10281                );
10282                let text = buffer
10283                    .text_for_range(start..end)
10284                    .chain(Some("\n"))
10285                    .collect::<String>();
10286                let insert_location = if upwards {
10287                    Point::new(rows.end.0, 0)
10288                } else {
10289                    start
10290                };
10291                edits.push((insert_location..insert_location, text));
10292            } else {
10293                // duplicate character-wise
10294                let start = selection.start;
10295                let end = selection.end;
10296                let text = buffer.text_for_range(start..end).collect::<String>();
10297                edits.push((selection.end..selection.end, text));
10298            }
10299        }
10300
10301        self.transact(window, cx, |this, _, cx| {
10302            this.buffer.update(cx, |buffer, cx| {
10303                buffer.edit(edits, None, cx);
10304            });
10305
10306            this.request_autoscroll(Autoscroll::fit(), cx);
10307        });
10308    }
10309
10310    pub fn duplicate_line_up(
10311        &mut self,
10312        _: &DuplicateLineUp,
10313        window: &mut Window,
10314        cx: &mut Context<Self>,
10315    ) {
10316        self.duplicate(true, true, window, cx);
10317    }
10318
10319    pub fn duplicate_line_down(
10320        &mut self,
10321        _: &DuplicateLineDown,
10322        window: &mut Window,
10323        cx: &mut Context<Self>,
10324    ) {
10325        self.duplicate(false, true, window, cx);
10326    }
10327
10328    pub fn duplicate_selection(
10329        &mut self,
10330        _: &DuplicateSelection,
10331        window: &mut Window,
10332        cx: &mut Context<Self>,
10333    ) {
10334        self.duplicate(false, false, window, cx);
10335    }
10336
10337    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10338        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10339
10340        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10341        let buffer = self.buffer.read(cx).snapshot(cx);
10342
10343        let mut edits = Vec::new();
10344        let mut unfold_ranges = Vec::new();
10345        let mut refold_creases = Vec::new();
10346
10347        let selections = self.selections.all::<Point>(cx);
10348        let mut selections = selections.iter().peekable();
10349        let mut contiguous_row_selections = Vec::new();
10350        let mut new_selections = Vec::new();
10351
10352        while let Some(selection) = selections.next() {
10353            // Find all the selections that span a contiguous row range
10354            let (start_row, end_row) = consume_contiguous_rows(
10355                &mut contiguous_row_selections,
10356                selection,
10357                &display_map,
10358                &mut selections,
10359            );
10360
10361            // Move the text spanned by the row range to be before the line preceding the row range
10362            if start_row.0 > 0 {
10363                let range_to_move = Point::new(
10364                    start_row.previous_row().0,
10365                    buffer.line_len(start_row.previous_row()),
10366                )
10367                    ..Point::new(
10368                        end_row.previous_row().0,
10369                        buffer.line_len(end_row.previous_row()),
10370                    );
10371                let insertion_point = display_map
10372                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10373                    .0;
10374
10375                // Don't move lines across excerpts
10376                if buffer
10377                    .excerpt_containing(insertion_point..range_to_move.end)
10378                    .is_some()
10379                {
10380                    let text = buffer
10381                        .text_for_range(range_to_move.clone())
10382                        .flat_map(|s| s.chars())
10383                        .skip(1)
10384                        .chain(['\n'])
10385                        .collect::<String>();
10386
10387                    edits.push((
10388                        buffer.anchor_after(range_to_move.start)
10389                            ..buffer.anchor_before(range_to_move.end),
10390                        String::new(),
10391                    ));
10392                    let insertion_anchor = buffer.anchor_after(insertion_point);
10393                    edits.push((insertion_anchor..insertion_anchor, text));
10394
10395                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10396
10397                    // Move selections up
10398                    new_selections.extend(contiguous_row_selections.drain(..).map(
10399                        |mut selection| {
10400                            selection.start.row -= row_delta;
10401                            selection.end.row -= row_delta;
10402                            selection
10403                        },
10404                    ));
10405
10406                    // Move folds up
10407                    unfold_ranges.push(range_to_move.clone());
10408                    for fold in display_map.folds_in_range(
10409                        buffer.anchor_before(range_to_move.start)
10410                            ..buffer.anchor_after(range_to_move.end),
10411                    ) {
10412                        let mut start = fold.range.start.to_point(&buffer);
10413                        let mut end = fold.range.end.to_point(&buffer);
10414                        start.row -= row_delta;
10415                        end.row -= row_delta;
10416                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10417                    }
10418                }
10419            }
10420
10421            // If we didn't move line(s), preserve the existing selections
10422            new_selections.append(&mut contiguous_row_selections);
10423        }
10424
10425        self.transact(window, cx, |this, window, cx| {
10426            this.unfold_ranges(&unfold_ranges, true, true, cx);
10427            this.buffer.update(cx, |buffer, cx| {
10428                for (range, text) in edits {
10429                    buffer.edit([(range, text)], None, cx);
10430                }
10431            });
10432            this.fold_creases(refold_creases, true, window, cx);
10433            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10434                s.select(new_selections);
10435            })
10436        });
10437    }
10438
10439    pub fn move_line_down(
10440        &mut self,
10441        _: &MoveLineDown,
10442        window: &mut Window,
10443        cx: &mut Context<Self>,
10444    ) {
10445        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10446
10447        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10448        let buffer = self.buffer.read(cx).snapshot(cx);
10449
10450        let mut edits = Vec::new();
10451        let mut unfold_ranges = Vec::new();
10452        let mut refold_creases = Vec::new();
10453
10454        let selections = self.selections.all::<Point>(cx);
10455        let mut selections = selections.iter().peekable();
10456        let mut contiguous_row_selections = Vec::new();
10457        let mut new_selections = Vec::new();
10458
10459        while let Some(selection) = selections.next() {
10460            // Find all the selections that span a contiguous row range
10461            let (start_row, end_row) = consume_contiguous_rows(
10462                &mut contiguous_row_selections,
10463                selection,
10464                &display_map,
10465                &mut selections,
10466            );
10467
10468            // Move the text spanned by the row range to be after the last line of the row range
10469            if end_row.0 <= buffer.max_point().row {
10470                let range_to_move =
10471                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10472                let insertion_point = display_map
10473                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10474                    .0;
10475
10476                // Don't move lines across excerpt boundaries
10477                if buffer
10478                    .excerpt_containing(range_to_move.start..insertion_point)
10479                    .is_some()
10480                {
10481                    let mut text = String::from("\n");
10482                    text.extend(buffer.text_for_range(range_to_move.clone()));
10483                    text.pop(); // Drop trailing newline
10484                    edits.push((
10485                        buffer.anchor_after(range_to_move.start)
10486                            ..buffer.anchor_before(range_to_move.end),
10487                        String::new(),
10488                    ));
10489                    let insertion_anchor = buffer.anchor_after(insertion_point);
10490                    edits.push((insertion_anchor..insertion_anchor, text));
10491
10492                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10493
10494                    // Move selections down
10495                    new_selections.extend(contiguous_row_selections.drain(..).map(
10496                        |mut selection| {
10497                            selection.start.row += row_delta;
10498                            selection.end.row += row_delta;
10499                            selection
10500                        },
10501                    ));
10502
10503                    // Move folds down
10504                    unfold_ranges.push(range_to_move.clone());
10505                    for fold in display_map.folds_in_range(
10506                        buffer.anchor_before(range_to_move.start)
10507                            ..buffer.anchor_after(range_to_move.end),
10508                    ) {
10509                        let mut start = fold.range.start.to_point(&buffer);
10510                        let mut end = fold.range.end.to_point(&buffer);
10511                        start.row += row_delta;
10512                        end.row += row_delta;
10513                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10514                    }
10515                }
10516            }
10517
10518            // If we didn't move line(s), preserve the existing selections
10519            new_selections.append(&mut contiguous_row_selections);
10520        }
10521
10522        self.transact(window, cx, |this, window, cx| {
10523            this.unfold_ranges(&unfold_ranges, true, true, cx);
10524            this.buffer.update(cx, |buffer, cx| {
10525                for (range, text) in edits {
10526                    buffer.edit([(range, text)], None, cx);
10527                }
10528            });
10529            this.fold_creases(refold_creases, true, window, cx);
10530            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10531                s.select(new_selections)
10532            });
10533        });
10534    }
10535
10536    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10537        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10538        let text_layout_details = &self.text_layout_details(window);
10539        self.transact(window, cx, |this, window, cx| {
10540            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10541                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10542                s.move_with(|display_map, selection| {
10543                    if !selection.is_empty() {
10544                        return;
10545                    }
10546
10547                    let mut head = selection.head();
10548                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10549                    if head.column() == display_map.line_len(head.row()) {
10550                        transpose_offset = display_map
10551                            .buffer_snapshot
10552                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10553                    }
10554
10555                    if transpose_offset == 0 {
10556                        return;
10557                    }
10558
10559                    *head.column_mut() += 1;
10560                    head = display_map.clip_point(head, Bias::Right);
10561                    let goal = SelectionGoal::HorizontalPosition(
10562                        display_map
10563                            .x_for_display_point(head, text_layout_details)
10564                            .into(),
10565                    );
10566                    selection.collapse_to(head, goal);
10567
10568                    let transpose_start = display_map
10569                        .buffer_snapshot
10570                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10571                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10572                        let transpose_end = display_map
10573                            .buffer_snapshot
10574                            .clip_offset(transpose_offset + 1, Bias::Right);
10575                        if let Some(ch) =
10576                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10577                        {
10578                            edits.push((transpose_start..transpose_offset, String::new()));
10579                            edits.push((transpose_end..transpose_end, ch.to_string()));
10580                        }
10581                    }
10582                });
10583                edits
10584            });
10585            this.buffer
10586                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10587            let selections = this.selections.all::<usize>(cx);
10588            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10589                s.select(selections);
10590            });
10591        });
10592    }
10593
10594    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10595        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10596        self.rewrap_impl(RewrapOptions::default(), cx)
10597    }
10598
10599    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10600        let buffer = self.buffer.read(cx).snapshot(cx);
10601        let selections = self.selections.all::<Point>(cx);
10602        let mut selections = selections.iter().peekable();
10603
10604        let mut edits = Vec::new();
10605        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10606
10607        while let Some(selection) = selections.next() {
10608            let mut start_row = selection.start.row;
10609            let mut end_row = selection.end.row;
10610
10611            // Skip selections that overlap with a range that has already been rewrapped.
10612            let selection_range = start_row..end_row;
10613            if rewrapped_row_ranges
10614                .iter()
10615                .any(|range| range.overlaps(&selection_range))
10616            {
10617                continue;
10618            }
10619
10620            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10621
10622            // Since not all lines in the selection may be at the same indent
10623            // level, choose the indent size that is the most common between all
10624            // of the lines.
10625            //
10626            // If there is a tie, we use the deepest indent.
10627            let (indent_size, indent_end) = {
10628                let mut indent_size_occurrences = HashMap::default();
10629                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10630
10631                for row in start_row..=end_row {
10632                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10633                    rows_by_indent_size.entry(indent).or_default().push(row);
10634                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10635                }
10636
10637                let indent_size = indent_size_occurrences
10638                    .into_iter()
10639                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10640                    .map(|(indent, _)| indent)
10641                    .unwrap_or_default();
10642                let row = rows_by_indent_size[&indent_size][0];
10643                let indent_end = Point::new(row, indent_size.len);
10644
10645                (indent_size, indent_end)
10646            };
10647
10648            let mut line_prefix = indent_size.chars().collect::<String>();
10649
10650            let mut inside_comment = false;
10651            if let Some(comment_prefix) =
10652                buffer
10653                    .language_scope_at(selection.head())
10654                    .and_then(|language| {
10655                        language
10656                            .line_comment_prefixes()
10657                            .iter()
10658                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10659                            .cloned()
10660                    })
10661            {
10662                line_prefix.push_str(&comment_prefix);
10663                inside_comment = true;
10664            }
10665
10666            let language_settings = buffer.language_settings_at(selection.head(), cx);
10667            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10668                RewrapBehavior::InComments => inside_comment,
10669                RewrapBehavior::InSelections => !selection.is_empty(),
10670                RewrapBehavior::Anywhere => true,
10671            };
10672
10673            let should_rewrap = options.override_language_settings
10674                || allow_rewrap_based_on_language
10675                || self.hard_wrap.is_some();
10676            if !should_rewrap {
10677                continue;
10678            }
10679
10680            if selection.is_empty() {
10681                'expand_upwards: while start_row > 0 {
10682                    let prev_row = start_row - 1;
10683                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10684                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10685                    {
10686                        start_row = prev_row;
10687                    } else {
10688                        break 'expand_upwards;
10689                    }
10690                }
10691
10692                'expand_downwards: while end_row < buffer.max_point().row {
10693                    let next_row = end_row + 1;
10694                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10695                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10696                    {
10697                        end_row = next_row;
10698                    } else {
10699                        break 'expand_downwards;
10700                    }
10701                }
10702            }
10703
10704            let start = Point::new(start_row, 0);
10705            let start_offset = start.to_offset(&buffer);
10706            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10707            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10708            let Some(lines_without_prefixes) = selection_text
10709                .lines()
10710                .map(|line| {
10711                    line.strip_prefix(&line_prefix)
10712                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10713                        .with_context(|| {
10714                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10715                        })
10716                })
10717                .collect::<Result<Vec<_>, _>>()
10718                .log_err()
10719            else {
10720                continue;
10721            };
10722
10723            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10724                buffer
10725                    .language_settings_at(Point::new(start_row, 0), cx)
10726                    .preferred_line_length as usize
10727            });
10728            let wrapped_text = wrap_with_prefix(
10729                line_prefix,
10730                lines_without_prefixes.join("\n"),
10731                wrap_column,
10732                tab_size,
10733                options.preserve_existing_whitespace,
10734            );
10735
10736            // TODO: should always use char-based diff while still supporting cursor behavior that
10737            // matches vim.
10738            let mut diff_options = DiffOptions::default();
10739            if options.override_language_settings {
10740                diff_options.max_word_diff_len = 0;
10741                diff_options.max_word_diff_line_count = 0;
10742            } else {
10743                diff_options.max_word_diff_len = usize::MAX;
10744                diff_options.max_word_diff_line_count = usize::MAX;
10745            }
10746
10747            for (old_range, new_text) in
10748                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10749            {
10750                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10751                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10752                edits.push((edit_start..edit_end, new_text));
10753            }
10754
10755            rewrapped_row_ranges.push(start_row..=end_row);
10756        }
10757
10758        self.buffer
10759            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10760    }
10761
10762    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10763        let mut text = String::new();
10764        let buffer = self.buffer.read(cx).snapshot(cx);
10765        let mut selections = self.selections.all::<Point>(cx);
10766        let mut clipboard_selections = Vec::with_capacity(selections.len());
10767        {
10768            let max_point = buffer.max_point();
10769            let mut is_first = true;
10770            for selection in &mut selections {
10771                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10772                if is_entire_line {
10773                    selection.start = Point::new(selection.start.row, 0);
10774                    if !selection.is_empty() && selection.end.column == 0 {
10775                        selection.end = cmp::min(max_point, selection.end);
10776                    } else {
10777                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10778                    }
10779                    selection.goal = SelectionGoal::None;
10780                }
10781                if is_first {
10782                    is_first = false;
10783                } else {
10784                    text += "\n";
10785                }
10786                let mut len = 0;
10787                for chunk in buffer.text_for_range(selection.start..selection.end) {
10788                    text.push_str(chunk);
10789                    len += chunk.len();
10790                }
10791                clipboard_selections.push(ClipboardSelection {
10792                    len,
10793                    is_entire_line,
10794                    first_line_indent: buffer
10795                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10796                        .len,
10797                });
10798            }
10799        }
10800
10801        self.transact(window, cx, |this, window, cx| {
10802            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10803                s.select(selections);
10804            });
10805            this.insert("", window, cx);
10806        });
10807        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10808    }
10809
10810    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10811        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10812        let item = self.cut_common(window, cx);
10813        cx.write_to_clipboard(item);
10814    }
10815
10816    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10817        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10818        self.change_selections(None, window, cx, |s| {
10819            s.move_with(|snapshot, sel| {
10820                if sel.is_empty() {
10821                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10822                }
10823            });
10824        });
10825        let item = self.cut_common(window, cx);
10826        cx.set_global(KillRing(item))
10827    }
10828
10829    pub fn kill_ring_yank(
10830        &mut self,
10831        _: &KillRingYank,
10832        window: &mut Window,
10833        cx: &mut Context<Self>,
10834    ) {
10835        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10836        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10837            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10838                (kill_ring.text().to_string(), kill_ring.metadata_json())
10839            } else {
10840                return;
10841            }
10842        } else {
10843            return;
10844        };
10845        self.do_paste(&text, metadata, false, window, cx);
10846    }
10847
10848    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10849        self.do_copy(true, cx);
10850    }
10851
10852    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10853        self.do_copy(false, cx);
10854    }
10855
10856    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10857        let selections = self.selections.all::<Point>(cx);
10858        let buffer = self.buffer.read(cx).read(cx);
10859        let mut text = String::new();
10860
10861        let mut clipboard_selections = Vec::with_capacity(selections.len());
10862        {
10863            let max_point = buffer.max_point();
10864            let mut is_first = true;
10865            for selection in &selections {
10866                let mut start = selection.start;
10867                let mut end = selection.end;
10868                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10869                if is_entire_line {
10870                    start = Point::new(start.row, 0);
10871                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10872                }
10873
10874                let mut trimmed_selections = Vec::new();
10875                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10876                    let row = MultiBufferRow(start.row);
10877                    let first_indent = buffer.indent_size_for_line(row);
10878                    if first_indent.len == 0 || start.column > first_indent.len {
10879                        trimmed_selections.push(start..end);
10880                    } else {
10881                        trimmed_selections.push(
10882                            Point::new(row.0, first_indent.len)
10883                                ..Point::new(row.0, buffer.line_len(row)),
10884                        );
10885                        for row in start.row + 1..=end.row {
10886                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10887                            if row == end.row {
10888                                line_len = end.column;
10889                            }
10890                            if line_len == 0 {
10891                                trimmed_selections
10892                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10893                                continue;
10894                            }
10895                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10896                            if row_indent_size.len >= first_indent.len {
10897                                trimmed_selections.push(
10898                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10899                                );
10900                            } else {
10901                                trimmed_selections.clear();
10902                                trimmed_selections.push(start..end);
10903                                break;
10904                            }
10905                        }
10906                    }
10907                } else {
10908                    trimmed_selections.push(start..end);
10909                }
10910
10911                for trimmed_range in trimmed_selections {
10912                    if is_first {
10913                        is_first = false;
10914                    } else {
10915                        text += "\n";
10916                    }
10917                    let mut len = 0;
10918                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10919                        text.push_str(chunk);
10920                        len += chunk.len();
10921                    }
10922                    clipboard_selections.push(ClipboardSelection {
10923                        len,
10924                        is_entire_line,
10925                        first_line_indent: buffer
10926                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10927                            .len,
10928                    });
10929                }
10930            }
10931        }
10932
10933        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10934            text,
10935            clipboard_selections,
10936        ));
10937    }
10938
10939    pub fn do_paste(
10940        &mut self,
10941        text: &String,
10942        clipboard_selections: Option<Vec<ClipboardSelection>>,
10943        handle_entire_lines: bool,
10944        window: &mut Window,
10945        cx: &mut Context<Self>,
10946    ) {
10947        if self.read_only(cx) {
10948            return;
10949        }
10950
10951        let clipboard_text = Cow::Borrowed(text);
10952
10953        self.transact(window, cx, |this, window, cx| {
10954            if let Some(mut clipboard_selections) = clipboard_selections {
10955                let old_selections = this.selections.all::<usize>(cx);
10956                let all_selections_were_entire_line =
10957                    clipboard_selections.iter().all(|s| s.is_entire_line);
10958                let first_selection_indent_column =
10959                    clipboard_selections.first().map(|s| s.first_line_indent);
10960                if clipboard_selections.len() != old_selections.len() {
10961                    clipboard_selections.drain(..);
10962                }
10963                let cursor_offset = this.selections.last::<usize>(cx).head();
10964                let mut auto_indent_on_paste = true;
10965
10966                this.buffer.update(cx, |buffer, cx| {
10967                    let snapshot = buffer.read(cx);
10968                    auto_indent_on_paste = snapshot
10969                        .language_settings_at(cursor_offset, cx)
10970                        .auto_indent_on_paste;
10971
10972                    let mut start_offset = 0;
10973                    let mut edits = Vec::new();
10974                    let mut original_indent_columns = Vec::new();
10975                    for (ix, selection) in old_selections.iter().enumerate() {
10976                        let to_insert;
10977                        let entire_line;
10978                        let original_indent_column;
10979                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10980                            let end_offset = start_offset + clipboard_selection.len;
10981                            to_insert = &clipboard_text[start_offset..end_offset];
10982                            entire_line = clipboard_selection.is_entire_line;
10983                            start_offset = end_offset + 1;
10984                            original_indent_column = Some(clipboard_selection.first_line_indent);
10985                        } else {
10986                            to_insert = clipboard_text.as_str();
10987                            entire_line = all_selections_were_entire_line;
10988                            original_indent_column = first_selection_indent_column
10989                        }
10990
10991                        // If the corresponding selection was empty when this slice of the
10992                        // clipboard text was written, then the entire line containing the
10993                        // selection was copied. If this selection is also currently empty,
10994                        // then paste the line before the current line of the buffer.
10995                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10996                            let column = selection.start.to_point(&snapshot).column as usize;
10997                            let line_start = selection.start - column;
10998                            line_start..line_start
10999                        } else {
11000                            selection.range()
11001                        };
11002
11003                        edits.push((range, to_insert));
11004                        original_indent_columns.push(original_indent_column);
11005                    }
11006                    drop(snapshot);
11007
11008                    buffer.edit(
11009                        edits,
11010                        if auto_indent_on_paste {
11011                            Some(AutoindentMode::Block {
11012                                original_indent_columns,
11013                            })
11014                        } else {
11015                            None
11016                        },
11017                        cx,
11018                    );
11019                });
11020
11021                let selections = this.selections.all::<usize>(cx);
11022                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11023                    s.select(selections)
11024                });
11025            } else {
11026                this.insert(&clipboard_text, window, cx);
11027            }
11028        });
11029    }
11030
11031    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11032        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11033        if let Some(item) = cx.read_from_clipboard() {
11034            let entries = item.entries();
11035
11036            match entries.first() {
11037                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11038                // of all the pasted entries.
11039                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11040                    .do_paste(
11041                        clipboard_string.text(),
11042                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11043                        true,
11044                        window,
11045                        cx,
11046                    ),
11047                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11048            }
11049        }
11050    }
11051
11052    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11053        if self.read_only(cx) {
11054            return;
11055        }
11056
11057        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11058
11059        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11060            if let Some((selections, _)) =
11061                self.selection_history.transaction(transaction_id).cloned()
11062            {
11063                self.change_selections(None, window, cx, |s| {
11064                    s.select_anchors(selections.to_vec());
11065                });
11066            } else {
11067                log::error!(
11068                    "No entry in selection_history found for undo. \
11069                     This may correspond to a bug where undo does not update the selection. \
11070                     If this is occurring, please add details to \
11071                     https://github.com/zed-industries/zed/issues/22692"
11072                );
11073            }
11074            self.request_autoscroll(Autoscroll::fit(), cx);
11075            self.unmark_text(window, cx);
11076            self.refresh_inline_completion(true, false, window, cx);
11077            cx.emit(EditorEvent::Edited { transaction_id });
11078            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11079        }
11080    }
11081
11082    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11083        if self.read_only(cx) {
11084            return;
11085        }
11086
11087        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11088
11089        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11090            if let Some((_, Some(selections))) =
11091                self.selection_history.transaction(transaction_id).cloned()
11092            {
11093                self.change_selections(None, window, cx, |s| {
11094                    s.select_anchors(selections.to_vec());
11095                });
11096            } else {
11097                log::error!(
11098                    "No entry in selection_history found for redo. \
11099                     This may correspond to a bug where undo does not update the selection. \
11100                     If this is occurring, please add details to \
11101                     https://github.com/zed-industries/zed/issues/22692"
11102                );
11103            }
11104            self.request_autoscroll(Autoscroll::fit(), cx);
11105            self.unmark_text(window, cx);
11106            self.refresh_inline_completion(true, false, window, cx);
11107            cx.emit(EditorEvent::Edited { transaction_id });
11108        }
11109    }
11110
11111    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11112        self.buffer
11113            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11114    }
11115
11116    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11117        self.buffer
11118            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11119    }
11120
11121    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11122        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11123        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11124            s.move_with(|map, selection| {
11125                let cursor = if selection.is_empty() {
11126                    movement::left(map, selection.start)
11127                } else {
11128                    selection.start
11129                };
11130                selection.collapse_to(cursor, SelectionGoal::None);
11131            });
11132        })
11133    }
11134
11135    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11136        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11137        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11138            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11139        })
11140    }
11141
11142    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11143        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11144        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11145            s.move_with(|map, selection| {
11146                let cursor = if selection.is_empty() {
11147                    movement::right(map, selection.end)
11148                } else {
11149                    selection.end
11150                };
11151                selection.collapse_to(cursor, SelectionGoal::None)
11152            });
11153        })
11154    }
11155
11156    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11157        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11158        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11159            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11160        })
11161    }
11162
11163    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11164        if self.take_rename(true, window, cx).is_some() {
11165            return;
11166        }
11167
11168        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11169            cx.propagate();
11170            return;
11171        }
11172
11173        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11174
11175        let text_layout_details = &self.text_layout_details(window);
11176        let selection_count = self.selections.count();
11177        let first_selection = self.selections.first_anchor();
11178
11179        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11180            s.move_with(|map, selection| {
11181                if !selection.is_empty() {
11182                    selection.goal = SelectionGoal::None;
11183                }
11184                let (cursor, goal) = movement::up(
11185                    map,
11186                    selection.start,
11187                    selection.goal,
11188                    false,
11189                    text_layout_details,
11190                );
11191                selection.collapse_to(cursor, goal);
11192            });
11193        });
11194
11195        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11196        {
11197            cx.propagate();
11198        }
11199    }
11200
11201    pub fn move_up_by_lines(
11202        &mut self,
11203        action: &MoveUpByLines,
11204        window: &mut Window,
11205        cx: &mut Context<Self>,
11206    ) {
11207        if self.take_rename(true, window, cx).is_some() {
11208            return;
11209        }
11210
11211        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11212            cx.propagate();
11213            return;
11214        }
11215
11216        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11217
11218        let text_layout_details = &self.text_layout_details(window);
11219
11220        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11221            s.move_with(|map, selection| {
11222                if !selection.is_empty() {
11223                    selection.goal = SelectionGoal::None;
11224                }
11225                let (cursor, goal) = movement::up_by_rows(
11226                    map,
11227                    selection.start,
11228                    action.lines,
11229                    selection.goal,
11230                    false,
11231                    text_layout_details,
11232                );
11233                selection.collapse_to(cursor, goal);
11234            });
11235        })
11236    }
11237
11238    pub fn move_down_by_lines(
11239        &mut self,
11240        action: &MoveDownByLines,
11241        window: &mut Window,
11242        cx: &mut Context<Self>,
11243    ) {
11244        if self.take_rename(true, window, cx).is_some() {
11245            return;
11246        }
11247
11248        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11249            cx.propagate();
11250            return;
11251        }
11252
11253        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11254
11255        let text_layout_details = &self.text_layout_details(window);
11256
11257        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11258            s.move_with(|map, selection| {
11259                if !selection.is_empty() {
11260                    selection.goal = SelectionGoal::None;
11261                }
11262                let (cursor, goal) = movement::down_by_rows(
11263                    map,
11264                    selection.start,
11265                    action.lines,
11266                    selection.goal,
11267                    false,
11268                    text_layout_details,
11269                );
11270                selection.collapse_to(cursor, goal);
11271            });
11272        })
11273    }
11274
11275    pub fn select_down_by_lines(
11276        &mut self,
11277        action: &SelectDownByLines,
11278        window: &mut Window,
11279        cx: &mut Context<Self>,
11280    ) {
11281        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11282        let text_layout_details = &self.text_layout_details(window);
11283        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11284            s.move_heads_with(|map, head, goal| {
11285                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11286            })
11287        })
11288    }
11289
11290    pub fn select_up_by_lines(
11291        &mut self,
11292        action: &SelectUpByLines,
11293        window: &mut Window,
11294        cx: &mut Context<Self>,
11295    ) {
11296        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11297        let text_layout_details = &self.text_layout_details(window);
11298        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11299            s.move_heads_with(|map, head, goal| {
11300                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11301            })
11302        })
11303    }
11304
11305    pub fn select_page_up(
11306        &mut self,
11307        _: &SelectPageUp,
11308        window: &mut Window,
11309        cx: &mut Context<Self>,
11310    ) {
11311        let Some(row_count) = self.visible_row_count() else {
11312            return;
11313        };
11314
11315        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11316
11317        let text_layout_details = &self.text_layout_details(window);
11318
11319        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11320            s.move_heads_with(|map, head, goal| {
11321                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11322            })
11323        })
11324    }
11325
11326    pub fn move_page_up(
11327        &mut self,
11328        action: &MovePageUp,
11329        window: &mut Window,
11330        cx: &mut Context<Self>,
11331    ) {
11332        if self.take_rename(true, window, cx).is_some() {
11333            return;
11334        }
11335
11336        if self
11337            .context_menu
11338            .borrow_mut()
11339            .as_mut()
11340            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11341            .unwrap_or(false)
11342        {
11343            return;
11344        }
11345
11346        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11347            cx.propagate();
11348            return;
11349        }
11350
11351        let Some(row_count) = self.visible_row_count() else {
11352            return;
11353        };
11354
11355        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11356
11357        let autoscroll = if action.center_cursor {
11358            Autoscroll::center()
11359        } else {
11360            Autoscroll::fit()
11361        };
11362
11363        let text_layout_details = &self.text_layout_details(window);
11364
11365        self.change_selections(Some(autoscroll), window, cx, |s| {
11366            s.move_with(|map, selection| {
11367                if !selection.is_empty() {
11368                    selection.goal = SelectionGoal::None;
11369                }
11370                let (cursor, goal) = movement::up_by_rows(
11371                    map,
11372                    selection.end,
11373                    row_count,
11374                    selection.goal,
11375                    false,
11376                    text_layout_details,
11377                );
11378                selection.collapse_to(cursor, goal);
11379            });
11380        });
11381    }
11382
11383    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11384        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11385        let text_layout_details = &self.text_layout_details(window);
11386        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11387            s.move_heads_with(|map, head, goal| {
11388                movement::up(map, head, goal, false, text_layout_details)
11389            })
11390        })
11391    }
11392
11393    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11394        self.take_rename(true, window, cx);
11395
11396        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11397            cx.propagate();
11398            return;
11399        }
11400
11401        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11402
11403        let text_layout_details = &self.text_layout_details(window);
11404        let selection_count = self.selections.count();
11405        let first_selection = self.selections.first_anchor();
11406
11407        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11408            s.move_with(|map, selection| {
11409                if !selection.is_empty() {
11410                    selection.goal = SelectionGoal::None;
11411                }
11412                let (cursor, goal) = movement::down(
11413                    map,
11414                    selection.end,
11415                    selection.goal,
11416                    false,
11417                    text_layout_details,
11418                );
11419                selection.collapse_to(cursor, goal);
11420            });
11421        });
11422
11423        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11424        {
11425            cx.propagate();
11426        }
11427    }
11428
11429    pub fn select_page_down(
11430        &mut self,
11431        _: &SelectPageDown,
11432        window: &mut Window,
11433        cx: &mut Context<Self>,
11434    ) {
11435        let Some(row_count) = self.visible_row_count() else {
11436            return;
11437        };
11438
11439        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11440
11441        let text_layout_details = &self.text_layout_details(window);
11442
11443        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11444            s.move_heads_with(|map, head, goal| {
11445                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11446            })
11447        })
11448    }
11449
11450    pub fn move_page_down(
11451        &mut self,
11452        action: &MovePageDown,
11453        window: &mut Window,
11454        cx: &mut Context<Self>,
11455    ) {
11456        if self.take_rename(true, window, cx).is_some() {
11457            return;
11458        }
11459
11460        if self
11461            .context_menu
11462            .borrow_mut()
11463            .as_mut()
11464            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11465            .unwrap_or(false)
11466        {
11467            return;
11468        }
11469
11470        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11471            cx.propagate();
11472            return;
11473        }
11474
11475        let Some(row_count) = self.visible_row_count() else {
11476            return;
11477        };
11478
11479        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11480
11481        let autoscroll = if action.center_cursor {
11482            Autoscroll::center()
11483        } else {
11484            Autoscroll::fit()
11485        };
11486
11487        let text_layout_details = &self.text_layout_details(window);
11488        self.change_selections(Some(autoscroll), window, cx, |s| {
11489            s.move_with(|map, selection| {
11490                if !selection.is_empty() {
11491                    selection.goal = SelectionGoal::None;
11492                }
11493                let (cursor, goal) = movement::down_by_rows(
11494                    map,
11495                    selection.end,
11496                    row_count,
11497                    selection.goal,
11498                    false,
11499                    text_layout_details,
11500                );
11501                selection.collapse_to(cursor, goal);
11502            });
11503        });
11504    }
11505
11506    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11507        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11508        let text_layout_details = &self.text_layout_details(window);
11509        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11510            s.move_heads_with(|map, head, goal| {
11511                movement::down(map, head, goal, false, text_layout_details)
11512            })
11513        });
11514    }
11515
11516    pub fn context_menu_first(
11517        &mut self,
11518        _: &ContextMenuFirst,
11519        _window: &mut Window,
11520        cx: &mut Context<Self>,
11521    ) {
11522        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11523            context_menu.select_first(self.completion_provider.as_deref(), cx);
11524        }
11525    }
11526
11527    pub fn context_menu_prev(
11528        &mut self,
11529        _: &ContextMenuPrevious,
11530        _window: &mut Window,
11531        cx: &mut Context<Self>,
11532    ) {
11533        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11534            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11535        }
11536    }
11537
11538    pub fn context_menu_next(
11539        &mut self,
11540        _: &ContextMenuNext,
11541        _window: &mut Window,
11542        cx: &mut Context<Self>,
11543    ) {
11544        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11545            context_menu.select_next(self.completion_provider.as_deref(), cx);
11546        }
11547    }
11548
11549    pub fn context_menu_last(
11550        &mut self,
11551        _: &ContextMenuLast,
11552        _window: &mut Window,
11553        cx: &mut Context<Self>,
11554    ) {
11555        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11556            context_menu.select_last(self.completion_provider.as_deref(), cx);
11557        }
11558    }
11559
11560    pub fn move_to_previous_word_start(
11561        &mut self,
11562        _: &MoveToPreviousWordStart,
11563        window: &mut Window,
11564        cx: &mut Context<Self>,
11565    ) {
11566        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11567        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11568            s.move_cursors_with(|map, head, _| {
11569                (
11570                    movement::previous_word_start(map, head),
11571                    SelectionGoal::None,
11572                )
11573            });
11574        })
11575    }
11576
11577    pub fn move_to_previous_subword_start(
11578        &mut self,
11579        _: &MoveToPreviousSubwordStart,
11580        window: &mut Window,
11581        cx: &mut Context<Self>,
11582    ) {
11583        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11584        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11585            s.move_cursors_with(|map, head, _| {
11586                (
11587                    movement::previous_subword_start(map, head),
11588                    SelectionGoal::None,
11589                )
11590            });
11591        })
11592    }
11593
11594    pub fn select_to_previous_word_start(
11595        &mut self,
11596        _: &SelectToPreviousWordStart,
11597        window: &mut Window,
11598        cx: &mut Context<Self>,
11599    ) {
11600        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11601        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11602            s.move_heads_with(|map, head, _| {
11603                (
11604                    movement::previous_word_start(map, head),
11605                    SelectionGoal::None,
11606                )
11607            });
11608        })
11609    }
11610
11611    pub fn select_to_previous_subword_start(
11612        &mut self,
11613        _: &SelectToPreviousSubwordStart,
11614        window: &mut Window,
11615        cx: &mut Context<Self>,
11616    ) {
11617        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11618        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11619            s.move_heads_with(|map, head, _| {
11620                (
11621                    movement::previous_subword_start(map, head),
11622                    SelectionGoal::None,
11623                )
11624            });
11625        })
11626    }
11627
11628    pub fn delete_to_previous_word_start(
11629        &mut self,
11630        action: &DeleteToPreviousWordStart,
11631        window: &mut Window,
11632        cx: &mut Context<Self>,
11633    ) {
11634        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11635        self.transact(window, cx, |this, window, cx| {
11636            this.select_autoclose_pair(window, cx);
11637            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11638                s.move_with(|map, selection| {
11639                    if selection.is_empty() {
11640                        let cursor = if action.ignore_newlines {
11641                            movement::previous_word_start(map, selection.head())
11642                        } else {
11643                            movement::previous_word_start_or_newline(map, selection.head())
11644                        };
11645                        selection.set_head(cursor, SelectionGoal::None);
11646                    }
11647                });
11648            });
11649            this.insert("", window, cx);
11650        });
11651    }
11652
11653    pub fn delete_to_previous_subword_start(
11654        &mut self,
11655        _: &DeleteToPreviousSubwordStart,
11656        window: &mut Window,
11657        cx: &mut Context<Self>,
11658    ) {
11659        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11660        self.transact(window, cx, |this, window, cx| {
11661            this.select_autoclose_pair(window, cx);
11662            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11663                s.move_with(|map, selection| {
11664                    if selection.is_empty() {
11665                        let cursor = movement::previous_subword_start(map, selection.head());
11666                        selection.set_head(cursor, SelectionGoal::None);
11667                    }
11668                });
11669            });
11670            this.insert("", window, cx);
11671        });
11672    }
11673
11674    pub fn move_to_next_word_end(
11675        &mut self,
11676        _: &MoveToNextWordEnd,
11677        window: &mut Window,
11678        cx: &mut Context<Self>,
11679    ) {
11680        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11681        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11682            s.move_cursors_with(|map, head, _| {
11683                (movement::next_word_end(map, head), SelectionGoal::None)
11684            });
11685        })
11686    }
11687
11688    pub fn move_to_next_subword_end(
11689        &mut self,
11690        _: &MoveToNextSubwordEnd,
11691        window: &mut Window,
11692        cx: &mut Context<Self>,
11693    ) {
11694        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11695        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11696            s.move_cursors_with(|map, head, _| {
11697                (movement::next_subword_end(map, head), SelectionGoal::None)
11698            });
11699        })
11700    }
11701
11702    pub fn select_to_next_word_end(
11703        &mut self,
11704        _: &SelectToNextWordEnd,
11705        window: &mut Window,
11706        cx: &mut Context<Self>,
11707    ) {
11708        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11709        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11710            s.move_heads_with(|map, head, _| {
11711                (movement::next_word_end(map, head), SelectionGoal::None)
11712            });
11713        })
11714    }
11715
11716    pub fn select_to_next_subword_end(
11717        &mut self,
11718        _: &SelectToNextSubwordEnd,
11719        window: &mut Window,
11720        cx: &mut Context<Self>,
11721    ) {
11722        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11723        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11724            s.move_heads_with(|map, head, _| {
11725                (movement::next_subword_end(map, head), SelectionGoal::None)
11726            });
11727        })
11728    }
11729
11730    pub fn delete_to_next_word_end(
11731        &mut self,
11732        action: &DeleteToNextWordEnd,
11733        window: &mut Window,
11734        cx: &mut Context<Self>,
11735    ) {
11736        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11737        self.transact(window, cx, |this, window, cx| {
11738            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11739                s.move_with(|map, selection| {
11740                    if selection.is_empty() {
11741                        let cursor = if action.ignore_newlines {
11742                            movement::next_word_end(map, selection.head())
11743                        } else {
11744                            movement::next_word_end_or_newline(map, selection.head())
11745                        };
11746                        selection.set_head(cursor, SelectionGoal::None);
11747                    }
11748                });
11749            });
11750            this.insert("", window, cx);
11751        });
11752    }
11753
11754    pub fn delete_to_next_subword_end(
11755        &mut self,
11756        _: &DeleteToNextSubwordEnd,
11757        window: &mut Window,
11758        cx: &mut Context<Self>,
11759    ) {
11760        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11761        self.transact(window, cx, |this, window, cx| {
11762            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11763                s.move_with(|map, selection| {
11764                    if selection.is_empty() {
11765                        let cursor = movement::next_subword_end(map, selection.head());
11766                        selection.set_head(cursor, SelectionGoal::None);
11767                    }
11768                });
11769            });
11770            this.insert("", window, cx);
11771        });
11772    }
11773
11774    pub fn move_to_beginning_of_line(
11775        &mut self,
11776        action: &MoveToBeginningOfLine,
11777        window: &mut Window,
11778        cx: &mut Context<Self>,
11779    ) {
11780        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11781        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11782            s.move_cursors_with(|map, head, _| {
11783                (
11784                    movement::indented_line_beginning(
11785                        map,
11786                        head,
11787                        action.stop_at_soft_wraps,
11788                        action.stop_at_indent,
11789                    ),
11790                    SelectionGoal::None,
11791                )
11792            });
11793        })
11794    }
11795
11796    pub fn select_to_beginning_of_line(
11797        &mut self,
11798        action: &SelectToBeginningOfLine,
11799        window: &mut Window,
11800        cx: &mut Context<Self>,
11801    ) {
11802        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11803        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11804            s.move_heads_with(|map, head, _| {
11805                (
11806                    movement::indented_line_beginning(
11807                        map,
11808                        head,
11809                        action.stop_at_soft_wraps,
11810                        action.stop_at_indent,
11811                    ),
11812                    SelectionGoal::None,
11813                )
11814            });
11815        });
11816    }
11817
11818    pub fn delete_to_beginning_of_line(
11819        &mut self,
11820        action: &DeleteToBeginningOfLine,
11821        window: &mut Window,
11822        cx: &mut Context<Self>,
11823    ) {
11824        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11825        self.transact(window, cx, |this, window, cx| {
11826            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11827                s.move_with(|_, selection| {
11828                    selection.reversed = true;
11829                });
11830            });
11831
11832            this.select_to_beginning_of_line(
11833                &SelectToBeginningOfLine {
11834                    stop_at_soft_wraps: false,
11835                    stop_at_indent: action.stop_at_indent,
11836                },
11837                window,
11838                cx,
11839            );
11840            this.backspace(&Backspace, window, cx);
11841        });
11842    }
11843
11844    pub fn move_to_end_of_line(
11845        &mut self,
11846        action: &MoveToEndOfLine,
11847        window: &mut Window,
11848        cx: &mut Context<Self>,
11849    ) {
11850        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11851        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11852            s.move_cursors_with(|map, head, _| {
11853                (
11854                    movement::line_end(map, head, action.stop_at_soft_wraps),
11855                    SelectionGoal::None,
11856                )
11857            });
11858        })
11859    }
11860
11861    pub fn select_to_end_of_line(
11862        &mut self,
11863        action: &SelectToEndOfLine,
11864        window: &mut Window,
11865        cx: &mut Context<Self>,
11866    ) {
11867        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11868        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11869            s.move_heads_with(|map, head, _| {
11870                (
11871                    movement::line_end(map, head, action.stop_at_soft_wraps),
11872                    SelectionGoal::None,
11873                )
11874            });
11875        })
11876    }
11877
11878    pub fn delete_to_end_of_line(
11879        &mut self,
11880        _: &DeleteToEndOfLine,
11881        window: &mut Window,
11882        cx: &mut Context<Self>,
11883    ) {
11884        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11885        self.transact(window, cx, |this, window, cx| {
11886            this.select_to_end_of_line(
11887                &SelectToEndOfLine {
11888                    stop_at_soft_wraps: false,
11889                },
11890                window,
11891                cx,
11892            );
11893            this.delete(&Delete, window, cx);
11894        });
11895    }
11896
11897    pub fn cut_to_end_of_line(
11898        &mut self,
11899        _: &CutToEndOfLine,
11900        window: &mut Window,
11901        cx: &mut Context<Self>,
11902    ) {
11903        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11904        self.transact(window, cx, |this, window, cx| {
11905            this.select_to_end_of_line(
11906                &SelectToEndOfLine {
11907                    stop_at_soft_wraps: false,
11908                },
11909                window,
11910                cx,
11911            );
11912            this.cut(&Cut, window, cx);
11913        });
11914    }
11915
11916    pub fn move_to_start_of_paragraph(
11917        &mut self,
11918        _: &MoveToStartOfParagraph,
11919        window: &mut Window,
11920        cx: &mut Context<Self>,
11921    ) {
11922        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11923            cx.propagate();
11924            return;
11925        }
11926        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11927        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11928            s.move_with(|map, selection| {
11929                selection.collapse_to(
11930                    movement::start_of_paragraph(map, selection.head(), 1),
11931                    SelectionGoal::None,
11932                )
11933            });
11934        })
11935    }
11936
11937    pub fn move_to_end_of_paragraph(
11938        &mut self,
11939        _: &MoveToEndOfParagraph,
11940        window: &mut Window,
11941        cx: &mut Context<Self>,
11942    ) {
11943        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11944            cx.propagate();
11945            return;
11946        }
11947        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11948        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11949            s.move_with(|map, selection| {
11950                selection.collapse_to(
11951                    movement::end_of_paragraph(map, selection.head(), 1),
11952                    SelectionGoal::None,
11953                )
11954            });
11955        })
11956    }
11957
11958    pub fn select_to_start_of_paragraph(
11959        &mut self,
11960        _: &SelectToStartOfParagraph,
11961        window: &mut Window,
11962        cx: &mut Context<Self>,
11963    ) {
11964        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11965            cx.propagate();
11966            return;
11967        }
11968        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11969        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11970            s.move_heads_with(|map, head, _| {
11971                (
11972                    movement::start_of_paragraph(map, head, 1),
11973                    SelectionGoal::None,
11974                )
11975            });
11976        })
11977    }
11978
11979    pub fn select_to_end_of_paragraph(
11980        &mut self,
11981        _: &SelectToEndOfParagraph,
11982        window: &mut Window,
11983        cx: &mut Context<Self>,
11984    ) {
11985        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11986            cx.propagate();
11987            return;
11988        }
11989        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11990        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11991            s.move_heads_with(|map, head, _| {
11992                (
11993                    movement::end_of_paragraph(map, head, 1),
11994                    SelectionGoal::None,
11995                )
11996            });
11997        })
11998    }
11999
12000    pub fn move_to_start_of_excerpt(
12001        &mut self,
12002        _: &MoveToStartOfExcerpt,
12003        window: &mut Window,
12004        cx: &mut Context<Self>,
12005    ) {
12006        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12007            cx.propagate();
12008            return;
12009        }
12010        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12011        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12012            s.move_with(|map, selection| {
12013                selection.collapse_to(
12014                    movement::start_of_excerpt(
12015                        map,
12016                        selection.head(),
12017                        workspace::searchable::Direction::Prev,
12018                    ),
12019                    SelectionGoal::None,
12020                )
12021            });
12022        })
12023    }
12024
12025    pub fn move_to_start_of_next_excerpt(
12026        &mut self,
12027        _: &MoveToStartOfNextExcerpt,
12028        window: &mut Window,
12029        cx: &mut Context<Self>,
12030    ) {
12031        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12032            cx.propagate();
12033            return;
12034        }
12035
12036        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12037            s.move_with(|map, selection| {
12038                selection.collapse_to(
12039                    movement::start_of_excerpt(
12040                        map,
12041                        selection.head(),
12042                        workspace::searchable::Direction::Next,
12043                    ),
12044                    SelectionGoal::None,
12045                )
12046            });
12047        })
12048    }
12049
12050    pub fn move_to_end_of_excerpt(
12051        &mut self,
12052        _: &MoveToEndOfExcerpt,
12053        window: &mut Window,
12054        cx: &mut Context<Self>,
12055    ) {
12056        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12057            cx.propagate();
12058            return;
12059        }
12060        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12061        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12062            s.move_with(|map, selection| {
12063                selection.collapse_to(
12064                    movement::end_of_excerpt(
12065                        map,
12066                        selection.head(),
12067                        workspace::searchable::Direction::Next,
12068                    ),
12069                    SelectionGoal::None,
12070                )
12071            });
12072        })
12073    }
12074
12075    pub fn move_to_end_of_previous_excerpt(
12076        &mut self,
12077        _: &MoveToEndOfPreviousExcerpt,
12078        window: &mut Window,
12079        cx: &mut Context<Self>,
12080    ) {
12081        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12082            cx.propagate();
12083            return;
12084        }
12085        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12086        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12087            s.move_with(|map, selection| {
12088                selection.collapse_to(
12089                    movement::end_of_excerpt(
12090                        map,
12091                        selection.head(),
12092                        workspace::searchable::Direction::Prev,
12093                    ),
12094                    SelectionGoal::None,
12095                )
12096            });
12097        })
12098    }
12099
12100    pub fn select_to_start_of_excerpt(
12101        &mut self,
12102        _: &SelectToStartOfExcerpt,
12103        window: &mut Window,
12104        cx: &mut Context<Self>,
12105    ) {
12106        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12107            cx.propagate();
12108            return;
12109        }
12110        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12111        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12112            s.move_heads_with(|map, head, _| {
12113                (
12114                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12115                    SelectionGoal::None,
12116                )
12117            });
12118        })
12119    }
12120
12121    pub fn select_to_start_of_next_excerpt(
12122        &mut self,
12123        _: &SelectToStartOfNextExcerpt,
12124        window: &mut Window,
12125        cx: &mut Context<Self>,
12126    ) {
12127        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12128            cx.propagate();
12129            return;
12130        }
12131        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12132        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12133            s.move_heads_with(|map, head, _| {
12134                (
12135                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12136                    SelectionGoal::None,
12137                )
12138            });
12139        })
12140    }
12141
12142    pub fn select_to_end_of_excerpt(
12143        &mut self,
12144        _: &SelectToEndOfExcerpt,
12145        window: &mut Window,
12146        cx: &mut Context<Self>,
12147    ) {
12148        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12149            cx.propagate();
12150            return;
12151        }
12152        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12153        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12154            s.move_heads_with(|map, head, _| {
12155                (
12156                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12157                    SelectionGoal::None,
12158                )
12159            });
12160        })
12161    }
12162
12163    pub fn select_to_end_of_previous_excerpt(
12164        &mut self,
12165        _: &SelectToEndOfPreviousExcerpt,
12166        window: &mut Window,
12167        cx: &mut Context<Self>,
12168    ) {
12169        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12170            cx.propagate();
12171            return;
12172        }
12173        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12174        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12175            s.move_heads_with(|map, head, _| {
12176                (
12177                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12178                    SelectionGoal::None,
12179                )
12180            });
12181        })
12182    }
12183
12184    pub fn move_to_beginning(
12185        &mut self,
12186        _: &MoveToBeginning,
12187        window: &mut Window,
12188        cx: &mut Context<Self>,
12189    ) {
12190        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12191            cx.propagate();
12192            return;
12193        }
12194        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12195        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12196            s.select_ranges(vec![0..0]);
12197        });
12198    }
12199
12200    pub fn select_to_beginning(
12201        &mut self,
12202        _: &SelectToBeginning,
12203        window: &mut Window,
12204        cx: &mut Context<Self>,
12205    ) {
12206        let mut selection = self.selections.last::<Point>(cx);
12207        selection.set_head(Point::zero(), SelectionGoal::None);
12208        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12209        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12210            s.select(vec![selection]);
12211        });
12212    }
12213
12214    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12215        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12216            cx.propagate();
12217            return;
12218        }
12219        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12220        let cursor = self.buffer.read(cx).read(cx).len();
12221        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12222            s.select_ranges(vec![cursor..cursor])
12223        });
12224    }
12225
12226    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12227        self.nav_history = nav_history;
12228    }
12229
12230    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12231        self.nav_history.as_ref()
12232    }
12233
12234    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12235        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12236    }
12237
12238    fn push_to_nav_history(
12239        &mut self,
12240        cursor_anchor: Anchor,
12241        new_position: Option<Point>,
12242        is_deactivate: bool,
12243        cx: &mut Context<Self>,
12244    ) {
12245        if let Some(nav_history) = self.nav_history.as_mut() {
12246            let buffer = self.buffer.read(cx).read(cx);
12247            let cursor_position = cursor_anchor.to_point(&buffer);
12248            let scroll_state = self.scroll_manager.anchor();
12249            let scroll_top_row = scroll_state.top_row(&buffer);
12250            drop(buffer);
12251
12252            if let Some(new_position) = new_position {
12253                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12254                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12255                    return;
12256                }
12257            }
12258
12259            nav_history.push(
12260                Some(NavigationData {
12261                    cursor_anchor,
12262                    cursor_position,
12263                    scroll_anchor: scroll_state,
12264                    scroll_top_row,
12265                }),
12266                cx,
12267            );
12268            cx.emit(EditorEvent::PushedToNavHistory {
12269                anchor: cursor_anchor,
12270                is_deactivate,
12271            })
12272        }
12273    }
12274
12275    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12276        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12277        let buffer = self.buffer.read(cx).snapshot(cx);
12278        let mut selection = self.selections.first::<usize>(cx);
12279        selection.set_head(buffer.len(), SelectionGoal::None);
12280        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12281            s.select(vec![selection]);
12282        });
12283    }
12284
12285    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12286        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12287        let end = self.buffer.read(cx).read(cx).len();
12288        self.change_selections(None, window, cx, |s| {
12289            s.select_ranges(vec![0..end]);
12290        });
12291    }
12292
12293    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12294        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12295        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12296        let mut selections = self.selections.all::<Point>(cx);
12297        let max_point = display_map.buffer_snapshot.max_point();
12298        for selection in &mut selections {
12299            let rows = selection.spanned_rows(true, &display_map);
12300            selection.start = Point::new(rows.start.0, 0);
12301            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12302            selection.reversed = false;
12303        }
12304        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12305            s.select(selections);
12306        });
12307    }
12308
12309    pub fn split_selection_into_lines(
12310        &mut self,
12311        _: &SplitSelectionIntoLines,
12312        window: &mut Window,
12313        cx: &mut Context<Self>,
12314    ) {
12315        let selections = self
12316            .selections
12317            .all::<Point>(cx)
12318            .into_iter()
12319            .map(|selection| selection.start..selection.end)
12320            .collect::<Vec<_>>();
12321        self.unfold_ranges(&selections, true, true, cx);
12322
12323        let mut new_selection_ranges = Vec::new();
12324        {
12325            let buffer = self.buffer.read(cx).read(cx);
12326            for selection in selections {
12327                for row in selection.start.row..selection.end.row {
12328                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12329                    new_selection_ranges.push(cursor..cursor);
12330                }
12331
12332                let is_multiline_selection = selection.start.row != selection.end.row;
12333                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12334                // so this action feels more ergonomic when paired with other selection operations
12335                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12336                if !should_skip_last {
12337                    new_selection_ranges.push(selection.end..selection.end);
12338                }
12339            }
12340        }
12341        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12342            s.select_ranges(new_selection_ranges);
12343        });
12344    }
12345
12346    pub fn add_selection_above(
12347        &mut self,
12348        _: &AddSelectionAbove,
12349        window: &mut Window,
12350        cx: &mut Context<Self>,
12351    ) {
12352        self.add_selection(true, window, cx);
12353    }
12354
12355    pub fn add_selection_below(
12356        &mut self,
12357        _: &AddSelectionBelow,
12358        window: &mut Window,
12359        cx: &mut Context<Self>,
12360    ) {
12361        self.add_selection(false, window, cx);
12362    }
12363
12364    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12365        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12366
12367        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12368        let mut selections = self.selections.all::<Point>(cx);
12369        let text_layout_details = self.text_layout_details(window);
12370        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12371            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12372            let range = oldest_selection.display_range(&display_map).sorted();
12373
12374            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12375            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12376            let positions = start_x.min(end_x)..start_x.max(end_x);
12377
12378            selections.clear();
12379            let mut stack = Vec::new();
12380            for row in range.start.row().0..=range.end.row().0 {
12381                if let Some(selection) = self.selections.build_columnar_selection(
12382                    &display_map,
12383                    DisplayRow(row),
12384                    &positions,
12385                    oldest_selection.reversed,
12386                    &text_layout_details,
12387                ) {
12388                    stack.push(selection.id);
12389                    selections.push(selection);
12390                }
12391            }
12392
12393            if above {
12394                stack.reverse();
12395            }
12396
12397            AddSelectionsState { above, stack }
12398        });
12399
12400        let last_added_selection = *state.stack.last().unwrap();
12401        let mut new_selections = Vec::new();
12402        if above == state.above {
12403            let end_row = if above {
12404                DisplayRow(0)
12405            } else {
12406                display_map.max_point().row()
12407            };
12408
12409            'outer: for selection in selections {
12410                if selection.id == last_added_selection {
12411                    let range = selection.display_range(&display_map).sorted();
12412                    debug_assert_eq!(range.start.row(), range.end.row());
12413                    let mut row = range.start.row();
12414                    let positions =
12415                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12416                            px(start)..px(end)
12417                        } else {
12418                            let start_x =
12419                                display_map.x_for_display_point(range.start, &text_layout_details);
12420                            let end_x =
12421                                display_map.x_for_display_point(range.end, &text_layout_details);
12422                            start_x.min(end_x)..start_x.max(end_x)
12423                        };
12424
12425                    while row != end_row {
12426                        if above {
12427                            row.0 -= 1;
12428                        } else {
12429                            row.0 += 1;
12430                        }
12431
12432                        if let Some(new_selection) = self.selections.build_columnar_selection(
12433                            &display_map,
12434                            row,
12435                            &positions,
12436                            selection.reversed,
12437                            &text_layout_details,
12438                        ) {
12439                            state.stack.push(new_selection.id);
12440                            if above {
12441                                new_selections.push(new_selection);
12442                                new_selections.push(selection);
12443                            } else {
12444                                new_selections.push(selection);
12445                                new_selections.push(new_selection);
12446                            }
12447
12448                            continue 'outer;
12449                        }
12450                    }
12451                }
12452
12453                new_selections.push(selection);
12454            }
12455        } else {
12456            new_selections = selections;
12457            new_selections.retain(|s| s.id != last_added_selection);
12458            state.stack.pop();
12459        }
12460
12461        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12462            s.select(new_selections);
12463        });
12464        if state.stack.len() > 1 {
12465            self.add_selections_state = Some(state);
12466        }
12467    }
12468
12469    fn select_match_ranges(
12470        &mut self,
12471        range: Range<usize>,
12472        reversed: bool,
12473        replace_newest: bool,
12474        auto_scroll: Option<Autoscroll>,
12475        window: &mut Window,
12476        cx: &mut Context<Editor>,
12477    ) {
12478        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12479        self.change_selections(auto_scroll, window, cx, |s| {
12480            if replace_newest {
12481                s.delete(s.newest_anchor().id);
12482            }
12483            if reversed {
12484                s.insert_range(range.end..range.start);
12485            } else {
12486                s.insert_range(range);
12487            }
12488        });
12489    }
12490
12491    pub fn select_next_match_internal(
12492        &mut self,
12493        display_map: &DisplaySnapshot,
12494        replace_newest: bool,
12495        autoscroll: Option<Autoscroll>,
12496        window: &mut Window,
12497        cx: &mut Context<Self>,
12498    ) -> Result<()> {
12499        let buffer = &display_map.buffer_snapshot;
12500        let mut selections = self.selections.all::<usize>(cx);
12501        if let Some(mut select_next_state) = self.select_next_state.take() {
12502            let query = &select_next_state.query;
12503            if !select_next_state.done {
12504                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12505                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12506                let mut next_selected_range = None;
12507
12508                let bytes_after_last_selection =
12509                    buffer.bytes_in_range(last_selection.end..buffer.len());
12510                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12511                let query_matches = query
12512                    .stream_find_iter(bytes_after_last_selection)
12513                    .map(|result| (last_selection.end, result))
12514                    .chain(
12515                        query
12516                            .stream_find_iter(bytes_before_first_selection)
12517                            .map(|result| (0, result)),
12518                    );
12519
12520                for (start_offset, query_match) in query_matches {
12521                    let query_match = query_match.unwrap(); // can only fail due to I/O
12522                    let offset_range =
12523                        start_offset + query_match.start()..start_offset + query_match.end();
12524                    let display_range = offset_range.start.to_display_point(display_map)
12525                        ..offset_range.end.to_display_point(display_map);
12526
12527                    if !select_next_state.wordwise
12528                        || (!movement::is_inside_word(display_map, display_range.start)
12529                            && !movement::is_inside_word(display_map, display_range.end))
12530                    {
12531                        // TODO: This is n^2, because we might check all the selections
12532                        if !selections
12533                            .iter()
12534                            .any(|selection| selection.range().overlaps(&offset_range))
12535                        {
12536                            next_selected_range = Some(offset_range);
12537                            break;
12538                        }
12539                    }
12540                }
12541
12542                if let Some(next_selected_range) = next_selected_range {
12543                    self.select_match_ranges(
12544                        next_selected_range,
12545                        last_selection.reversed,
12546                        replace_newest,
12547                        autoscroll,
12548                        window,
12549                        cx,
12550                    );
12551                } else {
12552                    select_next_state.done = true;
12553                }
12554            }
12555
12556            self.select_next_state = Some(select_next_state);
12557        } else {
12558            let mut only_carets = true;
12559            let mut same_text_selected = true;
12560            let mut selected_text = None;
12561
12562            let mut selections_iter = selections.iter().peekable();
12563            while let Some(selection) = selections_iter.next() {
12564                if selection.start != selection.end {
12565                    only_carets = false;
12566                }
12567
12568                if same_text_selected {
12569                    if selected_text.is_none() {
12570                        selected_text =
12571                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12572                    }
12573
12574                    if let Some(next_selection) = selections_iter.peek() {
12575                        if next_selection.range().len() == selection.range().len() {
12576                            let next_selected_text = buffer
12577                                .text_for_range(next_selection.range())
12578                                .collect::<String>();
12579                            if Some(next_selected_text) != selected_text {
12580                                same_text_selected = false;
12581                                selected_text = None;
12582                            }
12583                        } else {
12584                            same_text_selected = false;
12585                            selected_text = None;
12586                        }
12587                    }
12588                }
12589            }
12590
12591            if only_carets {
12592                for selection in &mut selections {
12593                    let word_range = movement::surrounding_word(
12594                        display_map,
12595                        selection.start.to_display_point(display_map),
12596                    );
12597                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12598                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12599                    selection.goal = SelectionGoal::None;
12600                    selection.reversed = false;
12601                    self.select_match_ranges(
12602                        selection.start..selection.end,
12603                        selection.reversed,
12604                        replace_newest,
12605                        autoscroll,
12606                        window,
12607                        cx,
12608                    );
12609                }
12610
12611                if selections.len() == 1 {
12612                    let selection = selections
12613                        .last()
12614                        .expect("ensured that there's only one selection");
12615                    let query = buffer
12616                        .text_for_range(selection.start..selection.end)
12617                        .collect::<String>();
12618                    let is_empty = query.is_empty();
12619                    let select_state = SelectNextState {
12620                        query: AhoCorasick::new(&[query])?,
12621                        wordwise: true,
12622                        done: is_empty,
12623                    };
12624                    self.select_next_state = Some(select_state);
12625                } else {
12626                    self.select_next_state = None;
12627                }
12628            } else if let Some(selected_text) = selected_text {
12629                self.select_next_state = Some(SelectNextState {
12630                    query: AhoCorasick::new(&[selected_text])?,
12631                    wordwise: false,
12632                    done: false,
12633                });
12634                self.select_next_match_internal(
12635                    display_map,
12636                    replace_newest,
12637                    autoscroll,
12638                    window,
12639                    cx,
12640                )?;
12641            }
12642        }
12643        Ok(())
12644    }
12645
12646    pub fn select_all_matches(
12647        &mut self,
12648        _action: &SelectAllMatches,
12649        window: &mut Window,
12650        cx: &mut Context<Self>,
12651    ) -> Result<()> {
12652        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12653
12654        self.push_to_selection_history();
12655        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12656
12657        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12658        let Some(select_next_state) = self.select_next_state.as_mut() else {
12659            return Ok(());
12660        };
12661        if select_next_state.done {
12662            return Ok(());
12663        }
12664
12665        let mut new_selections = Vec::new();
12666
12667        let reversed = self.selections.oldest::<usize>(cx).reversed;
12668        let buffer = &display_map.buffer_snapshot;
12669        let query_matches = select_next_state
12670            .query
12671            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12672
12673        for query_match in query_matches.into_iter() {
12674            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12675            let offset_range = if reversed {
12676                query_match.end()..query_match.start()
12677            } else {
12678                query_match.start()..query_match.end()
12679            };
12680            let display_range = offset_range.start.to_display_point(&display_map)
12681                ..offset_range.end.to_display_point(&display_map);
12682
12683            if !select_next_state.wordwise
12684                || (!movement::is_inside_word(&display_map, display_range.start)
12685                    && !movement::is_inside_word(&display_map, display_range.end))
12686            {
12687                new_selections.push(offset_range.start..offset_range.end);
12688            }
12689        }
12690
12691        select_next_state.done = true;
12692        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12693        self.change_selections(None, window, cx, |selections| {
12694            selections.select_ranges(new_selections)
12695        });
12696
12697        Ok(())
12698    }
12699
12700    pub fn select_next(
12701        &mut self,
12702        action: &SelectNext,
12703        window: &mut Window,
12704        cx: &mut Context<Self>,
12705    ) -> Result<()> {
12706        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12707        self.push_to_selection_history();
12708        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12709        self.select_next_match_internal(
12710            &display_map,
12711            action.replace_newest,
12712            Some(Autoscroll::newest()),
12713            window,
12714            cx,
12715        )?;
12716        Ok(())
12717    }
12718
12719    pub fn select_previous(
12720        &mut self,
12721        action: &SelectPrevious,
12722        window: &mut Window,
12723        cx: &mut Context<Self>,
12724    ) -> Result<()> {
12725        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12726        self.push_to_selection_history();
12727        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12728        let buffer = &display_map.buffer_snapshot;
12729        let mut selections = self.selections.all::<usize>(cx);
12730        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12731            let query = &select_prev_state.query;
12732            if !select_prev_state.done {
12733                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12734                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12735                let mut next_selected_range = None;
12736                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12737                let bytes_before_last_selection =
12738                    buffer.reversed_bytes_in_range(0..last_selection.start);
12739                let bytes_after_first_selection =
12740                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12741                let query_matches = query
12742                    .stream_find_iter(bytes_before_last_selection)
12743                    .map(|result| (last_selection.start, result))
12744                    .chain(
12745                        query
12746                            .stream_find_iter(bytes_after_first_selection)
12747                            .map(|result| (buffer.len(), result)),
12748                    );
12749                for (end_offset, query_match) in query_matches {
12750                    let query_match = query_match.unwrap(); // can only fail due to I/O
12751                    let offset_range =
12752                        end_offset - query_match.end()..end_offset - query_match.start();
12753                    let display_range = offset_range.start.to_display_point(&display_map)
12754                        ..offset_range.end.to_display_point(&display_map);
12755
12756                    if !select_prev_state.wordwise
12757                        || (!movement::is_inside_word(&display_map, display_range.start)
12758                            && !movement::is_inside_word(&display_map, display_range.end))
12759                    {
12760                        next_selected_range = Some(offset_range);
12761                        break;
12762                    }
12763                }
12764
12765                if let Some(next_selected_range) = next_selected_range {
12766                    self.select_match_ranges(
12767                        next_selected_range,
12768                        last_selection.reversed,
12769                        action.replace_newest,
12770                        Some(Autoscroll::newest()),
12771                        window,
12772                        cx,
12773                    );
12774                } else {
12775                    select_prev_state.done = true;
12776                }
12777            }
12778
12779            self.select_prev_state = Some(select_prev_state);
12780        } else {
12781            let mut only_carets = true;
12782            let mut same_text_selected = true;
12783            let mut selected_text = None;
12784
12785            let mut selections_iter = selections.iter().peekable();
12786            while let Some(selection) = selections_iter.next() {
12787                if selection.start != selection.end {
12788                    only_carets = false;
12789                }
12790
12791                if same_text_selected {
12792                    if selected_text.is_none() {
12793                        selected_text =
12794                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12795                    }
12796
12797                    if let Some(next_selection) = selections_iter.peek() {
12798                        if next_selection.range().len() == selection.range().len() {
12799                            let next_selected_text = buffer
12800                                .text_for_range(next_selection.range())
12801                                .collect::<String>();
12802                            if Some(next_selected_text) != selected_text {
12803                                same_text_selected = false;
12804                                selected_text = None;
12805                            }
12806                        } else {
12807                            same_text_selected = false;
12808                            selected_text = None;
12809                        }
12810                    }
12811                }
12812            }
12813
12814            if only_carets {
12815                for selection in &mut selections {
12816                    let word_range = movement::surrounding_word(
12817                        &display_map,
12818                        selection.start.to_display_point(&display_map),
12819                    );
12820                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12821                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12822                    selection.goal = SelectionGoal::None;
12823                    selection.reversed = false;
12824                    self.select_match_ranges(
12825                        selection.start..selection.end,
12826                        selection.reversed,
12827                        action.replace_newest,
12828                        Some(Autoscroll::newest()),
12829                        window,
12830                        cx,
12831                    );
12832                }
12833                if selections.len() == 1 {
12834                    let selection = selections
12835                        .last()
12836                        .expect("ensured that there's only one selection");
12837                    let query = buffer
12838                        .text_for_range(selection.start..selection.end)
12839                        .collect::<String>();
12840                    let is_empty = query.is_empty();
12841                    let select_state = SelectNextState {
12842                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12843                        wordwise: true,
12844                        done: is_empty,
12845                    };
12846                    self.select_prev_state = Some(select_state);
12847                } else {
12848                    self.select_prev_state = None;
12849                }
12850            } else if let Some(selected_text) = selected_text {
12851                self.select_prev_state = Some(SelectNextState {
12852                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12853                    wordwise: false,
12854                    done: false,
12855                });
12856                self.select_previous(action, window, cx)?;
12857            }
12858        }
12859        Ok(())
12860    }
12861
12862    pub fn find_next_match(
12863        &mut self,
12864        _: &FindNextMatch,
12865        window: &mut Window,
12866        cx: &mut Context<Self>,
12867    ) -> Result<()> {
12868        let selections = self.selections.disjoint_anchors();
12869        match selections.first() {
12870            Some(first) if selections.len() >= 2 => {
12871                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12872                    s.select_ranges([first.range()]);
12873                });
12874            }
12875            _ => self.select_next(
12876                &SelectNext {
12877                    replace_newest: true,
12878                },
12879                window,
12880                cx,
12881            )?,
12882        }
12883        Ok(())
12884    }
12885
12886    pub fn find_previous_match(
12887        &mut self,
12888        _: &FindPreviousMatch,
12889        window: &mut Window,
12890        cx: &mut Context<Self>,
12891    ) -> Result<()> {
12892        let selections = self.selections.disjoint_anchors();
12893        match selections.last() {
12894            Some(last) if selections.len() >= 2 => {
12895                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12896                    s.select_ranges([last.range()]);
12897                });
12898            }
12899            _ => self.select_previous(
12900                &SelectPrevious {
12901                    replace_newest: true,
12902                },
12903                window,
12904                cx,
12905            )?,
12906        }
12907        Ok(())
12908    }
12909
12910    pub fn toggle_comments(
12911        &mut self,
12912        action: &ToggleComments,
12913        window: &mut Window,
12914        cx: &mut Context<Self>,
12915    ) {
12916        if self.read_only(cx) {
12917            return;
12918        }
12919        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12920        let text_layout_details = &self.text_layout_details(window);
12921        self.transact(window, cx, |this, window, cx| {
12922            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12923            let mut edits = Vec::new();
12924            let mut selection_edit_ranges = Vec::new();
12925            let mut last_toggled_row = None;
12926            let snapshot = this.buffer.read(cx).read(cx);
12927            let empty_str: Arc<str> = Arc::default();
12928            let mut suffixes_inserted = Vec::new();
12929            let ignore_indent = action.ignore_indent;
12930
12931            fn comment_prefix_range(
12932                snapshot: &MultiBufferSnapshot,
12933                row: MultiBufferRow,
12934                comment_prefix: &str,
12935                comment_prefix_whitespace: &str,
12936                ignore_indent: bool,
12937            ) -> Range<Point> {
12938                let indent_size = if ignore_indent {
12939                    0
12940                } else {
12941                    snapshot.indent_size_for_line(row).len
12942                };
12943
12944                let start = Point::new(row.0, indent_size);
12945
12946                let mut line_bytes = snapshot
12947                    .bytes_in_range(start..snapshot.max_point())
12948                    .flatten()
12949                    .copied();
12950
12951                // If this line currently begins with the line comment prefix, then record
12952                // the range containing the prefix.
12953                if line_bytes
12954                    .by_ref()
12955                    .take(comment_prefix.len())
12956                    .eq(comment_prefix.bytes())
12957                {
12958                    // Include any whitespace that matches the comment prefix.
12959                    let matching_whitespace_len = line_bytes
12960                        .zip(comment_prefix_whitespace.bytes())
12961                        .take_while(|(a, b)| a == b)
12962                        .count() as u32;
12963                    let end = Point::new(
12964                        start.row,
12965                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12966                    );
12967                    start..end
12968                } else {
12969                    start..start
12970                }
12971            }
12972
12973            fn comment_suffix_range(
12974                snapshot: &MultiBufferSnapshot,
12975                row: MultiBufferRow,
12976                comment_suffix: &str,
12977                comment_suffix_has_leading_space: bool,
12978            ) -> Range<Point> {
12979                let end = Point::new(row.0, snapshot.line_len(row));
12980                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12981
12982                let mut line_end_bytes = snapshot
12983                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12984                    .flatten()
12985                    .copied();
12986
12987                let leading_space_len = if suffix_start_column > 0
12988                    && line_end_bytes.next() == Some(b' ')
12989                    && comment_suffix_has_leading_space
12990                {
12991                    1
12992                } else {
12993                    0
12994                };
12995
12996                // If this line currently begins with the line comment prefix, then record
12997                // the range containing the prefix.
12998                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12999                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13000                    start..end
13001                } else {
13002                    end..end
13003                }
13004            }
13005
13006            // TODO: Handle selections that cross excerpts
13007            for selection in &mut selections {
13008                let start_column = snapshot
13009                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13010                    .len;
13011                let language = if let Some(language) =
13012                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13013                {
13014                    language
13015                } else {
13016                    continue;
13017                };
13018
13019                selection_edit_ranges.clear();
13020
13021                // If multiple selections contain a given row, avoid processing that
13022                // row more than once.
13023                let mut start_row = MultiBufferRow(selection.start.row);
13024                if last_toggled_row == Some(start_row) {
13025                    start_row = start_row.next_row();
13026                }
13027                let end_row =
13028                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13029                        MultiBufferRow(selection.end.row - 1)
13030                    } else {
13031                        MultiBufferRow(selection.end.row)
13032                    };
13033                last_toggled_row = Some(end_row);
13034
13035                if start_row > end_row {
13036                    continue;
13037                }
13038
13039                // If the language has line comments, toggle those.
13040                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13041
13042                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13043                if ignore_indent {
13044                    full_comment_prefixes = full_comment_prefixes
13045                        .into_iter()
13046                        .map(|s| Arc::from(s.trim_end()))
13047                        .collect();
13048                }
13049
13050                if !full_comment_prefixes.is_empty() {
13051                    let first_prefix = full_comment_prefixes
13052                        .first()
13053                        .expect("prefixes is non-empty");
13054                    let prefix_trimmed_lengths = full_comment_prefixes
13055                        .iter()
13056                        .map(|p| p.trim_end_matches(' ').len())
13057                        .collect::<SmallVec<[usize; 4]>>();
13058
13059                    let mut all_selection_lines_are_comments = true;
13060
13061                    for row in start_row.0..=end_row.0 {
13062                        let row = MultiBufferRow(row);
13063                        if start_row < end_row && snapshot.is_line_blank(row) {
13064                            continue;
13065                        }
13066
13067                        let prefix_range = full_comment_prefixes
13068                            .iter()
13069                            .zip(prefix_trimmed_lengths.iter().copied())
13070                            .map(|(prefix, trimmed_prefix_len)| {
13071                                comment_prefix_range(
13072                                    snapshot.deref(),
13073                                    row,
13074                                    &prefix[..trimmed_prefix_len],
13075                                    &prefix[trimmed_prefix_len..],
13076                                    ignore_indent,
13077                                )
13078                            })
13079                            .max_by_key(|range| range.end.column - range.start.column)
13080                            .expect("prefixes is non-empty");
13081
13082                        if prefix_range.is_empty() {
13083                            all_selection_lines_are_comments = false;
13084                        }
13085
13086                        selection_edit_ranges.push(prefix_range);
13087                    }
13088
13089                    if all_selection_lines_are_comments {
13090                        edits.extend(
13091                            selection_edit_ranges
13092                                .iter()
13093                                .cloned()
13094                                .map(|range| (range, empty_str.clone())),
13095                        );
13096                    } else {
13097                        let min_column = selection_edit_ranges
13098                            .iter()
13099                            .map(|range| range.start.column)
13100                            .min()
13101                            .unwrap_or(0);
13102                        edits.extend(selection_edit_ranges.iter().map(|range| {
13103                            let position = Point::new(range.start.row, min_column);
13104                            (position..position, first_prefix.clone())
13105                        }));
13106                    }
13107                } else if let Some((full_comment_prefix, comment_suffix)) =
13108                    language.block_comment_delimiters()
13109                {
13110                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13111                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13112                    let prefix_range = comment_prefix_range(
13113                        snapshot.deref(),
13114                        start_row,
13115                        comment_prefix,
13116                        comment_prefix_whitespace,
13117                        ignore_indent,
13118                    );
13119                    let suffix_range = comment_suffix_range(
13120                        snapshot.deref(),
13121                        end_row,
13122                        comment_suffix.trim_start_matches(' '),
13123                        comment_suffix.starts_with(' '),
13124                    );
13125
13126                    if prefix_range.is_empty() || suffix_range.is_empty() {
13127                        edits.push((
13128                            prefix_range.start..prefix_range.start,
13129                            full_comment_prefix.clone(),
13130                        ));
13131                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13132                        suffixes_inserted.push((end_row, comment_suffix.len()));
13133                    } else {
13134                        edits.push((prefix_range, empty_str.clone()));
13135                        edits.push((suffix_range, empty_str.clone()));
13136                    }
13137                } else {
13138                    continue;
13139                }
13140            }
13141
13142            drop(snapshot);
13143            this.buffer.update(cx, |buffer, cx| {
13144                buffer.edit(edits, None, cx);
13145            });
13146
13147            // Adjust selections so that they end before any comment suffixes that
13148            // were inserted.
13149            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13150            let mut selections = this.selections.all::<Point>(cx);
13151            let snapshot = this.buffer.read(cx).read(cx);
13152            for selection in &mut selections {
13153                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13154                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13155                        Ordering::Less => {
13156                            suffixes_inserted.next();
13157                            continue;
13158                        }
13159                        Ordering::Greater => break,
13160                        Ordering::Equal => {
13161                            if selection.end.column == snapshot.line_len(row) {
13162                                if selection.is_empty() {
13163                                    selection.start.column -= suffix_len as u32;
13164                                }
13165                                selection.end.column -= suffix_len as u32;
13166                            }
13167                            break;
13168                        }
13169                    }
13170                }
13171            }
13172
13173            drop(snapshot);
13174            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13175                s.select(selections)
13176            });
13177
13178            let selections = this.selections.all::<Point>(cx);
13179            let selections_on_single_row = selections.windows(2).all(|selections| {
13180                selections[0].start.row == selections[1].start.row
13181                    && selections[0].end.row == selections[1].end.row
13182                    && selections[0].start.row == selections[0].end.row
13183            });
13184            let selections_selecting = selections
13185                .iter()
13186                .any(|selection| selection.start != selection.end);
13187            let advance_downwards = action.advance_downwards
13188                && selections_on_single_row
13189                && !selections_selecting
13190                && !matches!(this.mode, EditorMode::SingleLine { .. });
13191
13192            if advance_downwards {
13193                let snapshot = this.buffer.read(cx).snapshot(cx);
13194
13195                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13196                    s.move_cursors_with(|display_snapshot, display_point, _| {
13197                        let mut point = display_point.to_point(display_snapshot);
13198                        point.row += 1;
13199                        point = snapshot.clip_point(point, Bias::Left);
13200                        let display_point = point.to_display_point(display_snapshot);
13201                        let goal = SelectionGoal::HorizontalPosition(
13202                            display_snapshot
13203                                .x_for_display_point(display_point, text_layout_details)
13204                                .into(),
13205                        );
13206                        (display_point, goal)
13207                    })
13208                });
13209            }
13210        });
13211    }
13212
13213    pub fn select_enclosing_symbol(
13214        &mut self,
13215        _: &SelectEnclosingSymbol,
13216        window: &mut Window,
13217        cx: &mut Context<Self>,
13218    ) {
13219        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13220
13221        let buffer = self.buffer.read(cx).snapshot(cx);
13222        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13223
13224        fn update_selection(
13225            selection: &Selection<usize>,
13226            buffer_snap: &MultiBufferSnapshot,
13227        ) -> Option<Selection<usize>> {
13228            let cursor = selection.head();
13229            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13230            for symbol in symbols.iter().rev() {
13231                let start = symbol.range.start.to_offset(buffer_snap);
13232                let end = symbol.range.end.to_offset(buffer_snap);
13233                let new_range = start..end;
13234                if start < selection.start || end > selection.end {
13235                    return Some(Selection {
13236                        id: selection.id,
13237                        start: new_range.start,
13238                        end: new_range.end,
13239                        goal: SelectionGoal::None,
13240                        reversed: selection.reversed,
13241                    });
13242                }
13243            }
13244            None
13245        }
13246
13247        let mut selected_larger_symbol = false;
13248        let new_selections = old_selections
13249            .iter()
13250            .map(|selection| match update_selection(selection, &buffer) {
13251                Some(new_selection) => {
13252                    if new_selection.range() != selection.range() {
13253                        selected_larger_symbol = true;
13254                    }
13255                    new_selection
13256                }
13257                None => selection.clone(),
13258            })
13259            .collect::<Vec<_>>();
13260
13261        if selected_larger_symbol {
13262            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13263                s.select(new_selections);
13264            });
13265        }
13266    }
13267
13268    pub fn select_larger_syntax_node(
13269        &mut self,
13270        _: &SelectLargerSyntaxNode,
13271        window: &mut Window,
13272        cx: &mut Context<Self>,
13273    ) {
13274        let Some(visible_row_count) = self.visible_row_count() else {
13275            return;
13276        };
13277        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13278        if old_selections.is_empty() {
13279            return;
13280        }
13281
13282        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13283
13284        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13285        let buffer = self.buffer.read(cx).snapshot(cx);
13286
13287        let mut selected_larger_node = false;
13288        let mut new_selections = old_selections
13289            .iter()
13290            .map(|selection| {
13291                let old_range = selection.start..selection.end;
13292
13293                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13294                    // manually select word at selection
13295                    if ["string_content", "inline"].contains(&node.kind()) {
13296                        let word_range = {
13297                            let display_point = buffer
13298                                .offset_to_point(old_range.start)
13299                                .to_display_point(&display_map);
13300                            let Range { start, end } =
13301                                movement::surrounding_word(&display_map, display_point);
13302                            start.to_point(&display_map).to_offset(&buffer)
13303                                ..end.to_point(&display_map).to_offset(&buffer)
13304                        };
13305                        // ignore if word is already selected
13306                        if !word_range.is_empty() && old_range != word_range {
13307                            let last_word_range = {
13308                                let display_point = buffer
13309                                    .offset_to_point(old_range.end)
13310                                    .to_display_point(&display_map);
13311                                let Range { start, end } =
13312                                    movement::surrounding_word(&display_map, display_point);
13313                                start.to_point(&display_map).to_offset(&buffer)
13314                                    ..end.to_point(&display_map).to_offset(&buffer)
13315                            };
13316                            // only select word if start and end point belongs to same word
13317                            if word_range == last_word_range {
13318                                selected_larger_node = true;
13319                                return Selection {
13320                                    id: selection.id,
13321                                    start: word_range.start,
13322                                    end: word_range.end,
13323                                    goal: SelectionGoal::None,
13324                                    reversed: selection.reversed,
13325                                };
13326                            }
13327                        }
13328                    }
13329                }
13330
13331                let mut new_range = old_range.clone();
13332                while let Some((_node, containing_range)) =
13333                    buffer.syntax_ancestor(new_range.clone())
13334                {
13335                    new_range = match containing_range {
13336                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13337                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13338                    };
13339                    if !display_map.intersects_fold(new_range.start)
13340                        && !display_map.intersects_fold(new_range.end)
13341                    {
13342                        break;
13343                    }
13344                }
13345
13346                selected_larger_node |= new_range != old_range;
13347                Selection {
13348                    id: selection.id,
13349                    start: new_range.start,
13350                    end: new_range.end,
13351                    goal: SelectionGoal::None,
13352                    reversed: selection.reversed,
13353                }
13354            })
13355            .collect::<Vec<_>>();
13356
13357        if !selected_larger_node {
13358            return; // don't put this call in the history
13359        }
13360
13361        // scroll based on transformation done to the last selection created by the user
13362        let (last_old, last_new) = old_selections
13363            .last()
13364            .zip(new_selections.last().cloned())
13365            .expect("old_selections isn't empty");
13366
13367        // revert selection
13368        let is_selection_reversed = {
13369            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13370            new_selections.last_mut().expect("checked above").reversed =
13371                should_newest_selection_be_reversed;
13372            should_newest_selection_be_reversed
13373        };
13374
13375        if selected_larger_node {
13376            self.select_syntax_node_history.disable_clearing = true;
13377            self.change_selections(None, window, cx, |s| {
13378                s.select(new_selections.clone());
13379            });
13380            self.select_syntax_node_history.disable_clearing = false;
13381        }
13382
13383        let start_row = last_new.start.to_display_point(&display_map).row().0;
13384        let end_row = last_new.end.to_display_point(&display_map).row().0;
13385        let selection_height = end_row - start_row + 1;
13386        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13387
13388        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13389        let scroll_behavior = if fits_on_the_screen {
13390            self.request_autoscroll(Autoscroll::fit(), cx);
13391            SelectSyntaxNodeScrollBehavior::FitSelection
13392        } else if is_selection_reversed {
13393            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13394            SelectSyntaxNodeScrollBehavior::CursorTop
13395        } else {
13396            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13397            SelectSyntaxNodeScrollBehavior::CursorBottom
13398        };
13399
13400        self.select_syntax_node_history.push((
13401            old_selections,
13402            scroll_behavior,
13403            is_selection_reversed,
13404        ));
13405    }
13406
13407    pub fn select_smaller_syntax_node(
13408        &mut self,
13409        _: &SelectSmallerSyntaxNode,
13410        window: &mut Window,
13411        cx: &mut Context<Self>,
13412    ) {
13413        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13414
13415        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13416            self.select_syntax_node_history.pop()
13417        {
13418            if let Some(selection) = selections.last_mut() {
13419                selection.reversed = is_selection_reversed;
13420            }
13421
13422            self.select_syntax_node_history.disable_clearing = true;
13423            self.change_selections(None, window, cx, |s| {
13424                s.select(selections.to_vec());
13425            });
13426            self.select_syntax_node_history.disable_clearing = false;
13427
13428            match scroll_behavior {
13429                SelectSyntaxNodeScrollBehavior::CursorTop => {
13430                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13431                }
13432                SelectSyntaxNodeScrollBehavior::FitSelection => {
13433                    self.request_autoscroll(Autoscroll::fit(), cx);
13434                }
13435                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13436                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13437                }
13438            }
13439        }
13440    }
13441
13442    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13443        if !EditorSettings::get_global(cx).gutter.runnables {
13444            self.clear_tasks();
13445            return Task::ready(());
13446        }
13447        let project = self.project.as_ref().map(Entity::downgrade);
13448        let task_sources = self.lsp_task_sources(cx);
13449        cx.spawn_in(window, async move |editor, cx| {
13450            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13451            let Some(project) = project.and_then(|p| p.upgrade()) else {
13452                return;
13453            };
13454            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13455                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13456            }) else {
13457                return;
13458            };
13459
13460            let hide_runnables = project
13461                .update(cx, |project, cx| {
13462                    // Do not display any test indicators in non-dev server remote projects.
13463                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13464                })
13465                .unwrap_or(true);
13466            if hide_runnables {
13467                return;
13468            }
13469            let new_rows =
13470                cx.background_spawn({
13471                    let snapshot = display_snapshot.clone();
13472                    async move {
13473                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13474                    }
13475                })
13476                    .await;
13477            let Ok(lsp_tasks) =
13478                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13479            else {
13480                return;
13481            };
13482            let lsp_tasks = lsp_tasks.await;
13483
13484            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13485                lsp_tasks
13486                    .into_iter()
13487                    .flat_map(|(kind, tasks)| {
13488                        tasks.into_iter().filter_map(move |(location, task)| {
13489                            Some((kind.clone(), location?, task))
13490                        })
13491                    })
13492                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13493                        let buffer = location.target.buffer;
13494                        let buffer_snapshot = buffer.read(cx).snapshot();
13495                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13496                            |(excerpt_id, snapshot, _)| {
13497                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13498                                    display_snapshot
13499                                        .buffer_snapshot
13500                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13501                                } else {
13502                                    None
13503                                }
13504                            },
13505                        );
13506                        if let Some(offset) = offset {
13507                            let task_buffer_range =
13508                                location.target.range.to_point(&buffer_snapshot);
13509                            let context_buffer_range =
13510                                task_buffer_range.to_offset(&buffer_snapshot);
13511                            let context_range = BufferOffset(context_buffer_range.start)
13512                                ..BufferOffset(context_buffer_range.end);
13513
13514                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13515                                .or_insert_with(|| RunnableTasks {
13516                                    templates: Vec::new(),
13517                                    offset,
13518                                    column: task_buffer_range.start.column,
13519                                    extra_variables: HashMap::default(),
13520                                    context_range,
13521                                })
13522                                .templates
13523                                .push((kind, task.original_task().clone()));
13524                        }
13525
13526                        acc
13527                    })
13528            }) else {
13529                return;
13530            };
13531
13532            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13533            editor
13534                .update(cx, |editor, _| {
13535                    editor.clear_tasks();
13536                    for (key, mut value) in rows {
13537                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13538                            value.templates.extend(lsp_tasks.templates);
13539                        }
13540
13541                        editor.insert_tasks(key, value);
13542                    }
13543                    for (key, value) in lsp_tasks_by_rows {
13544                        editor.insert_tasks(key, value);
13545                    }
13546                })
13547                .ok();
13548        })
13549    }
13550    fn fetch_runnable_ranges(
13551        snapshot: &DisplaySnapshot,
13552        range: Range<Anchor>,
13553    ) -> Vec<language::RunnableRange> {
13554        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13555    }
13556
13557    fn runnable_rows(
13558        project: Entity<Project>,
13559        snapshot: DisplaySnapshot,
13560        runnable_ranges: Vec<RunnableRange>,
13561        mut cx: AsyncWindowContext,
13562    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13563        runnable_ranges
13564            .into_iter()
13565            .filter_map(|mut runnable| {
13566                let tasks = cx
13567                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13568                    .ok()?;
13569                if tasks.is_empty() {
13570                    return None;
13571                }
13572
13573                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13574
13575                let row = snapshot
13576                    .buffer_snapshot
13577                    .buffer_line_for_row(MultiBufferRow(point.row))?
13578                    .1
13579                    .start
13580                    .row;
13581
13582                let context_range =
13583                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13584                Some((
13585                    (runnable.buffer_id, row),
13586                    RunnableTasks {
13587                        templates: tasks,
13588                        offset: snapshot
13589                            .buffer_snapshot
13590                            .anchor_before(runnable.run_range.start),
13591                        context_range,
13592                        column: point.column,
13593                        extra_variables: runnable.extra_captures,
13594                    },
13595                ))
13596            })
13597            .collect()
13598    }
13599
13600    fn templates_with_tags(
13601        project: &Entity<Project>,
13602        runnable: &mut Runnable,
13603        cx: &mut App,
13604    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13605        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13606            let (worktree_id, file) = project
13607                .buffer_for_id(runnable.buffer, cx)
13608                .and_then(|buffer| buffer.read(cx).file())
13609                .map(|file| (file.worktree_id(cx), file.clone()))
13610                .unzip();
13611
13612            (
13613                project.task_store().read(cx).task_inventory().cloned(),
13614                worktree_id,
13615                file,
13616            )
13617        });
13618
13619        let mut templates_with_tags = mem::take(&mut runnable.tags)
13620            .into_iter()
13621            .flat_map(|RunnableTag(tag)| {
13622                inventory
13623                    .as_ref()
13624                    .into_iter()
13625                    .flat_map(|inventory| {
13626                        inventory.read(cx).list_tasks(
13627                            file.clone(),
13628                            Some(runnable.language.clone()),
13629                            worktree_id,
13630                            cx,
13631                        )
13632                    })
13633                    .filter(move |(_, template)| {
13634                        template.tags.iter().any(|source_tag| source_tag == &tag)
13635                    })
13636            })
13637            .sorted_by_key(|(kind, _)| kind.to_owned())
13638            .collect::<Vec<_>>();
13639        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13640            // Strongest source wins; if we have worktree tag binding, prefer that to
13641            // global and language bindings;
13642            // if we have a global binding, prefer that to language binding.
13643            let first_mismatch = templates_with_tags
13644                .iter()
13645                .position(|(tag_source, _)| tag_source != leading_tag_source);
13646            if let Some(index) = first_mismatch {
13647                templates_with_tags.truncate(index);
13648            }
13649        }
13650
13651        templates_with_tags
13652    }
13653
13654    pub fn move_to_enclosing_bracket(
13655        &mut self,
13656        _: &MoveToEnclosingBracket,
13657        window: &mut Window,
13658        cx: &mut Context<Self>,
13659    ) {
13660        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13661        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13662            s.move_offsets_with(|snapshot, selection| {
13663                let Some(enclosing_bracket_ranges) =
13664                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13665                else {
13666                    return;
13667                };
13668
13669                let mut best_length = usize::MAX;
13670                let mut best_inside = false;
13671                let mut best_in_bracket_range = false;
13672                let mut best_destination = None;
13673                for (open, close) in enclosing_bracket_ranges {
13674                    let close = close.to_inclusive();
13675                    let length = close.end() - open.start;
13676                    let inside = selection.start >= open.end && selection.end <= *close.start();
13677                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13678                        || close.contains(&selection.head());
13679
13680                    // If best is next to a bracket and current isn't, skip
13681                    if !in_bracket_range && best_in_bracket_range {
13682                        continue;
13683                    }
13684
13685                    // Prefer smaller lengths unless best is inside and current isn't
13686                    if length > best_length && (best_inside || !inside) {
13687                        continue;
13688                    }
13689
13690                    best_length = length;
13691                    best_inside = inside;
13692                    best_in_bracket_range = in_bracket_range;
13693                    best_destination = Some(
13694                        if close.contains(&selection.start) && close.contains(&selection.end) {
13695                            if inside { open.end } else { open.start }
13696                        } else if inside {
13697                            *close.start()
13698                        } else {
13699                            *close.end()
13700                        },
13701                    );
13702                }
13703
13704                if let Some(destination) = best_destination {
13705                    selection.collapse_to(destination, SelectionGoal::None);
13706                }
13707            })
13708        });
13709    }
13710
13711    pub fn undo_selection(
13712        &mut self,
13713        _: &UndoSelection,
13714        window: &mut Window,
13715        cx: &mut Context<Self>,
13716    ) {
13717        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13718        self.end_selection(window, cx);
13719        self.selection_history.mode = SelectionHistoryMode::Undoing;
13720        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13721            self.change_selections(None, window, cx, |s| {
13722                s.select_anchors(entry.selections.to_vec())
13723            });
13724            self.select_next_state = entry.select_next_state;
13725            self.select_prev_state = entry.select_prev_state;
13726            self.add_selections_state = entry.add_selections_state;
13727            self.request_autoscroll(Autoscroll::newest(), cx);
13728        }
13729        self.selection_history.mode = SelectionHistoryMode::Normal;
13730    }
13731
13732    pub fn redo_selection(
13733        &mut self,
13734        _: &RedoSelection,
13735        window: &mut Window,
13736        cx: &mut Context<Self>,
13737    ) {
13738        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13739        self.end_selection(window, cx);
13740        self.selection_history.mode = SelectionHistoryMode::Redoing;
13741        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13742            self.change_selections(None, window, cx, |s| {
13743                s.select_anchors(entry.selections.to_vec())
13744            });
13745            self.select_next_state = entry.select_next_state;
13746            self.select_prev_state = entry.select_prev_state;
13747            self.add_selections_state = entry.add_selections_state;
13748            self.request_autoscroll(Autoscroll::newest(), cx);
13749        }
13750        self.selection_history.mode = SelectionHistoryMode::Normal;
13751    }
13752
13753    pub fn expand_excerpts(
13754        &mut self,
13755        action: &ExpandExcerpts,
13756        _: &mut Window,
13757        cx: &mut Context<Self>,
13758    ) {
13759        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13760    }
13761
13762    pub fn expand_excerpts_down(
13763        &mut self,
13764        action: &ExpandExcerptsDown,
13765        _: &mut Window,
13766        cx: &mut Context<Self>,
13767    ) {
13768        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13769    }
13770
13771    pub fn expand_excerpts_up(
13772        &mut self,
13773        action: &ExpandExcerptsUp,
13774        _: &mut Window,
13775        cx: &mut Context<Self>,
13776    ) {
13777        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13778    }
13779
13780    pub fn expand_excerpts_for_direction(
13781        &mut self,
13782        lines: u32,
13783        direction: ExpandExcerptDirection,
13784
13785        cx: &mut Context<Self>,
13786    ) {
13787        let selections = self.selections.disjoint_anchors();
13788
13789        let lines = if lines == 0 {
13790            EditorSettings::get_global(cx).expand_excerpt_lines
13791        } else {
13792            lines
13793        };
13794
13795        self.buffer.update(cx, |buffer, cx| {
13796            let snapshot = buffer.snapshot(cx);
13797            let mut excerpt_ids = selections
13798                .iter()
13799                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13800                .collect::<Vec<_>>();
13801            excerpt_ids.sort();
13802            excerpt_ids.dedup();
13803            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13804        })
13805    }
13806
13807    pub fn expand_excerpt(
13808        &mut self,
13809        excerpt: ExcerptId,
13810        direction: ExpandExcerptDirection,
13811        window: &mut Window,
13812        cx: &mut Context<Self>,
13813    ) {
13814        let current_scroll_position = self.scroll_position(cx);
13815        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13816        let mut should_scroll_up = false;
13817
13818        if direction == ExpandExcerptDirection::Down {
13819            let multi_buffer = self.buffer.read(cx);
13820            let snapshot = multi_buffer.snapshot(cx);
13821            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13822                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13823                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13824                        let buffer_snapshot = buffer.read(cx).snapshot();
13825                        let excerpt_end_row =
13826                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13827                        let last_row = buffer_snapshot.max_point().row;
13828                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13829                        should_scroll_up = lines_below >= lines_to_expand;
13830                    }
13831                }
13832            }
13833        }
13834
13835        self.buffer.update(cx, |buffer, cx| {
13836            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13837        });
13838
13839        if should_scroll_up {
13840            let new_scroll_position =
13841                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13842            self.set_scroll_position(new_scroll_position, window, cx);
13843        }
13844    }
13845
13846    pub fn go_to_singleton_buffer_point(
13847        &mut self,
13848        point: Point,
13849        window: &mut Window,
13850        cx: &mut Context<Self>,
13851    ) {
13852        self.go_to_singleton_buffer_range(point..point, window, cx);
13853    }
13854
13855    pub fn go_to_singleton_buffer_range(
13856        &mut self,
13857        range: Range<Point>,
13858        window: &mut Window,
13859        cx: &mut Context<Self>,
13860    ) {
13861        let multibuffer = self.buffer().read(cx);
13862        let Some(buffer) = multibuffer.as_singleton() else {
13863            return;
13864        };
13865        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13866            return;
13867        };
13868        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13869            return;
13870        };
13871        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13872            s.select_anchor_ranges([start..end])
13873        });
13874    }
13875
13876    pub fn go_to_diagnostic(
13877        &mut self,
13878        _: &GoToDiagnostic,
13879        window: &mut Window,
13880        cx: &mut Context<Self>,
13881    ) {
13882        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13883        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13884    }
13885
13886    pub fn go_to_prev_diagnostic(
13887        &mut self,
13888        _: &GoToPreviousDiagnostic,
13889        window: &mut Window,
13890        cx: &mut Context<Self>,
13891    ) {
13892        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13893        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13894    }
13895
13896    pub fn go_to_diagnostic_impl(
13897        &mut self,
13898        direction: Direction,
13899        window: &mut Window,
13900        cx: &mut Context<Self>,
13901    ) {
13902        let buffer = self.buffer.read(cx).snapshot(cx);
13903        let selection = self.selections.newest::<usize>(cx);
13904
13905        let mut active_group_id = None;
13906        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13907            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13908                active_group_id = Some(active_group.group_id);
13909            }
13910        }
13911
13912        fn filtered(
13913            snapshot: EditorSnapshot,
13914            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13915        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13916            diagnostics
13917                .filter(|entry| entry.range.start != entry.range.end)
13918                .filter(|entry| !entry.diagnostic.is_unnecessary)
13919                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13920        }
13921
13922        let snapshot = self.snapshot(window, cx);
13923        let before = filtered(
13924            snapshot.clone(),
13925            buffer
13926                .diagnostics_in_range(0..selection.start)
13927                .filter(|entry| entry.range.start <= selection.start),
13928        );
13929        let after = filtered(
13930            snapshot,
13931            buffer
13932                .diagnostics_in_range(selection.start..buffer.len())
13933                .filter(|entry| entry.range.start >= selection.start),
13934        );
13935
13936        let mut found: Option<DiagnosticEntry<usize>> = None;
13937        if direction == Direction::Prev {
13938            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13939            {
13940                for diagnostic in prev_diagnostics.into_iter().rev() {
13941                    if diagnostic.range.start != selection.start
13942                        || active_group_id
13943                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13944                    {
13945                        found = Some(diagnostic);
13946                        break 'outer;
13947                    }
13948                }
13949            }
13950        } else {
13951            for diagnostic in after.chain(before) {
13952                if diagnostic.range.start != selection.start
13953                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13954                {
13955                    found = Some(diagnostic);
13956                    break;
13957                }
13958            }
13959        }
13960        let Some(next_diagnostic) = found else {
13961            return;
13962        };
13963
13964        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13965            return;
13966        };
13967        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13968            s.select_ranges(vec![
13969                next_diagnostic.range.start..next_diagnostic.range.start,
13970            ])
13971        });
13972        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13973        self.refresh_inline_completion(false, true, window, cx);
13974    }
13975
13976    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13977        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13978        let snapshot = self.snapshot(window, cx);
13979        let selection = self.selections.newest::<Point>(cx);
13980        self.go_to_hunk_before_or_after_position(
13981            &snapshot,
13982            selection.head(),
13983            Direction::Next,
13984            window,
13985            cx,
13986        );
13987    }
13988
13989    pub fn go_to_hunk_before_or_after_position(
13990        &mut self,
13991        snapshot: &EditorSnapshot,
13992        position: Point,
13993        direction: Direction,
13994        window: &mut Window,
13995        cx: &mut Context<Editor>,
13996    ) {
13997        let row = if direction == Direction::Next {
13998            self.hunk_after_position(snapshot, position)
13999                .map(|hunk| hunk.row_range.start)
14000        } else {
14001            self.hunk_before_position(snapshot, position)
14002        };
14003
14004        if let Some(row) = row {
14005            let destination = Point::new(row.0, 0);
14006            let autoscroll = Autoscroll::center();
14007
14008            self.unfold_ranges(&[destination..destination], false, false, cx);
14009            self.change_selections(Some(autoscroll), window, cx, |s| {
14010                s.select_ranges([destination..destination]);
14011            });
14012        }
14013    }
14014
14015    fn hunk_after_position(
14016        &mut self,
14017        snapshot: &EditorSnapshot,
14018        position: Point,
14019    ) -> Option<MultiBufferDiffHunk> {
14020        snapshot
14021            .buffer_snapshot
14022            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14023            .find(|hunk| hunk.row_range.start.0 > position.row)
14024            .or_else(|| {
14025                snapshot
14026                    .buffer_snapshot
14027                    .diff_hunks_in_range(Point::zero()..position)
14028                    .find(|hunk| hunk.row_range.end.0 < position.row)
14029            })
14030    }
14031
14032    fn go_to_prev_hunk(
14033        &mut self,
14034        _: &GoToPreviousHunk,
14035        window: &mut Window,
14036        cx: &mut Context<Self>,
14037    ) {
14038        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14039        let snapshot = self.snapshot(window, cx);
14040        let selection = self.selections.newest::<Point>(cx);
14041        self.go_to_hunk_before_or_after_position(
14042            &snapshot,
14043            selection.head(),
14044            Direction::Prev,
14045            window,
14046            cx,
14047        );
14048    }
14049
14050    fn hunk_before_position(
14051        &mut self,
14052        snapshot: &EditorSnapshot,
14053        position: Point,
14054    ) -> Option<MultiBufferRow> {
14055        snapshot
14056            .buffer_snapshot
14057            .diff_hunk_before(position)
14058            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14059    }
14060
14061    fn go_to_next_change(
14062        &mut self,
14063        _: &GoToNextChange,
14064        window: &mut Window,
14065        cx: &mut Context<Self>,
14066    ) {
14067        if let Some(selections) = self
14068            .change_list
14069            .next_change(1, Direction::Next)
14070            .map(|s| s.to_vec())
14071        {
14072            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14073                let map = s.display_map();
14074                s.select_display_ranges(selections.iter().map(|a| {
14075                    let point = a.to_display_point(&map);
14076                    point..point
14077                }))
14078            })
14079        }
14080    }
14081
14082    fn go_to_previous_change(
14083        &mut self,
14084        _: &GoToPreviousChange,
14085        window: &mut Window,
14086        cx: &mut Context<Self>,
14087    ) {
14088        if let Some(selections) = self
14089            .change_list
14090            .next_change(1, Direction::Prev)
14091            .map(|s| s.to_vec())
14092        {
14093            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14094                let map = s.display_map();
14095                s.select_display_ranges(selections.iter().map(|a| {
14096                    let point = a.to_display_point(&map);
14097                    point..point
14098                }))
14099            })
14100        }
14101    }
14102
14103    fn go_to_line<T: 'static>(
14104        &mut self,
14105        position: Anchor,
14106        highlight_color: Option<Hsla>,
14107        window: &mut Window,
14108        cx: &mut Context<Self>,
14109    ) {
14110        let snapshot = self.snapshot(window, cx).display_snapshot;
14111        let position = position.to_point(&snapshot.buffer_snapshot);
14112        let start = snapshot
14113            .buffer_snapshot
14114            .clip_point(Point::new(position.row, 0), Bias::Left);
14115        let end = start + Point::new(1, 0);
14116        let start = snapshot.buffer_snapshot.anchor_before(start);
14117        let end = snapshot.buffer_snapshot.anchor_before(end);
14118
14119        self.highlight_rows::<T>(
14120            start..end,
14121            highlight_color
14122                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14123            Default::default(),
14124            cx,
14125        );
14126
14127        if self.buffer.read(cx).is_singleton() {
14128            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14129        }
14130    }
14131
14132    pub fn go_to_definition(
14133        &mut self,
14134        _: &GoToDefinition,
14135        window: &mut Window,
14136        cx: &mut Context<Self>,
14137    ) -> Task<Result<Navigated>> {
14138        let definition =
14139            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14140        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14141        cx.spawn_in(window, async move |editor, cx| {
14142            if definition.await? == Navigated::Yes {
14143                return Ok(Navigated::Yes);
14144            }
14145            match fallback_strategy {
14146                GoToDefinitionFallback::None => Ok(Navigated::No),
14147                GoToDefinitionFallback::FindAllReferences => {
14148                    match editor.update_in(cx, |editor, window, cx| {
14149                        editor.find_all_references(&FindAllReferences, window, cx)
14150                    })? {
14151                        Some(references) => references.await,
14152                        None => Ok(Navigated::No),
14153                    }
14154                }
14155            }
14156        })
14157    }
14158
14159    pub fn go_to_declaration(
14160        &mut self,
14161        _: &GoToDeclaration,
14162        window: &mut Window,
14163        cx: &mut Context<Self>,
14164    ) -> Task<Result<Navigated>> {
14165        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14166    }
14167
14168    pub fn go_to_declaration_split(
14169        &mut self,
14170        _: &GoToDeclaration,
14171        window: &mut Window,
14172        cx: &mut Context<Self>,
14173    ) -> Task<Result<Navigated>> {
14174        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14175    }
14176
14177    pub fn go_to_implementation(
14178        &mut self,
14179        _: &GoToImplementation,
14180        window: &mut Window,
14181        cx: &mut Context<Self>,
14182    ) -> Task<Result<Navigated>> {
14183        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14184    }
14185
14186    pub fn go_to_implementation_split(
14187        &mut self,
14188        _: &GoToImplementationSplit,
14189        window: &mut Window,
14190        cx: &mut Context<Self>,
14191    ) -> Task<Result<Navigated>> {
14192        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14193    }
14194
14195    pub fn go_to_type_definition(
14196        &mut self,
14197        _: &GoToTypeDefinition,
14198        window: &mut Window,
14199        cx: &mut Context<Self>,
14200    ) -> Task<Result<Navigated>> {
14201        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14202    }
14203
14204    pub fn go_to_definition_split(
14205        &mut self,
14206        _: &GoToDefinitionSplit,
14207        window: &mut Window,
14208        cx: &mut Context<Self>,
14209    ) -> Task<Result<Navigated>> {
14210        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14211    }
14212
14213    pub fn go_to_type_definition_split(
14214        &mut self,
14215        _: &GoToTypeDefinitionSplit,
14216        window: &mut Window,
14217        cx: &mut Context<Self>,
14218    ) -> Task<Result<Navigated>> {
14219        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14220    }
14221
14222    fn go_to_definition_of_kind(
14223        &mut self,
14224        kind: GotoDefinitionKind,
14225        split: bool,
14226        window: &mut Window,
14227        cx: &mut Context<Self>,
14228    ) -> Task<Result<Navigated>> {
14229        let Some(provider) = self.semantics_provider.clone() else {
14230            return Task::ready(Ok(Navigated::No));
14231        };
14232        let head = self.selections.newest::<usize>(cx).head();
14233        let buffer = self.buffer.read(cx);
14234        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14235            text_anchor
14236        } else {
14237            return Task::ready(Ok(Navigated::No));
14238        };
14239
14240        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14241            return Task::ready(Ok(Navigated::No));
14242        };
14243
14244        cx.spawn_in(window, async move |editor, cx| {
14245            let definitions = definitions.await?;
14246            let navigated = editor
14247                .update_in(cx, |editor, window, cx| {
14248                    editor.navigate_to_hover_links(
14249                        Some(kind),
14250                        definitions
14251                            .into_iter()
14252                            .filter(|location| {
14253                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14254                            })
14255                            .map(HoverLink::Text)
14256                            .collect::<Vec<_>>(),
14257                        split,
14258                        window,
14259                        cx,
14260                    )
14261                })?
14262                .await?;
14263            anyhow::Ok(navigated)
14264        })
14265    }
14266
14267    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14268        let selection = self.selections.newest_anchor();
14269        let head = selection.head();
14270        let tail = selection.tail();
14271
14272        let Some((buffer, start_position)) =
14273            self.buffer.read(cx).text_anchor_for_position(head, cx)
14274        else {
14275            return;
14276        };
14277
14278        let end_position = if head != tail {
14279            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14280                return;
14281            };
14282            Some(pos)
14283        } else {
14284            None
14285        };
14286
14287        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14288            let url = if let Some(end_pos) = end_position {
14289                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14290            } else {
14291                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14292            };
14293
14294            if let Some(url) = url {
14295                editor.update(cx, |_, cx| {
14296                    cx.open_url(&url);
14297                })
14298            } else {
14299                Ok(())
14300            }
14301        });
14302
14303        url_finder.detach();
14304    }
14305
14306    pub fn open_selected_filename(
14307        &mut self,
14308        _: &OpenSelectedFilename,
14309        window: &mut Window,
14310        cx: &mut Context<Self>,
14311    ) {
14312        let Some(workspace) = self.workspace() else {
14313            return;
14314        };
14315
14316        let position = self.selections.newest_anchor().head();
14317
14318        let Some((buffer, buffer_position)) =
14319            self.buffer.read(cx).text_anchor_for_position(position, cx)
14320        else {
14321            return;
14322        };
14323
14324        let project = self.project.clone();
14325
14326        cx.spawn_in(window, async move |_, cx| {
14327            let result = find_file(&buffer, project, buffer_position, cx).await;
14328
14329            if let Some((_, path)) = result {
14330                workspace
14331                    .update_in(cx, |workspace, window, cx| {
14332                        workspace.open_resolved_path(path, window, cx)
14333                    })?
14334                    .await?;
14335            }
14336            anyhow::Ok(())
14337        })
14338        .detach();
14339    }
14340
14341    pub(crate) fn navigate_to_hover_links(
14342        &mut self,
14343        kind: Option<GotoDefinitionKind>,
14344        mut definitions: Vec<HoverLink>,
14345        split: bool,
14346        window: &mut Window,
14347        cx: &mut Context<Editor>,
14348    ) -> Task<Result<Navigated>> {
14349        // If there is one definition, just open it directly
14350        if definitions.len() == 1 {
14351            let definition = definitions.pop().unwrap();
14352
14353            enum TargetTaskResult {
14354                Location(Option<Location>),
14355                AlreadyNavigated,
14356            }
14357
14358            let target_task = match definition {
14359                HoverLink::Text(link) => {
14360                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14361                }
14362                HoverLink::InlayHint(lsp_location, server_id) => {
14363                    let computation =
14364                        self.compute_target_location(lsp_location, server_id, window, cx);
14365                    cx.background_spawn(async move {
14366                        let location = computation.await?;
14367                        Ok(TargetTaskResult::Location(location))
14368                    })
14369                }
14370                HoverLink::Url(url) => {
14371                    cx.open_url(&url);
14372                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14373                }
14374                HoverLink::File(path) => {
14375                    if let Some(workspace) = self.workspace() {
14376                        cx.spawn_in(window, async move |_, cx| {
14377                            workspace
14378                                .update_in(cx, |workspace, window, cx| {
14379                                    workspace.open_resolved_path(path, window, cx)
14380                                })?
14381                                .await
14382                                .map(|_| TargetTaskResult::AlreadyNavigated)
14383                        })
14384                    } else {
14385                        Task::ready(Ok(TargetTaskResult::Location(None)))
14386                    }
14387                }
14388            };
14389            cx.spawn_in(window, async move |editor, cx| {
14390                let target = match target_task.await.context("target resolution task")? {
14391                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14392                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14393                    TargetTaskResult::Location(Some(target)) => target,
14394                };
14395
14396                editor.update_in(cx, |editor, window, cx| {
14397                    let Some(workspace) = editor.workspace() else {
14398                        return Navigated::No;
14399                    };
14400                    let pane = workspace.read(cx).active_pane().clone();
14401
14402                    let range = target.range.to_point(target.buffer.read(cx));
14403                    let range = editor.range_for_match(&range);
14404                    let range = collapse_multiline_range(range);
14405
14406                    if !split
14407                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14408                    {
14409                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14410                    } else {
14411                        window.defer(cx, move |window, cx| {
14412                            let target_editor: Entity<Self> =
14413                                workspace.update(cx, |workspace, cx| {
14414                                    let pane = if split {
14415                                        workspace.adjacent_pane(window, cx)
14416                                    } else {
14417                                        workspace.active_pane().clone()
14418                                    };
14419
14420                                    workspace.open_project_item(
14421                                        pane,
14422                                        target.buffer.clone(),
14423                                        true,
14424                                        true,
14425                                        window,
14426                                        cx,
14427                                    )
14428                                });
14429                            target_editor.update(cx, |target_editor, cx| {
14430                                // When selecting a definition in a different buffer, disable the nav history
14431                                // to avoid creating a history entry at the previous cursor location.
14432                                pane.update(cx, |pane, _| pane.disable_history());
14433                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14434                                pane.update(cx, |pane, _| pane.enable_history());
14435                            });
14436                        });
14437                    }
14438                    Navigated::Yes
14439                })
14440            })
14441        } else if !definitions.is_empty() {
14442            cx.spawn_in(window, async move |editor, cx| {
14443                let (title, location_tasks, workspace) = editor
14444                    .update_in(cx, |editor, window, cx| {
14445                        let tab_kind = match kind {
14446                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14447                            _ => "Definitions",
14448                        };
14449                        let title = definitions
14450                            .iter()
14451                            .find_map(|definition| match definition {
14452                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14453                                    let buffer = origin.buffer.read(cx);
14454                                    format!(
14455                                        "{} for {}",
14456                                        tab_kind,
14457                                        buffer
14458                                            .text_for_range(origin.range.clone())
14459                                            .collect::<String>()
14460                                    )
14461                                }),
14462                                HoverLink::InlayHint(_, _) => None,
14463                                HoverLink::Url(_) => None,
14464                                HoverLink::File(_) => None,
14465                            })
14466                            .unwrap_or(tab_kind.to_string());
14467                        let location_tasks = definitions
14468                            .into_iter()
14469                            .map(|definition| match definition {
14470                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14471                                HoverLink::InlayHint(lsp_location, server_id) => editor
14472                                    .compute_target_location(lsp_location, server_id, window, cx),
14473                                HoverLink::Url(_) => Task::ready(Ok(None)),
14474                                HoverLink::File(_) => Task::ready(Ok(None)),
14475                            })
14476                            .collect::<Vec<_>>();
14477                        (title, location_tasks, editor.workspace().clone())
14478                    })
14479                    .context("location tasks preparation")?;
14480
14481                let locations = future::join_all(location_tasks)
14482                    .await
14483                    .into_iter()
14484                    .filter_map(|location| location.transpose())
14485                    .collect::<Result<_>>()
14486                    .context("location tasks")?;
14487
14488                let Some(workspace) = workspace else {
14489                    return Ok(Navigated::No);
14490                };
14491                let opened = workspace
14492                    .update_in(cx, |workspace, window, cx| {
14493                        Self::open_locations_in_multibuffer(
14494                            workspace,
14495                            locations,
14496                            title,
14497                            split,
14498                            MultibufferSelectionMode::First,
14499                            window,
14500                            cx,
14501                        )
14502                    })
14503                    .ok();
14504
14505                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14506            })
14507        } else {
14508            Task::ready(Ok(Navigated::No))
14509        }
14510    }
14511
14512    fn compute_target_location(
14513        &self,
14514        lsp_location: lsp::Location,
14515        server_id: LanguageServerId,
14516        window: &mut Window,
14517        cx: &mut Context<Self>,
14518    ) -> Task<anyhow::Result<Option<Location>>> {
14519        let Some(project) = self.project.clone() else {
14520            return Task::ready(Ok(None));
14521        };
14522
14523        cx.spawn_in(window, async move |editor, cx| {
14524            let location_task = editor.update(cx, |_, cx| {
14525                project.update(cx, |project, cx| {
14526                    let language_server_name = project
14527                        .language_server_statuses(cx)
14528                        .find(|(id, _)| server_id == *id)
14529                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14530                    language_server_name.map(|language_server_name| {
14531                        project.open_local_buffer_via_lsp(
14532                            lsp_location.uri.clone(),
14533                            server_id,
14534                            language_server_name,
14535                            cx,
14536                        )
14537                    })
14538                })
14539            })?;
14540            let location = match location_task {
14541                Some(task) => Some({
14542                    let target_buffer_handle = task.await.context("open local buffer")?;
14543                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14544                        let target_start = target_buffer
14545                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14546                        let target_end = target_buffer
14547                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14548                        target_buffer.anchor_after(target_start)
14549                            ..target_buffer.anchor_before(target_end)
14550                    })?;
14551                    Location {
14552                        buffer: target_buffer_handle,
14553                        range,
14554                    }
14555                }),
14556                None => None,
14557            };
14558            Ok(location)
14559        })
14560    }
14561
14562    pub fn find_all_references(
14563        &mut self,
14564        _: &FindAllReferences,
14565        window: &mut Window,
14566        cx: &mut Context<Self>,
14567    ) -> Option<Task<Result<Navigated>>> {
14568        let selection = self.selections.newest::<usize>(cx);
14569        let multi_buffer = self.buffer.read(cx);
14570        let head = selection.head();
14571
14572        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14573        let head_anchor = multi_buffer_snapshot.anchor_at(
14574            head,
14575            if head < selection.tail() {
14576                Bias::Right
14577            } else {
14578                Bias::Left
14579            },
14580        );
14581
14582        match self
14583            .find_all_references_task_sources
14584            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14585        {
14586            Ok(_) => {
14587                log::info!(
14588                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14589                );
14590                return None;
14591            }
14592            Err(i) => {
14593                self.find_all_references_task_sources.insert(i, head_anchor);
14594            }
14595        }
14596
14597        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14598        let workspace = self.workspace()?;
14599        let project = workspace.read(cx).project().clone();
14600        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14601        Some(cx.spawn_in(window, async move |editor, cx| {
14602            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14603                if let Ok(i) = editor
14604                    .find_all_references_task_sources
14605                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14606                {
14607                    editor.find_all_references_task_sources.remove(i);
14608                }
14609            });
14610
14611            let locations = references.await?;
14612            if locations.is_empty() {
14613                return anyhow::Ok(Navigated::No);
14614            }
14615
14616            workspace.update_in(cx, |workspace, window, cx| {
14617                let title = locations
14618                    .first()
14619                    .as_ref()
14620                    .map(|location| {
14621                        let buffer = location.buffer.read(cx);
14622                        format!(
14623                            "References to `{}`",
14624                            buffer
14625                                .text_for_range(location.range.clone())
14626                                .collect::<String>()
14627                        )
14628                    })
14629                    .unwrap();
14630                Self::open_locations_in_multibuffer(
14631                    workspace,
14632                    locations,
14633                    title,
14634                    false,
14635                    MultibufferSelectionMode::First,
14636                    window,
14637                    cx,
14638                );
14639                Navigated::Yes
14640            })
14641        }))
14642    }
14643
14644    /// Opens a multibuffer with the given project locations in it
14645    pub fn open_locations_in_multibuffer(
14646        workspace: &mut Workspace,
14647        mut locations: Vec<Location>,
14648        title: String,
14649        split: bool,
14650        multibuffer_selection_mode: MultibufferSelectionMode,
14651        window: &mut Window,
14652        cx: &mut Context<Workspace>,
14653    ) {
14654        // If there are multiple definitions, open them in a multibuffer
14655        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14656        let mut locations = locations.into_iter().peekable();
14657        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14658        let capability = workspace.project().read(cx).capability();
14659
14660        let excerpt_buffer = cx.new(|cx| {
14661            let mut multibuffer = MultiBuffer::new(capability);
14662            while let Some(location) = locations.next() {
14663                let buffer = location.buffer.read(cx);
14664                let mut ranges_for_buffer = Vec::new();
14665                let range = location.range.to_point(buffer);
14666                ranges_for_buffer.push(range.clone());
14667
14668                while let Some(next_location) = locations.peek() {
14669                    if next_location.buffer == location.buffer {
14670                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14671                        locations.next();
14672                    } else {
14673                        break;
14674                    }
14675                }
14676
14677                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14678                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14679                    PathKey::for_buffer(&location.buffer, cx),
14680                    location.buffer.clone(),
14681                    ranges_for_buffer,
14682                    DEFAULT_MULTIBUFFER_CONTEXT,
14683                    cx,
14684                );
14685                ranges.extend(new_ranges)
14686            }
14687
14688            multibuffer.with_title(title)
14689        });
14690
14691        let editor = cx.new(|cx| {
14692            Editor::for_multibuffer(
14693                excerpt_buffer,
14694                Some(workspace.project().clone()),
14695                window,
14696                cx,
14697            )
14698        });
14699        editor.update(cx, |editor, cx| {
14700            match multibuffer_selection_mode {
14701                MultibufferSelectionMode::First => {
14702                    if let Some(first_range) = ranges.first() {
14703                        editor.change_selections(None, window, cx, |selections| {
14704                            selections.clear_disjoint();
14705                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14706                        });
14707                    }
14708                    editor.highlight_background::<Self>(
14709                        &ranges,
14710                        |theme| theme.editor_highlighted_line_background,
14711                        cx,
14712                    );
14713                }
14714                MultibufferSelectionMode::All => {
14715                    editor.change_selections(None, window, cx, |selections| {
14716                        selections.clear_disjoint();
14717                        selections.select_anchor_ranges(ranges);
14718                    });
14719                }
14720            }
14721            editor.register_buffers_with_language_servers(cx);
14722        });
14723
14724        let item = Box::new(editor);
14725        let item_id = item.item_id();
14726
14727        if split {
14728            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14729        } else {
14730            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14731                let (preview_item_id, preview_item_idx) =
14732                    workspace.active_pane().update(cx, |pane, _| {
14733                        (pane.preview_item_id(), pane.preview_item_idx())
14734                    });
14735
14736                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14737
14738                if let Some(preview_item_id) = preview_item_id {
14739                    workspace.active_pane().update(cx, |pane, cx| {
14740                        pane.remove_item(preview_item_id, false, false, window, cx);
14741                    });
14742                }
14743            } else {
14744                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14745            }
14746        }
14747        workspace.active_pane().update(cx, |pane, cx| {
14748            pane.set_preview_item_id(Some(item_id), cx);
14749        });
14750    }
14751
14752    pub fn rename(
14753        &mut self,
14754        _: &Rename,
14755        window: &mut Window,
14756        cx: &mut Context<Self>,
14757    ) -> Option<Task<Result<()>>> {
14758        use language::ToOffset as _;
14759
14760        let provider = self.semantics_provider.clone()?;
14761        let selection = self.selections.newest_anchor().clone();
14762        let (cursor_buffer, cursor_buffer_position) = self
14763            .buffer
14764            .read(cx)
14765            .text_anchor_for_position(selection.head(), cx)?;
14766        let (tail_buffer, cursor_buffer_position_end) = self
14767            .buffer
14768            .read(cx)
14769            .text_anchor_for_position(selection.tail(), cx)?;
14770        if tail_buffer != cursor_buffer {
14771            return None;
14772        }
14773
14774        let snapshot = cursor_buffer.read(cx).snapshot();
14775        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14776        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14777        let prepare_rename = provider
14778            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14779            .unwrap_or_else(|| Task::ready(Ok(None)));
14780        drop(snapshot);
14781
14782        Some(cx.spawn_in(window, async move |this, cx| {
14783            let rename_range = if let Some(range) = prepare_rename.await? {
14784                Some(range)
14785            } else {
14786                this.update(cx, |this, cx| {
14787                    let buffer = this.buffer.read(cx).snapshot(cx);
14788                    let mut buffer_highlights = this
14789                        .document_highlights_for_position(selection.head(), &buffer)
14790                        .filter(|highlight| {
14791                            highlight.start.excerpt_id == selection.head().excerpt_id
14792                                && highlight.end.excerpt_id == selection.head().excerpt_id
14793                        });
14794                    buffer_highlights
14795                        .next()
14796                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14797                })?
14798            };
14799            if let Some(rename_range) = rename_range {
14800                this.update_in(cx, |this, window, cx| {
14801                    let snapshot = cursor_buffer.read(cx).snapshot();
14802                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14803                    let cursor_offset_in_rename_range =
14804                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14805                    let cursor_offset_in_rename_range_end =
14806                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14807
14808                    this.take_rename(false, window, cx);
14809                    let buffer = this.buffer.read(cx).read(cx);
14810                    let cursor_offset = selection.head().to_offset(&buffer);
14811                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14812                    let rename_end = rename_start + rename_buffer_range.len();
14813                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14814                    let mut old_highlight_id = None;
14815                    let old_name: Arc<str> = buffer
14816                        .chunks(rename_start..rename_end, true)
14817                        .map(|chunk| {
14818                            if old_highlight_id.is_none() {
14819                                old_highlight_id = chunk.syntax_highlight_id;
14820                            }
14821                            chunk.text
14822                        })
14823                        .collect::<String>()
14824                        .into();
14825
14826                    drop(buffer);
14827
14828                    // Position the selection in the rename editor so that it matches the current selection.
14829                    this.show_local_selections = false;
14830                    let rename_editor = cx.new(|cx| {
14831                        let mut editor = Editor::single_line(window, cx);
14832                        editor.buffer.update(cx, |buffer, cx| {
14833                            buffer.edit([(0..0, old_name.clone())], None, cx)
14834                        });
14835                        let rename_selection_range = match cursor_offset_in_rename_range
14836                            .cmp(&cursor_offset_in_rename_range_end)
14837                        {
14838                            Ordering::Equal => {
14839                                editor.select_all(&SelectAll, window, cx);
14840                                return editor;
14841                            }
14842                            Ordering::Less => {
14843                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14844                            }
14845                            Ordering::Greater => {
14846                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14847                            }
14848                        };
14849                        if rename_selection_range.end > old_name.len() {
14850                            editor.select_all(&SelectAll, window, cx);
14851                        } else {
14852                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14853                                s.select_ranges([rename_selection_range]);
14854                            });
14855                        }
14856                        editor
14857                    });
14858                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14859                        if e == &EditorEvent::Focused {
14860                            cx.emit(EditorEvent::FocusedIn)
14861                        }
14862                    })
14863                    .detach();
14864
14865                    let write_highlights =
14866                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14867                    let read_highlights =
14868                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14869                    let ranges = write_highlights
14870                        .iter()
14871                        .flat_map(|(_, ranges)| ranges.iter())
14872                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14873                        .cloned()
14874                        .collect();
14875
14876                    this.highlight_text::<Rename>(
14877                        ranges,
14878                        HighlightStyle {
14879                            fade_out: Some(0.6),
14880                            ..Default::default()
14881                        },
14882                        cx,
14883                    );
14884                    let rename_focus_handle = rename_editor.focus_handle(cx);
14885                    window.focus(&rename_focus_handle);
14886                    let block_id = this.insert_blocks(
14887                        [BlockProperties {
14888                            style: BlockStyle::Flex,
14889                            placement: BlockPlacement::Below(range.start),
14890                            height: Some(1),
14891                            render: Arc::new({
14892                                let rename_editor = rename_editor.clone();
14893                                move |cx: &mut BlockContext| {
14894                                    let mut text_style = cx.editor_style.text.clone();
14895                                    if let Some(highlight_style) = old_highlight_id
14896                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14897                                    {
14898                                        text_style = text_style.highlight(highlight_style);
14899                                    }
14900                                    div()
14901                                        .block_mouse_down()
14902                                        .pl(cx.anchor_x)
14903                                        .child(EditorElement::new(
14904                                            &rename_editor,
14905                                            EditorStyle {
14906                                                background: cx.theme().system().transparent,
14907                                                local_player: cx.editor_style.local_player,
14908                                                text: text_style,
14909                                                scrollbar_width: cx.editor_style.scrollbar_width,
14910                                                syntax: cx.editor_style.syntax.clone(),
14911                                                status: cx.editor_style.status.clone(),
14912                                                inlay_hints_style: HighlightStyle {
14913                                                    font_weight: Some(FontWeight::BOLD),
14914                                                    ..make_inlay_hints_style(cx.app)
14915                                                },
14916                                                inline_completion_styles: make_suggestion_styles(
14917                                                    cx.app,
14918                                                ),
14919                                                ..EditorStyle::default()
14920                                            },
14921                                        ))
14922                                        .into_any_element()
14923                                }
14924                            }),
14925                            priority: 0,
14926                            render_in_minimap: true,
14927                        }],
14928                        Some(Autoscroll::fit()),
14929                        cx,
14930                    )[0];
14931                    this.pending_rename = Some(RenameState {
14932                        range,
14933                        old_name,
14934                        editor: rename_editor,
14935                        block_id,
14936                    });
14937                })?;
14938            }
14939
14940            Ok(())
14941        }))
14942    }
14943
14944    pub fn confirm_rename(
14945        &mut self,
14946        _: &ConfirmRename,
14947        window: &mut Window,
14948        cx: &mut Context<Self>,
14949    ) -> Option<Task<Result<()>>> {
14950        let rename = self.take_rename(false, window, cx)?;
14951        let workspace = self.workspace()?.downgrade();
14952        let (buffer, start) = self
14953            .buffer
14954            .read(cx)
14955            .text_anchor_for_position(rename.range.start, cx)?;
14956        let (end_buffer, _) = self
14957            .buffer
14958            .read(cx)
14959            .text_anchor_for_position(rename.range.end, cx)?;
14960        if buffer != end_buffer {
14961            return None;
14962        }
14963
14964        let old_name = rename.old_name;
14965        let new_name = rename.editor.read(cx).text(cx);
14966
14967        let rename = self.semantics_provider.as_ref()?.perform_rename(
14968            &buffer,
14969            start,
14970            new_name.clone(),
14971            cx,
14972        )?;
14973
14974        Some(cx.spawn_in(window, async move |editor, cx| {
14975            let project_transaction = rename.await?;
14976            Self::open_project_transaction(
14977                &editor,
14978                workspace,
14979                project_transaction,
14980                format!("Rename: {}{}", old_name, new_name),
14981                cx,
14982            )
14983            .await?;
14984
14985            editor.update(cx, |editor, cx| {
14986                editor.refresh_document_highlights(cx);
14987            })?;
14988            Ok(())
14989        }))
14990    }
14991
14992    fn take_rename(
14993        &mut self,
14994        moving_cursor: bool,
14995        window: &mut Window,
14996        cx: &mut Context<Self>,
14997    ) -> Option<RenameState> {
14998        let rename = self.pending_rename.take()?;
14999        if rename.editor.focus_handle(cx).is_focused(window) {
15000            window.focus(&self.focus_handle);
15001        }
15002
15003        self.remove_blocks(
15004            [rename.block_id].into_iter().collect(),
15005            Some(Autoscroll::fit()),
15006            cx,
15007        );
15008        self.clear_highlights::<Rename>(cx);
15009        self.show_local_selections = true;
15010
15011        if moving_cursor {
15012            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15013                editor.selections.newest::<usize>(cx).head()
15014            });
15015
15016            // Update the selection to match the position of the selection inside
15017            // the rename editor.
15018            let snapshot = self.buffer.read(cx).read(cx);
15019            let rename_range = rename.range.to_offset(&snapshot);
15020            let cursor_in_editor = snapshot
15021                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15022                .min(rename_range.end);
15023            drop(snapshot);
15024
15025            self.change_selections(None, window, cx, |s| {
15026                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15027            });
15028        } else {
15029            self.refresh_document_highlights(cx);
15030        }
15031
15032        Some(rename)
15033    }
15034
15035    pub fn pending_rename(&self) -> Option<&RenameState> {
15036        self.pending_rename.as_ref()
15037    }
15038
15039    fn format(
15040        &mut self,
15041        _: &Format,
15042        window: &mut Window,
15043        cx: &mut Context<Self>,
15044    ) -> Option<Task<Result<()>>> {
15045        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15046
15047        let project = match &self.project {
15048            Some(project) => project.clone(),
15049            None => return None,
15050        };
15051
15052        Some(self.perform_format(
15053            project,
15054            FormatTrigger::Manual,
15055            FormatTarget::Buffers,
15056            window,
15057            cx,
15058        ))
15059    }
15060
15061    fn format_selections(
15062        &mut self,
15063        _: &FormatSelections,
15064        window: &mut Window,
15065        cx: &mut Context<Self>,
15066    ) -> Option<Task<Result<()>>> {
15067        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15068
15069        let project = match &self.project {
15070            Some(project) => project.clone(),
15071            None => return None,
15072        };
15073
15074        let ranges = self
15075            .selections
15076            .all_adjusted(cx)
15077            .into_iter()
15078            .map(|selection| selection.range())
15079            .collect_vec();
15080
15081        Some(self.perform_format(
15082            project,
15083            FormatTrigger::Manual,
15084            FormatTarget::Ranges(ranges),
15085            window,
15086            cx,
15087        ))
15088    }
15089
15090    fn perform_format(
15091        &mut self,
15092        project: Entity<Project>,
15093        trigger: FormatTrigger,
15094        target: FormatTarget,
15095        window: &mut Window,
15096        cx: &mut Context<Self>,
15097    ) -> Task<Result<()>> {
15098        let buffer = self.buffer.clone();
15099        let (buffers, target) = match target {
15100            FormatTarget::Buffers => {
15101                let mut buffers = buffer.read(cx).all_buffers();
15102                if trigger == FormatTrigger::Save {
15103                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15104                }
15105                (buffers, LspFormatTarget::Buffers)
15106            }
15107            FormatTarget::Ranges(selection_ranges) => {
15108                let multi_buffer = buffer.read(cx);
15109                let snapshot = multi_buffer.read(cx);
15110                let mut buffers = HashSet::default();
15111                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15112                    BTreeMap::new();
15113                for selection_range in selection_ranges {
15114                    for (buffer, buffer_range, _) in
15115                        snapshot.range_to_buffer_ranges(selection_range)
15116                    {
15117                        let buffer_id = buffer.remote_id();
15118                        let start = buffer.anchor_before(buffer_range.start);
15119                        let end = buffer.anchor_after(buffer_range.end);
15120                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15121                        buffer_id_to_ranges
15122                            .entry(buffer_id)
15123                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15124                            .or_insert_with(|| vec![start..end]);
15125                    }
15126                }
15127                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15128            }
15129        };
15130
15131        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15132        let selections_prev = transaction_id_prev
15133            .and_then(|transaction_id_prev| {
15134                // default to selections as they were after the last edit, if we have them,
15135                // instead of how they are now.
15136                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15137                // will take you back to where you made the last edit, instead of staying where you scrolled
15138                self.selection_history
15139                    .transaction(transaction_id_prev)
15140                    .map(|t| t.0.clone())
15141            })
15142            .unwrap_or_else(|| {
15143                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15144                self.selections.disjoint_anchors()
15145            });
15146
15147        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15148        let format = project.update(cx, |project, cx| {
15149            project.format(buffers, target, true, trigger, cx)
15150        });
15151
15152        cx.spawn_in(window, async move |editor, cx| {
15153            let transaction = futures::select_biased! {
15154                transaction = format.log_err().fuse() => transaction,
15155                () = timeout => {
15156                    log::warn!("timed out waiting for formatting");
15157                    None
15158                }
15159            };
15160
15161            buffer
15162                .update(cx, |buffer, cx| {
15163                    if let Some(transaction) = transaction {
15164                        if !buffer.is_singleton() {
15165                            buffer.push_transaction(&transaction.0, cx);
15166                        }
15167                    }
15168                    cx.notify();
15169                })
15170                .ok();
15171
15172            if let Some(transaction_id_now) =
15173                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15174            {
15175                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15176                if has_new_transaction {
15177                    _ = editor.update(cx, |editor, _| {
15178                        editor
15179                            .selection_history
15180                            .insert_transaction(transaction_id_now, selections_prev);
15181                    });
15182                }
15183            }
15184
15185            Ok(())
15186        })
15187    }
15188
15189    fn organize_imports(
15190        &mut self,
15191        _: &OrganizeImports,
15192        window: &mut Window,
15193        cx: &mut Context<Self>,
15194    ) -> Option<Task<Result<()>>> {
15195        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15196        let project = match &self.project {
15197            Some(project) => project.clone(),
15198            None => return None,
15199        };
15200        Some(self.perform_code_action_kind(
15201            project,
15202            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15203            window,
15204            cx,
15205        ))
15206    }
15207
15208    fn perform_code_action_kind(
15209        &mut self,
15210        project: Entity<Project>,
15211        kind: CodeActionKind,
15212        window: &mut Window,
15213        cx: &mut Context<Self>,
15214    ) -> Task<Result<()>> {
15215        let buffer = self.buffer.clone();
15216        let buffers = buffer.read(cx).all_buffers();
15217        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15218        let apply_action = project.update(cx, |project, cx| {
15219            project.apply_code_action_kind(buffers, kind, true, cx)
15220        });
15221        cx.spawn_in(window, async move |_, cx| {
15222            let transaction = futures::select_biased! {
15223                () = timeout => {
15224                    log::warn!("timed out waiting for executing code action");
15225                    None
15226                }
15227                transaction = apply_action.log_err().fuse() => transaction,
15228            };
15229            buffer
15230                .update(cx, |buffer, cx| {
15231                    // check if we need this
15232                    if let Some(transaction) = transaction {
15233                        if !buffer.is_singleton() {
15234                            buffer.push_transaction(&transaction.0, cx);
15235                        }
15236                    }
15237                    cx.notify();
15238                })
15239                .ok();
15240            Ok(())
15241        })
15242    }
15243
15244    fn restart_language_server(
15245        &mut self,
15246        _: &RestartLanguageServer,
15247        _: &mut Window,
15248        cx: &mut Context<Self>,
15249    ) {
15250        if let Some(project) = self.project.clone() {
15251            self.buffer.update(cx, |multi_buffer, cx| {
15252                project.update(cx, |project, cx| {
15253                    project.restart_language_servers_for_buffers(
15254                        multi_buffer.all_buffers().into_iter().collect(),
15255                        cx,
15256                    );
15257                });
15258            })
15259        }
15260    }
15261
15262    fn stop_language_server(
15263        &mut self,
15264        _: &StopLanguageServer,
15265        _: &mut Window,
15266        cx: &mut Context<Self>,
15267    ) {
15268        if let Some(project) = self.project.clone() {
15269            self.buffer.update(cx, |multi_buffer, cx| {
15270                project.update(cx, |project, cx| {
15271                    project.stop_language_servers_for_buffers(
15272                        multi_buffer.all_buffers().into_iter().collect(),
15273                        cx,
15274                    );
15275                    cx.emit(project::Event::RefreshInlayHints);
15276                });
15277            });
15278        }
15279    }
15280
15281    fn cancel_language_server_work(
15282        workspace: &mut Workspace,
15283        _: &actions::CancelLanguageServerWork,
15284        _: &mut Window,
15285        cx: &mut Context<Workspace>,
15286    ) {
15287        let project = workspace.project();
15288        let buffers = workspace
15289            .active_item(cx)
15290            .and_then(|item| item.act_as::<Editor>(cx))
15291            .map_or(HashSet::default(), |editor| {
15292                editor.read(cx).buffer.read(cx).all_buffers()
15293            });
15294        project.update(cx, |project, cx| {
15295            project.cancel_language_server_work_for_buffers(buffers, cx);
15296        });
15297    }
15298
15299    fn show_character_palette(
15300        &mut self,
15301        _: &ShowCharacterPalette,
15302        window: &mut Window,
15303        _: &mut Context<Self>,
15304    ) {
15305        window.show_character_palette();
15306    }
15307
15308    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15309        if self.mode.is_minimap() {
15310            return;
15311        }
15312
15313        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15314            let buffer = self.buffer.read(cx).snapshot(cx);
15315            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15316            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15317            let is_valid = buffer
15318                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15319                .any(|entry| {
15320                    entry.diagnostic.is_primary
15321                        && !entry.range.is_empty()
15322                        && entry.range.start == primary_range_start
15323                        && entry.diagnostic.message == active_diagnostics.active_message
15324                });
15325
15326            if !is_valid {
15327                self.dismiss_diagnostics(cx);
15328            }
15329        }
15330    }
15331
15332    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15333        match &self.active_diagnostics {
15334            ActiveDiagnostic::Group(group) => Some(group),
15335            _ => None,
15336        }
15337    }
15338
15339    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15340        self.dismiss_diagnostics(cx);
15341        self.active_diagnostics = ActiveDiagnostic::All;
15342    }
15343
15344    fn activate_diagnostics(
15345        &mut self,
15346        buffer_id: BufferId,
15347        diagnostic: DiagnosticEntry<usize>,
15348        window: &mut Window,
15349        cx: &mut Context<Self>,
15350    ) {
15351        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15352            return;
15353        }
15354        self.dismiss_diagnostics(cx);
15355        let snapshot = self.snapshot(window, cx);
15356        let buffer = self.buffer.read(cx).snapshot(cx);
15357        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15358            return;
15359        };
15360
15361        let diagnostic_group = buffer
15362            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15363            .collect::<Vec<_>>();
15364
15365        let blocks =
15366            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15367
15368        let blocks = self.display_map.update(cx, |display_map, cx| {
15369            display_map.insert_blocks(blocks, cx).into_iter().collect()
15370        });
15371        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15372            active_range: buffer.anchor_before(diagnostic.range.start)
15373                ..buffer.anchor_after(diagnostic.range.end),
15374            active_message: diagnostic.diagnostic.message.clone(),
15375            group_id: diagnostic.diagnostic.group_id,
15376            blocks,
15377        });
15378        cx.notify();
15379    }
15380
15381    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15382        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15383            return;
15384        };
15385
15386        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15387        if let ActiveDiagnostic::Group(group) = prev {
15388            self.display_map.update(cx, |display_map, cx| {
15389                display_map.remove_blocks(group.blocks, cx);
15390            });
15391            cx.notify();
15392        }
15393    }
15394
15395    /// Disable inline diagnostics rendering for this editor.
15396    pub fn disable_inline_diagnostics(&mut self) {
15397        self.inline_diagnostics_enabled = false;
15398        self.inline_diagnostics_update = Task::ready(());
15399        self.inline_diagnostics.clear();
15400    }
15401
15402    pub fn diagnostics_enabled(&self) -> bool {
15403        self.mode.is_full()
15404    }
15405
15406    pub fn inline_diagnostics_enabled(&self) -> bool {
15407        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15408    }
15409
15410    pub fn show_inline_diagnostics(&self) -> bool {
15411        self.show_inline_diagnostics
15412    }
15413
15414    pub fn toggle_inline_diagnostics(
15415        &mut self,
15416        _: &ToggleInlineDiagnostics,
15417        window: &mut Window,
15418        cx: &mut Context<Editor>,
15419    ) {
15420        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15421        self.refresh_inline_diagnostics(false, window, cx);
15422    }
15423
15424    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15425        self.diagnostics_max_severity = severity;
15426        self.display_map.update(cx, |display_map, _| {
15427            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15428        });
15429    }
15430
15431    pub fn toggle_diagnostics(
15432        &mut self,
15433        _: &ToggleDiagnostics,
15434        window: &mut Window,
15435        cx: &mut Context<Editor>,
15436    ) {
15437        if !self.diagnostics_enabled() {
15438            return;
15439        }
15440
15441        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15442            EditorSettings::get_global(cx)
15443                .diagnostics_max_severity
15444                .filter(|severity| severity != &DiagnosticSeverity::Off)
15445                .unwrap_or(DiagnosticSeverity::Hint)
15446        } else {
15447            DiagnosticSeverity::Off
15448        };
15449        self.set_max_diagnostics_severity(new_severity, cx);
15450        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15451            self.active_diagnostics = ActiveDiagnostic::None;
15452            self.inline_diagnostics_update = Task::ready(());
15453            self.inline_diagnostics.clear();
15454        } else {
15455            self.refresh_inline_diagnostics(false, window, cx);
15456        }
15457
15458        cx.notify();
15459    }
15460
15461    pub fn toggle_minimap(
15462        &mut self,
15463        _: &ToggleMinimap,
15464        window: &mut Window,
15465        cx: &mut Context<Editor>,
15466    ) {
15467        if self.supports_minimap(cx) {
15468            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15469        }
15470    }
15471
15472    fn refresh_inline_diagnostics(
15473        &mut self,
15474        debounce: bool,
15475        window: &mut Window,
15476        cx: &mut Context<Self>,
15477    ) {
15478        let max_severity = ProjectSettings::get_global(cx)
15479            .diagnostics
15480            .inline
15481            .max_severity
15482            .unwrap_or(self.diagnostics_max_severity);
15483
15484        if self.mode.is_minimap()
15485            || !self.inline_diagnostics_enabled()
15486            || !self.show_inline_diagnostics
15487            || max_severity == DiagnosticSeverity::Off
15488        {
15489            self.inline_diagnostics_update = Task::ready(());
15490            self.inline_diagnostics.clear();
15491            return;
15492        }
15493
15494        let debounce_ms = ProjectSettings::get_global(cx)
15495            .diagnostics
15496            .inline
15497            .update_debounce_ms;
15498        let debounce = if debounce && debounce_ms > 0 {
15499            Some(Duration::from_millis(debounce_ms))
15500        } else {
15501            None
15502        };
15503        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15504            let editor = editor.upgrade().unwrap();
15505
15506            if let Some(debounce) = debounce {
15507                cx.background_executor().timer(debounce).await;
15508            }
15509            let Some(snapshot) = editor
15510                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15511                .ok()
15512            else {
15513                return;
15514            };
15515
15516            let new_inline_diagnostics = cx
15517                .background_spawn(async move {
15518                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15519                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15520                        let message = diagnostic_entry
15521                            .diagnostic
15522                            .message
15523                            .split_once('\n')
15524                            .map(|(line, _)| line)
15525                            .map(SharedString::new)
15526                            .unwrap_or_else(|| {
15527                                SharedString::from(diagnostic_entry.diagnostic.message)
15528                            });
15529                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15530                        let (Ok(i) | Err(i)) = inline_diagnostics
15531                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15532                        inline_diagnostics.insert(
15533                            i,
15534                            (
15535                                start_anchor,
15536                                InlineDiagnostic {
15537                                    message,
15538                                    group_id: diagnostic_entry.diagnostic.group_id,
15539                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15540                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15541                                    severity: diagnostic_entry.diagnostic.severity,
15542                                },
15543                            ),
15544                        );
15545                    }
15546                    inline_diagnostics
15547                })
15548                .await;
15549
15550            editor
15551                .update(cx, |editor, cx| {
15552                    editor.inline_diagnostics = new_inline_diagnostics;
15553                    cx.notify();
15554                })
15555                .ok();
15556        });
15557    }
15558
15559    pub fn set_selections_from_remote(
15560        &mut self,
15561        selections: Vec<Selection<Anchor>>,
15562        pending_selection: Option<Selection<Anchor>>,
15563        window: &mut Window,
15564        cx: &mut Context<Self>,
15565    ) {
15566        let old_cursor_position = self.selections.newest_anchor().head();
15567        self.selections.change_with(cx, |s| {
15568            s.select_anchors(selections);
15569            if let Some(pending_selection) = pending_selection {
15570                s.set_pending(pending_selection, SelectMode::Character);
15571            } else {
15572                s.clear_pending();
15573            }
15574        });
15575        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15576    }
15577
15578    fn push_to_selection_history(&mut self) {
15579        self.selection_history.push(SelectionHistoryEntry {
15580            selections: self.selections.disjoint_anchors(),
15581            select_next_state: self.select_next_state.clone(),
15582            select_prev_state: self.select_prev_state.clone(),
15583            add_selections_state: self.add_selections_state.clone(),
15584        });
15585    }
15586
15587    pub fn transact(
15588        &mut self,
15589        window: &mut Window,
15590        cx: &mut Context<Self>,
15591        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15592    ) -> Option<TransactionId> {
15593        self.start_transaction_at(Instant::now(), window, cx);
15594        update(self, window, cx);
15595        self.end_transaction_at(Instant::now(), cx)
15596    }
15597
15598    pub fn start_transaction_at(
15599        &mut self,
15600        now: Instant,
15601        window: &mut Window,
15602        cx: &mut Context<Self>,
15603    ) {
15604        self.end_selection(window, cx);
15605        if let Some(tx_id) = self
15606            .buffer
15607            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15608        {
15609            self.selection_history
15610                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15611            cx.emit(EditorEvent::TransactionBegun {
15612                transaction_id: tx_id,
15613            })
15614        }
15615    }
15616
15617    pub fn end_transaction_at(
15618        &mut self,
15619        now: Instant,
15620        cx: &mut Context<Self>,
15621    ) -> Option<TransactionId> {
15622        if let Some(transaction_id) = self
15623            .buffer
15624            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15625        {
15626            if let Some((_, end_selections)) =
15627                self.selection_history.transaction_mut(transaction_id)
15628            {
15629                *end_selections = Some(self.selections.disjoint_anchors());
15630            } else {
15631                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15632            }
15633
15634            cx.emit(EditorEvent::Edited { transaction_id });
15635            Some(transaction_id)
15636        } else {
15637            None
15638        }
15639    }
15640
15641    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15642        if self.selection_mark_mode {
15643            self.change_selections(None, window, cx, |s| {
15644                s.move_with(|_, sel| {
15645                    sel.collapse_to(sel.head(), SelectionGoal::None);
15646                });
15647            })
15648        }
15649        self.selection_mark_mode = true;
15650        cx.notify();
15651    }
15652
15653    pub fn swap_selection_ends(
15654        &mut self,
15655        _: &actions::SwapSelectionEnds,
15656        window: &mut Window,
15657        cx: &mut Context<Self>,
15658    ) {
15659        self.change_selections(None, window, cx, |s| {
15660            s.move_with(|_, sel| {
15661                if sel.start != sel.end {
15662                    sel.reversed = !sel.reversed
15663                }
15664            });
15665        });
15666        self.request_autoscroll(Autoscroll::newest(), cx);
15667        cx.notify();
15668    }
15669
15670    pub fn toggle_fold(
15671        &mut self,
15672        _: &actions::ToggleFold,
15673        window: &mut Window,
15674        cx: &mut Context<Self>,
15675    ) {
15676        if self.is_singleton(cx) {
15677            let selection = self.selections.newest::<Point>(cx);
15678
15679            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15680            let range = if selection.is_empty() {
15681                let point = selection.head().to_display_point(&display_map);
15682                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15683                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15684                    .to_point(&display_map);
15685                start..end
15686            } else {
15687                selection.range()
15688            };
15689            if display_map.folds_in_range(range).next().is_some() {
15690                self.unfold_lines(&Default::default(), window, cx)
15691            } else {
15692                self.fold(&Default::default(), window, cx)
15693            }
15694        } else {
15695            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15696            let buffer_ids: HashSet<_> = self
15697                .selections
15698                .disjoint_anchor_ranges()
15699                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15700                .collect();
15701
15702            let should_unfold = buffer_ids
15703                .iter()
15704                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15705
15706            for buffer_id in buffer_ids {
15707                if should_unfold {
15708                    self.unfold_buffer(buffer_id, cx);
15709                } else {
15710                    self.fold_buffer(buffer_id, cx);
15711                }
15712            }
15713        }
15714    }
15715
15716    pub fn toggle_fold_recursive(
15717        &mut self,
15718        _: &actions::ToggleFoldRecursive,
15719        window: &mut Window,
15720        cx: &mut Context<Self>,
15721    ) {
15722        let selection = self.selections.newest::<Point>(cx);
15723
15724        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15725        let range = if selection.is_empty() {
15726            let point = selection.head().to_display_point(&display_map);
15727            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15728            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15729                .to_point(&display_map);
15730            start..end
15731        } else {
15732            selection.range()
15733        };
15734        if display_map.folds_in_range(range).next().is_some() {
15735            self.unfold_recursive(&Default::default(), window, cx)
15736        } else {
15737            self.fold_recursive(&Default::default(), window, cx)
15738        }
15739    }
15740
15741    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15742        if self.is_singleton(cx) {
15743            let mut to_fold = Vec::new();
15744            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15745            let selections = self.selections.all_adjusted(cx);
15746
15747            for selection in selections {
15748                let range = selection.range().sorted();
15749                let buffer_start_row = range.start.row;
15750
15751                if range.start.row != range.end.row {
15752                    let mut found = false;
15753                    let mut row = range.start.row;
15754                    while row <= range.end.row {
15755                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15756                        {
15757                            found = true;
15758                            row = crease.range().end.row + 1;
15759                            to_fold.push(crease);
15760                        } else {
15761                            row += 1
15762                        }
15763                    }
15764                    if found {
15765                        continue;
15766                    }
15767                }
15768
15769                for row in (0..=range.start.row).rev() {
15770                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15771                        if crease.range().end.row >= buffer_start_row {
15772                            to_fold.push(crease);
15773                            if row <= range.start.row {
15774                                break;
15775                            }
15776                        }
15777                    }
15778                }
15779            }
15780
15781            self.fold_creases(to_fold, true, window, cx);
15782        } else {
15783            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15784            let buffer_ids = self
15785                .selections
15786                .disjoint_anchor_ranges()
15787                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15788                .collect::<HashSet<_>>();
15789            for buffer_id in buffer_ids {
15790                self.fold_buffer(buffer_id, cx);
15791            }
15792        }
15793    }
15794
15795    fn fold_at_level(
15796        &mut self,
15797        fold_at: &FoldAtLevel,
15798        window: &mut Window,
15799        cx: &mut Context<Self>,
15800    ) {
15801        if !self.buffer.read(cx).is_singleton() {
15802            return;
15803        }
15804
15805        let fold_at_level = fold_at.0;
15806        let snapshot = self.buffer.read(cx).snapshot(cx);
15807        let mut to_fold = Vec::new();
15808        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15809
15810        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15811            while start_row < end_row {
15812                match self
15813                    .snapshot(window, cx)
15814                    .crease_for_buffer_row(MultiBufferRow(start_row))
15815                {
15816                    Some(crease) => {
15817                        let nested_start_row = crease.range().start.row + 1;
15818                        let nested_end_row = crease.range().end.row;
15819
15820                        if current_level < fold_at_level {
15821                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15822                        } else if current_level == fold_at_level {
15823                            to_fold.push(crease);
15824                        }
15825
15826                        start_row = nested_end_row + 1;
15827                    }
15828                    None => start_row += 1,
15829                }
15830            }
15831        }
15832
15833        self.fold_creases(to_fold, true, window, cx);
15834    }
15835
15836    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15837        if self.buffer.read(cx).is_singleton() {
15838            let mut fold_ranges = Vec::new();
15839            let snapshot = self.buffer.read(cx).snapshot(cx);
15840
15841            for row in 0..snapshot.max_row().0 {
15842                if let Some(foldable_range) = self
15843                    .snapshot(window, cx)
15844                    .crease_for_buffer_row(MultiBufferRow(row))
15845                {
15846                    fold_ranges.push(foldable_range);
15847                }
15848            }
15849
15850            self.fold_creases(fold_ranges, true, window, cx);
15851        } else {
15852            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15853                editor
15854                    .update_in(cx, |editor, _, cx| {
15855                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15856                            editor.fold_buffer(buffer_id, cx);
15857                        }
15858                    })
15859                    .ok();
15860            });
15861        }
15862    }
15863
15864    pub fn fold_function_bodies(
15865        &mut self,
15866        _: &actions::FoldFunctionBodies,
15867        window: &mut Window,
15868        cx: &mut Context<Self>,
15869    ) {
15870        let snapshot = self.buffer.read(cx).snapshot(cx);
15871
15872        let ranges = snapshot
15873            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15874            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15875            .collect::<Vec<_>>();
15876
15877        let creases = ranges
15878            .into_iter()
15879            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15880            .collect();
15881
15882        self.fold_creases(creases, true, window, cx);
15883    }
15884
15885    pub fn fold_recursive(
15886        &mut self,
15887        _: &actions::FoldRecursive,
15888        window: &mut Window,
15889        cx: &mut Context<Self>,
15890    ) {
15891        let mut to_fold = Vec::new();
15892        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15893        let selections = self.selections.all_adjusted(cx);
15894
15895        for selection in selections {
15896            let range = selection.range().sorted();
15897            let buffer_start_row = range.start.row;
15898
15899            if range.start.row != range.end.row {
15900                let mut found = false;
15901                for row in range.start.row..=range.end.row {
15902                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15903                        found = true;
15904                        to_fold.push(crease);
15905                    }
15906                }
15907                if found {
15908                    continue;
15909                }
15910            }
15911
15912            for row in (0..=range.start.row).rev() {
15913                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15914                    if crease.range().end.row >= buffer_start_row {
15915                        to_fold.push(crease);
15916                    } else {
15917                        break;
15918                    }
15919                }
15920            }
15921        }
15922
15923        self.fold_creases(to_fold, true, window, cx);
15924    }
15925
15926    pub fn fold_at(
15927        &mut self,
15928        buffer_row: MultiBufferRow,
15929        window: &mut Window,
15930        cx: &mut Context<Self>,
15931    ) {
15932        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15933
15934        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15935            let autoscroll = self
15936                .selections
15937                .all::<Point>(cx)
15938                .iter()
15939                .any(|selection| crease.range().overlaps(&selection.range()));
15940
15941            self.fold_creases(vec![crease], autoscroll, window, cx);
15942        }
15943    }
15944
15945    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15946        if self.is_singleton(cx) {
15947            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15948            let buffer = &display_map.buffer_snapshot;
15949            let selections = self.selections.all::<Point>(cx);
15950            let ranges = selections
15951                .iter()
15952                .map(|s| {
15953                    let range = s.display_range(&display_map).sorted();
15954                    let mut start = range.start.to_point(&display_map);
15955                    let mut end = range.end.to_point(&display_map);
15956                    start.column = 0;
15957                    end.column = buffer.line_len(MultiBufferRow(end.row));
15958                    start..end
15959                })
15960                .collect::<Vec<_>>();
15961
15962            self.unfold_ranges(&ranges, true, true, cx);
15963        } else {
15964            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15965            let buffer_ids = self
15966                .selections
15967                .disjoint_anchor_ranges()
15968                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15969                .collect::<HashSet<_>>();
15970            for buffer_id in buffer_ids {
15971                self.unfold_buffer(buffer_id, cx);
15972            }
15973        }
15974    }
15975
15976    pub fn unfold_recursive(
15977        &mut self,
15978        _: &UnfoldRecursive,
15979        _window: &mut Window,
15980        cx: &mut Context<Self>,
15981    ) {
15982        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15983        let selections = self.selections.all::<Point>(cx);
15984        let ranges = selections
15985            .iter()
15986            .map(|s| {
15987                let mut range = s.display_range(&display_map).sorted();
15988                *range.start.column_mut() = 0;
15989                *range.end.column_mut() = display_map.line_len(range.end.row());
15990                let start = range.start.to_point(&display_map);
15991                let end = range.end.to_point(&display_map);
15992                start..end
15993            })
15994            .collect::<Vec<_>>();
15995
15996        self.unfold_ranges(&ranges, true, true, cx);
15997    }
15998
15999    pub fn unfold_at(
16000        &mut self,
16001        buffer_row: MultiBufferRow,
16002        _window: &mut Window,
16003        cx: &mut Context<Self>,
16004    ) {
16005        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16006
16007        let intersection_range = Point::new(buffer_row.0, 0)
16008            ..Point::new(
16009                buffer_row.0,
16010                display_map.buffer_snapshot.line_len(buffer_row),
16011            );
16012
16013        let autoscroll = self
16014            .selections
16015            .all::<Point>(cx)
16016            .iter()
16017            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16018
16019        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16020    }
16021
16022    pub fn unfold_all(
16023        &mut self,
16024        _: &actions::UnfoldAll,
16025        _window: &mut Window,
16026        cx: &mut Context<Self>,
16027    ) {
16028        if self.buffer.read(cx).is_singleton() {
16029            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16030            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16031        } else {
16032            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16033                editor
16034                    .update(cx, |editor, cx| {
16035                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16036                            editor.unfold_buffer(buffer_id, cx);
16037                        }
16038                    })
16039                    .ok();
16040            });
16041        }
16042    }
16043
16044    pub fn fold_selected_ranges(
16045        &mut self,
16046        _: &FoldSelectedRanges,
16047        window: &mut Window,
16048        cx: &mut Context<Self>,
16049    ) {
16050        let selections = self.selections.all_adjusted(cx);
16051        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16052        let ranges = selections
16053            .into_iter()
16054            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16055            .collect::<Vec<_>>();
16056        self.fold_creases(ranges, true, window, cx);
16057    }
16058
16059    pub fn fold_ranges<T: ToOffset + Clone>(
16060        &mut self,
16061        ranges: Vec<Range<T>>,
16062        auto_scroll: bool,
16063        window: &mut Window,
16064        cx: &mut Context<Self>,
16065    ) {
16066        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16067        let ranges = ranges
16068            .into_iter()
16069            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16070            .collect::<Vec<_>>();
16071        self.fold_creases(ranges, auto_scroll, window, cx);
16072    }
16073
16074    pub fn fold_creases<T: ToOffset + Clone>(
16075        &mut self,
16076        creases: Vec<Crease<T>>,
16077        auto_scroll: bool,
16078        _window: &mut Window,
16079        cx: &mut Context<Self>,
16080    ) {
16081        if creases.is_empty() {
16082            return;
16083        }
16084
16085        let mut buffers_affected = HashSet::default();
16086        let multi_buffer = self.buffer().read(cx);
16087        for crease in &creases {
16088            if let Some((_, buffer, _)) =
16089                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16090            {
16091                buffers_affected.insert(buffer.read(cx).remote_id());
16092            };
16093        }
16094
16095        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16096
16097        if auto_scroll {
16098            self.request_autoscroll(Autoscroll::fit(), cx);
16099        }
16100
16101        cx.notify();
16102
16103        self.scrollbar_marker_state.dirty = true;
16104        self.folds_did_change(cx);
16105    }
16106
16107    /// Removes any folds whose ranges intersect any of the given ranges.
16108    pub fn unfold_ranges<T: ToOffset + Clone>(
16109        &mut self,
16110        ranges: &[Range<T>],
16111        inclusive: bool,
16112        auto_scroll: bool,
16113        cx: &mut Context<Self>,
16114    ) {
16115        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16116            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16117        });
16118        self.folds_did_change(cx);
16119    }
16120
16121    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16122        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16123            return;
16124        }
16125        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16126        self.display_map.update(cx, |display_map, cx| {
16127            display_map.fold_buffers([buffer_id], cx)
16128        });
16129        cx.emit(EditorEvent::BufferFoldToggled {
16130            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16131            folded: true,
16132        });
16133        cx.notify();
16134    }
16135
16136    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16137        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16138            return;
16139        }
16140        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16141        self.display_map.update(cx, |display_map, cx| {
16142            display_map.unfold_buffers([buffer_id], cx);
16143        });
16144        cx.emit(EditorEvent::BufferFoldToggled {
16145            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16146            folded: false,
16147        });
16148        cx.notify();
16149    }
16150
16151    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16152        self.display_map.read(cx).is_buffer_folded(buffer)
16153    }
16154
16155    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16156        self.display_map.read(cx).folded_buffers()
16157    }
16158
16159    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16160        self.display_map.update(cx, |display_map, cx| {
16161            display_map.disable_header_for_buffer(buffer_id, cx);
16162        });
16163        cx.notify();
16164    }
16165
16166    /// Removes any folds with the given ranges.
16167    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16168        &mut self,
16169        ranges: &[Range<T>],
16170        type_id: TypeId,
16171        auto_scroll: bool,
16172        cx: &mut Context<Self>,
16173    ) {
16174        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16175            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16176        });
16177        self.folds_did_change(cx);
16178    }
16179
16180    fn remove_folds_with<T: ToOffset + Clone>(
16181        &mut self,
16182        ranges: &[Range<T>],
16183        auto_scroll: bool,
16184        cx: &mut Context<Self>,
16185        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16186    ) {
16187        if ranges.is_empty() {
16188            return;
16189        }
16190
16191        let mut buffers_affected = HashSet::default();
16192        let multi_buffer = self.buffer().read(cx);
16193        for range in ranges {
16194            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16195                buffers_affected.insert(buffer.read(cx).remote_id());
16196            };
16197        }
16198
16199        self.display_map.update(cx, update);
16200
16201        if auto_scroll {
16202            self.request_autoscroll(Autoscroll::fit(), cx);
16203        }
16204
16205        cx.notify();
16206        self.scrollbar_marker_state.dirty = true;
16207        self.active_indent_guides_state.dirty = true;
16208    }
16209
16210    pub fn update_fold_widths(
16211        &mut self,
16212        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16213        cx: &mut Context<Self>,
16214    ) -> bool {
16215        self.display_map
16216            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16217    }
16218
16219    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16220        self.display_map.read(cx).fold_placeholder.clone()
16221    }
16222
16223    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16224        self.buffer.update(cx, |buffer, cx| {
16225            buffer.set_all_diff_hunks_expanded(cx);
16226        });
16227    }
16228
16229    pub fn expand_all_diff_hunks(
16230        &mut self,
16231        _: &ExpandAllDiffHunks,
16232        _window: &mut Window,
16233        cx: &mut Context<Self>,
16234    ) {
16235        self.buffer.update(cx, |buffer, cx| {
16236            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16237        });
16238    }
16239
16240    pub fn toggle_selected_diff_hunks(
16241        &mut self,
16242        _: &ToggleSelectedDiffHunks,
16243        _window: &mut Window,
16244        cx: &mut Context<Self>,
16245    ) {
16246        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16247        self.toggle_diff_hunks_in_ranges(ranges, cx);
16248    }
16249
16250    pub fn diff_hunks_in_ranges<'a>(
16251        &'a self,
16252        ranges: &'a [Range<Anchor>],
16253        buffer: &'a MultiBufferSnapshot,
16254    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16255        ranges.iter().flat_map(move |range| {
16256            let end_excerpt_id = range.end.excerpt_id;
16257            let range = range.to_point(buffer);
16258            let mut peek_end = range.end;
16259            if range.end.row < buffer.max_row().0 {
16260                peek_end = Point::new(range.end.row + 1, 0);
16261            }
16262            buffer
16263                .diff_hunks_in_range(range.start..peek_end)
16264                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16265        })
16266    }
16267
16268    pub fn has_stageable_diff_hunks_in_ranges(
16269        &self,
16270        ranges: &[Range<Anchor>],
16271        snapshot: &MultiBufferSnapshot,
16272    ) -> bool {
16273        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16274        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16275    }
16276
16277    pub fn toggle_staged_selected_diff_hunks(
16278        &mut self,
16279        _: &::git::ToggleStaged,
16280        _: &mut Window,
16281        cx: &mut Context<Self>,
16282    ) {
16283        let snapshot = self.buffer.read(cx).snapshot(cx);
16284        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16285        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16286        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16287    }
16288
16289    pub fn set_render_diff_hunk_controls(
16290        &mut self,
16291        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16292        cx: &mut Context<Self>,
16293    ) {
16294        self.render_diff_hunk_controls = render_diff_hunk_controls;
16295        cx.notify();
16296    }
16297
16298    pub fn stage_and_next(
16299        &mut self,
16300        _: &::git::StageAndNext,
16301        window: &mut Window,
16302        cx: &mut Context<Self>,
16303    ) {
16304        self.do_stage_or_unstage_and_next(true, window, cx);
16305    }
16306
16307    pub fn unstage_and_next(
16308        &mut self,
16309        _: &::git::UnstageAndNext,
16310        window: &mut Window,
16311        cx: &mut Context<Self>,
16312    ) {
16313        self.do_stage_or_unstage_and_next(false, window, cx);
16314    }
16315
16316    pub fn stage_or_unstage_diff_hunks(
16317        &mut self,
16318        stage: bool,
16319        ranges: Vec<Range<Anchor>>,
16320        cx: &mut Context<Self>,
16321    ) {
16322        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16323        cx.spawn(async move |this, cx| {
16324            task.await?;
16325            this.update(cx, |this, cx| {
16326                let snapshot = this.buffer.read(cx).snapshot(cx);
16327                let chunk_by = this
16328                    .diff_hunks_in_ranges(&ranges, &snapshot)
16329                    .chunk_by(|hunk| hunk.buffer_id);
16330                for (buffer_id, hunks) in &chunk_by {
16331                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16332                }
16333            })
16334        })
16335        .detach_and_log_err(cx);
16336    }
16337
16338    fn save_buffers_for_ranges_if_needed(
16339        &mut self,
16340        ranges: &[Range<Anchor>],
16341        cx: &mut Context<Editor>,
16342    ) -> Task<Result<()>> {
16343        let multibuffer = self.buffer.read(cx);
16344        let snapshot = multibuffer.read(cx);
16345        let buffer_ids: HashSet<_> = ranges
16346            .iter()
16347            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16348            .collect();
16349        drop(snapshot);
16350
16351        let mut buffers = HashSet::default();
16352        for buffer_id in buffer_ids {
16353            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16354                let buffer = buffer_entity.read(cx);
16355                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16356                {
16357                    buffers.insert(buffer_entity);
16358                }
16359            }
16360        }
16361
16362        if let Some(project) = &self.project {
16363            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16364        } else {
16365            Task::ready(Ok(()))
16366        }
16367    }
16368
16369    fn do_stage_or_unstage_and_next(
16370        &mut self,
16371        stage: bool,
16372        window: &mut Window,
16373        cx: &mut Context<Self>,
16374    ) {
16375        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16376
16377        if ranges.iter().any(|range| range.start != range.end) {
16378            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16379            return;
16380        }
16381
16382        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16383        let snapshot = self.snapshot(window, cx);
16384        let position = self.selections.newest::<Point>(cx).head();
16385        let mut row = snapshot
16386            .buffer_snapshot
16387            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16388            .find(|hunk| hunk.row_range.start.0 > position.row)
16389            .map(|hunk| hunk.row_range.start);
16390
16391        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16392        // Outside of the project diff editor, wrap around to the beginning.
16393        if !all_diff_hunks_expanded {
16394            row = row.or_else(|| {
16395                snapshot
16396                    .buffer_snapshot
16397                    .diff_hunks_in_range(Point::zero()..position)
16398                    .find(|hunk| hunk.row_range.end.0 < position.row)
16399                    .map(|hunk| hunk.row_range.start)
16400            });
16401        }
16402
16403        if let Some(row) = row {
16404            let destination = Point::new(row.0, 0);
16405            let autoscroll = Autoscroll::center();
16406
16407            self.unfold_ranges(&[destination..destination], false, false, cx);
16408            self.change_selections(Some(autoscroll), window, cx, |s| {
16409                s.select_ranges([destination..destination]);
16410            });
16411        }
16412    }
16413
16414    fn do_stage_or_unstage(
16415        &self,
16416        stage: bool,
16417        buffer_id: BufferId,
16418        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16419        cx: &mut App,
16420    ) -> Option<()> {
16421        let project = self.project.as_ref()?;
16422        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16423        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16424        let buffer_snapshot = buffer.read(cx).snapshot();
16425        let file_exists = buffer_snapshot
16426            .file()
16427            .is_some_and(|file| file.disk_state().exists());
16428        diff.update(cx, |diff, cx| {
16429            diff.stage_or_unstage_hunks(
16430                stage,
16431                &hunks
16432                    .map(|hunk| buffer_diff::DiffHunk {
16433                        buffer_range: hunk.buffer_range,
16434                        diff_base_byte_range: hunk.diff_base_byte_range,
16435                        secondary_status: hunk.secondary_status,
16436                        range: Point::zero()..Point::zero(), // unused
16437                    })
16438                    .collect::<Vec<_>>(),
16439                &buffer_snapshot,
16440                file_exists,
16441                cx,
16442            )
16443        });
16444        None
16445    }
16446
16447    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16448        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16449        self.buffer
16450            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16451    }
16452
16453    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16454        self.buffer.update(cx, |buffer, cx| {
16455            let ranges = vec![Anchor::min()..Anchor::max()];
16456            if !buffer.all_diff_hunks_expanded()
16457                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16458            {
16459                buffer.collapse_diff_hunks(ranges, cx);
16460                true
16461            } else {
16462                false
16463            }
16464        })
16465    }
16466
16467    fn toggle_diff_hunks_in_ranges(
16468        &mut self,
16469        ranges: Vec<Range<Anchor>>,
16470        cx: &mut Context<Editor>,
16471    ) {
16472        self.buffer.update(cx, |buffer, cx| {
16473            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16474            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16475        })
16476    }
16477
16478    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16479        self.buffer.update(cx, |buffer, cx| {
16480            let snapshot = buffer.snapshot(cx);
16481            let excerpt_id = range.end.excerpt_id;
16482            let point_range = range.to_point(&snapshot);
16483            let expand = !buffer.single_hunk_is_expanded(range, cx);
16484            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16485        })
16486    }
16487
16488    pub(crate) fn apply_all_diff_hunks(
16489        &mut self,
16490        _: &ApplyAllDiffHunks,
16491        window: &mut Window,
16492        cx: &mut Context<Self>,
16493    ) {
16494        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16495
16496        let buffers = self.buffer.read(cx).all_buffers();
16497        for branch_buffer in buffers {
16498            branch_buffer.update(cx, |branch_buffer, cx| {
16499                branch_buffer.merge_into_base(Vec::new(), cx);
16500            });
16501        }
16502
16503        if let Some(project) = self.project.clone() {
16504            self.save(true, project, window, cx).detach_and_log_err(cx);
16505        }
16506    }
16507
16508    pub(crate) fn apply_selected_diff_hunks(
16509        &mut self,
16510        _: &ApplyDiffHunk,
16511        window: &mut Window,
16512        cx: &mut Context<Self>,
16513    ) {
16514        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16515        let snapshot = self.snapshot(window, cx);
16516        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16517        let mut ranges_by_buffer = HashMap::default();
16518        self.transact(window, cx, |editor, _window, cx| {
16519            for hunk in hunks {
16520                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16521                    ranges_by_buffer
16522                        .entry(buffer.clone())
16523                        .or_insert_with(Vec::new)
16524                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16525                }
16526            }
16527
16528            for (buffer, ranges) in ranges_by_buffer {
16529                buffer.update(cx, |buffer, cx| {
16530                    buffer.merge_into_base(ranges, cx);
16531                });
16532            }
16533        });
16534
16535        if let Some(project) = self.project.clone() {
16536            self.save(true, project, window, cx).detach_and_log_err(cx);
16537        }
16538    }
16539
16540    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16541        if hovered != self.gutter_hovered {
16542            self.gutter_hovered = hovered;
16543            cx.notify();
16544        }
16545    }
16546
16547    pub fn insert_blocks(
16548        &mut self,
16549        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16550        autoscroll: Option<Autoscroll>,
16551        cx: &mut Context<Self>,
16552    ) -> Vec<CustomBlockId> {
16553        let blocks = self
16554            .display_map
16555            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16556        if let Some(autoscroll) = autoscroll {
16557            self.request_autoscroll(autoscroll, cx);
16558        }
16559        cx.notify();
16560        blocks
16561    }
16562
16563    pub fn resize_blocks(
16564        &mut self,
16565        heights: HashMap<CustomBlockId, u32>,
16566        autoscroll: Option<Autoscroll>,
16567        cx: &mut Context<Self>,
16568    ) {
16569        self.display_map
16570            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16571        if let Some(autoscroll) = autoscroll {
16572            self.request_autoscroll(autoscroll, cx);
16573        }
16574        cx.notify();
16575    }
16576
16577    pub fn replace_blocks(
16578        &mut self,
16579        renderers: HashMap<CustomBlockId, RenderBlock>,
16580        autoscroll: Option<Autoscroll>,
16581        cx: &mut Context<Self>,
16582    ) {
16583        self.display_map
16584            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16585        if let Some(autoscroll) = autoscroll {
16586            self.request_autoscroll(autoscroll, cx);
16587        }
16588        cx.notify();
16589    }
16590
16591    pub fn remove_blocks(
16592        &mut self,
16593        block_ids: HashSet<CustomBlockId>,
16594        autoscroll: Option<Autoscroll>,
16595        cx: &mut Context<Self>,
16596    ) {
16597        self.display_map.update(cx, |display_map, cx| {
16598            display_map.remove_blocks(block_ids, cx)
16599        });
16600        if let Some(autoscroll) = autoscroll {
16601            self.request_autoscroll(autoscroll, cx);
16602        }
16603        cx.notify();
16604    }
16605
16606    pub fn row_for_block(
16607        &self,
16608        block_id: CustomBlockId,
16609        cx: &mut Context<Self>,
16610    ) -> Option<DisplayRow> {
16611        self.display_map
16612            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16613    }
16614
16615    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16616        self.focused_block = Some(focused_block);
16617    }
16618
16619    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16620        self.focused_block.take()
16621    }
16622
16623    pub fn insert_creases(
16624        &mut self,
16625        creases: impl IntoIterator<Item = Crease<Anchor>>,
16626        cx: &mut Context<Self>,
16627    ) -> Vec<CreaseId> {
16628        self.display_map
16629            .update(cx, |map, cx| map.insert_creases(creases, cx))
16630    }
16631
16632    pub fn remove_creases(
16633        &mut self,
16634        ids: impl IntoIterator<Item = CreaseId>,
16635        cx: &mut Context<Self>,
16636    ) -> Vec<(CreaseId, Range<Anchor>)> {
16637        self.display_map
16638            .update(cx, |map, cx| map.remove_creases(ids, cx))
16639    }
16640
16641    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16642        self.display_map
16643            .update(cx, |map, cx| map.snapshot(cx))
16644            .longest_row()
16645    }
16646
16647    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16648        self.display_map
16649            .update(cx, |map, cx| map.snapshot(cx))
16650            .max_point()
16651    }
16652
16653    pub fn text(&self, cx: &App) -> String {
16654        self.buffer.read(cx).read(cx).text()
16655    }
16656
16657    pub fn is_empty(&self, cx: &App) -> bool {
16658        self.buffer.read(cx).read(cx).is_empty()
16659    }
16660
16661    pub fn text_option(&self, cx: &App) -> Option<String> {
16662        let text = self.text(cx);
16663        let text = text.trim();
16664
16665        if text.is_empty() {
16666            return None;
16667        }
16668
16669        Some(text.to_string())
16670    }
16671
16672    pub fn set_text(
16673        &mut self,
16674        text: impl Into<Arc<str>>,
16675        window: &mut Window,
16676        cx: &mut Context<Self>,
16677    ) {
16678        self.transact(window, cx, |this, _, cx| {
16679            this.buffer
16680                .read(cx)
16681                .as_singleton()
16682                .expect("you can only call set_text on editors for singleton buffers")
16683                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16684        });
16685    }
16686
16687    pub fn display_text(&self, cx: &mut App) -> String {
16688        self.display_map
16689            .update(cx, |map, cx| map.snapshot(cx))
16690            .text()
16691    }
16692
16693    fn create_minimap(
16694        &self,
16695        minimap_settings: MinimapSettings,
16696        window: &mut Window,
16697        cx: &mut Context<Self>,
16698    ) -> Option<Entity<Self>> {
16699        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16700            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16701    }
16702
16703    fn initialize_new_minimap(
16704        &self,
16705        minimap_settings: MinimapSettings,
16706        window: &mut Window,
16707        cx: &mut Context<Self>,
16708    ) -> Entity<Self> {
16709        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16710
16711        let mut minimap = Editor::new_internal(
16712            EditorMode::Minimap {
16713                parent: cx.weak_entity(),
16714            },
16715            self.buffer.clone(),
16716            self.project.clone(),
16717            Some(self.display_map.clone()),
16718            window,
16719            cx,
16720        );
16721        minimap.scroll_manager.clone_state(&self.scroll_manager);
16722        minimap.set_text_style_refinement(TextStyleRefinement {
16723            font_size: Some(MINIMAP_FONT_SIZE),
16724            font_weight: Some(MINIMAP_FONT_WEIGHT),
16725            ..Default::default()
16726        });
16727        minimap.update_minimap_configuration(minimap_settings, cx);
16728        cx.new(|_| minimap)
16729    }
16730
16731    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16732        let current_line_highlight = minimap_settings
16733            .current_line_highlight
16734            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16735        self.set_current_line_highlight(Some(current_line_highlight));
16736    }
16737
16738    pub fn minimap(&self) -> Option<&Entity<Self>> {
16739        self.minimap
16740            .as_ref()
16741            .filter(|_| self.minimap_visibility.visible())
16742    }
16743
16744    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16745        let mut wrap_guides = smallvec::smallvec![];
16746
16747        if self.show_wrap_guides == Some(false) {
16748            return wrap_guides;
16749        }
16750
16751        let settings = self.buffer.read(cx).language_settings(cx);
16752        if settings.show_wrap_guides {
16753            match self.soft_wrap_mode(cx) {
16754                SoftWrap::Column(soft_wrap) => {
16755                    wrap_guides.push((soft_wrap as usize, true));
16756                }
16757                SoftWrap::Bounded(soft_wrap) => {
16758                    wrap_guides.push((soft_wrap as usize, true));
16759                }
16760                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16761            }
16762            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16763        }
16764
16765        wrap_guides
16766    }
16767
16768    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16769        let settings = self.buffer.read(cx).language_settings(cx);
16770        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16771        match mode {
16772            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16773                SoftWrap::None
16774            }
16775            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16776            language_settings::SoftWrap::PreferredLineLength => {
16777                SoftWrap::Column(settings.preferred_line_length)
16778            }
16779            language_settings::SoftWrap::Bounded => {
16780                SoftWrap::Bounded(settings.preferred_line_length)
16781            }
16782        }
16783    }
16784
16785    pub fn set_soft_wrap_mode(
16786        &mut self,
16787        mode: language_settings::SoftWrap,
16788
16789        cx: &mut Context<Self>,
16790    ) {
16791        self.soft_wrap_mode_override = Some(mode);
16792        cx.notify();
16793    }
16794
16795    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16796        self.hard_wrap = hard_wrap;
16797        cx.notify();
16798    }
16799
16800    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16801        self.text_style_refinement = Some(style);
16802    }
16803
16804    /// called by the Element so we know what style we were most recently rendered with.
16805    pub(crate) fn set_style(
16806        &mut self,
16807        style: EditorStyle,
16808        window: &mut Window,
16809        cx: &mut Context<Self>,
16810    ) {
16811        // We intentionally do not inform the display map about the minimap style
16812        // so that wrapping is not recalculated and stays consistent for the editor
16813        // and its linked minimap.
16814        if !self.mode.is_minimap() {
16815            let rem_size = window.rem_size();
16816            self.display_map.update(cx, |map, cx| {
16817                map.set_font(
16818                    style.text.font(),
16819                    style.text.font_size.to_pixels(rem_size),
16820                    cx,
16821                )
16822            });
16823        }
16824        self.style = Some(style);
16825    }
16826
16827    pub fn style(&self) -> Option<&EditorStyle> {
16828        self.style.as_ref()
16829    }
16830
16831    // Called by the element. This method is not designed to be called outside of the editor
16832    // element's layout code because it does not notify when rewrapping is computed synchronously.
16833    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16834        self.display_map
16835            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16836    }
16837
16838    pub fn set_soft_wrap(&mut self) {
16839        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16840    }
16841
16842    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16843        if self.soft_wrap_mode_override.is_some() {
16844            self.soft_wrap_mode_override.take();
16845        } else {
16846            let soft_wrap = match self.soft_wrap_mode(cx) {
16847                SoftWrap::GitDiff => return,
16848                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16849                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16850                    language_settings::SoftWrap::None
16851                }
16852            };
16853            self.soft_wrap_mode_override = Some(soft_wrap);
16854        }
16855        cx.notify();
16856    }
16857
16858    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16859        let Some(workspace) = self.workspace() else {
16860            return;
16861        };
16862        let fs = workspace.read(cx).app_state().fs.clone();
16863        let current_show = TabBarSettings::get_global(cx).show;
16864        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16865            setting.show = Some(!current_show);
16866        });
16867    }
16868
16869    pub fn toggle_indent_guides(
16870        &mut self,
16871        _: &ToggleIndentGuides,
16872        _: &mut Window,
16873        cx: &mut Context<Self>,
16874    ) {
16875        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16876            self.buffer
16877                .read(cx)
16878                .language_settings(cx)
16879                .indent_guides
16880                .enabled
16881        });
16882        self.show_indent_guides = Some(!currently_enabled);
16883        cx.notify();
16884    }
16885
16886    fn should_show_indent_guides(&self) -> Option<bool> {
16887        self.show_indent_guides
16888    }
16889
16890    pub fn toggle_line_numbers(
16891        &mut self,
16892        _: &ToggleLineNumbers,
16893        _: &mut Window,
16894        cx: &mut Context<Self>,
16895    ) {
16896        let mut editor_settings = EditorSettings::get_global(cx).clone();
16897        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16898        EditorSettings::override_global(editor_settings, cx);
16899    }
16900
16901    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16902        if let Some(show_line_numbers) = self.show_line_numbers {
16903            return show_line_numbers;
16904        }
16905        EditorSettings::get_global(cx).gutter.line_numbers
16906    }
16907
16908    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16909        self.use_relative_line_numbers
16910            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16911    }
16912
16913    pub fn toggle_relative_line_numbers(
16914        &mut self,
16915        _: &ToggleRelativeLineNumbers,
16916        _: &mut Window,
16917        cx: &mut Context<Self>,
16918    ) {
16919        let is_relative = self.should_use_relative_line_numbers(cx);
16920        self.set_relative_line_number(Some(!is_relative), cx)
16921    }
16922
16923    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16924        self.use_relative_line_numbers = is_relative;
16925        cx.notify();
16926    }
16927
16928    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16929        self.show_gutter = show_gutter;
16930        cx.notify();
16931    }
16932
16933    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16934        self.show_scrollbars = show_scrollbars;
16935        cx.notify();
16936    }
16937
16938    pub fn set_minimap_visibility(
16939        &mut self,
16940        minimap_visibility: MinimapVisibility,
16941        window: &mut Window,
16942        cx: &mut Context<Self>,
16943    ) {
16944        if self.minimap_visibility != minimap_visibility {
16945            if minimap_visibility.visible() && self.minimap.is_none() {
16946                let minimap_settings = EditorSettings::get_global(cx).minimap;
16947                self.minimap =
16948                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16949            }
16950            self.minimap_visibility = minimap_visibility;
16951            cx.notify();
16952        }
16953    }
16954
16955    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16956        self.set_show_scrollbars(false, cx);
16957        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16958    }
16959
16960    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16961        self.show_line_numbers = Some(show_line_numbers);
16962        cx.notify();
16963    }
16964
16965    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16966        self.disable_expand_excerpt_buttons = true;
16967        cx.notify();
16968    }
16969
16970    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16971        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16972        cx.notify();
16973    }
16974
16975    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16976        self.show_code_actions = Some(show_code_actions);
16977        cx.notify();
16978    }
16979
16980    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16981        self.show_runnables = Some(show_runnables);
16982        cx.notify();
16983    }
16984
16985    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16986        self.show_breakpoints = Some(show_breakpoints);
16987        cx.notify();
16988    }
16989
16990    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16991        if self.display_map.read(cx).masked != masked {
16992            self.display_map.update(cx, |map, _| map.masked = masked);
16993        }
16994        cx.notify()
16995    }
16996
16997    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16998        self.show_wrap_guides = Some(show_wrap_guides);
16999        cx.notify();
17000    }
17001
17002    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17003        self.show_indent_guides = Some(show_indent_guides);
17004        cx.notify();
17005    }
17006
17007    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17008        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17009            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17010                if let Some(dir) = file.abs_path(cx).parent() {
17011                    return Some(dir.to_owned());
17012                }
17013            }
17014
17015            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17016                return Some(project_path.path.to_path_buf());
17017            }
17018        }
17019
17020        None
17021    }
17022
17023    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17024        self.active_excerpt(cx)?
17025            .1
17026            .read(cx)
17027            .file()
17028            .and_then(|f| f.as_local())
17029    }
17030
17031    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17032        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17033            let buffer = buffer.read(cx);
17034            if let Some(project_path) = buffer.project_path(cx) {
17035                let project = self.project.as_ref()?.read(cx);
17036                project.absolute_path(&project_path, cx)
17037            } else {
17038                buffer
17039                    .file()
17040                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17041            }
17042        })
17043    }
17044
17045    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17046        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17047            let project_path = buffer.read(cx).project_path(cx)?;
17048            let project = self.project.as_ref()?.read(cx);
17049            let entry = project.entry_for_path(&project_path, cx)?;
17050            let path = entry.path.to_path_buf();
17051            Some(path)
17052        })
17053    }
17054
17055    pub fn reveal_in_finder(
17056        &mut self,
17057        _: &RevealInFileManager,
17058        _window: &mut Window,
17059        cx: &mut Context<Self>,
17060    ) {
17061        if let Some(target) = self.target_file(cx) {
17062            cx.reveal_path(&target.abs_path(cx));
17063        }
17064    }
17065
17066    pub fn copy_path(
17067        &mut self,
17068        _: &zed_actions::workspace::CopyPath,
17069        _window: &mut Window,
17070        cx: &mut Context<Self>,
17071    ) {
17072        if let Some(path) = self.target_file_abs_path(cx) {
17073            if let Some(path) = path.to_str() {
17074                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17075            }
17076        }
17077    }
17078
17079    pub fn copy_relative_path(
17080        &mut self,
17081        _: &zed_actions::workspace::CopyRelativePath,
17082        _window: &mut Window,
17083        cx: &mut Context<Self>,
17084    ) {
17085        if let Some(path) = self.target_file_path(cx) {
17086            if let Some(path) = path.to_str() {
17087                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17088            }
17089        }
17090    }
17091
17092    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17093        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17094            buffer.read(cx).project_path(cx)
17095        } else {
17096            None
17097        }
17098    }
17099
17100    // Returns true if the editor handled a go-to-line request
17101    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17102        maybe!({
17103            let breakpoint_store = self.breakpoint_store.as_ref()?;
17104
17105            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17106            else {
17107                self.clear_row_highlights::<ActiveDebugLine>();
17108                return None;
17109            };
17110
17111            let position = active_stack_frame.position;
17112            let buffer_id = position.buffer_id?;
17113            let snapshot = self
17114                .project
17115                .as_ref()?
17116                .read(cx)
17117                .buffer_for_id(buffer_id, cx)?
17118                .read(cx)
17119                .snapshot();
17120
17121            let mut handled = false;
17122            for (id, ExcerptRange { context, .. }) in
17123                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17124            {
17125                if context.start.cmp(&position, &snapshot).is_ge()
17126                    || context.end.cmp(&position, &snapshot).is_lt()
17127                {
17128                    continue;
17129                }
17130                let snapshot = self.buffer.read(cx).snapshot(cx);
17131                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17132
17133                handled = true;
17134                self.clear_row_highlights::<ActiveDebugLine>();
17135
17136                self.go_to_line::<ActiveDebugLine>(
17137                    multibuffer_anchor,
17138                    Some(cx.theme().colors().editor_debugger_active_line_background),
17139                    window,
17140                    cx,
17141                );
17142
17143                cx.notify();
17144            }
17145
17146            handled.then_some(())
17147        })
17148        .is_some()
17149    }
17150
17151    pub fn copy_file_name_without_extension(
17152        &mut self,
17153        _: &CopyFileNameWithoutExtension,
17154        _: &mut Window,
17155        cx: &mut Context<Self>,
17156    ) {
17157        if let Some(file) = self.target_file(cx) {
17158            if let Some(file_stem) = file.path().file_stem() {
17159                if let Some(name) = file_stem.to_str() {
17160                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17161                }
17162            }
17163        }
17164    }
17165
17166    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17167        if let Some(file) = self.target_file(cx) {
17168            if let Some(file_name) = file.path().file_name() {
17169                if let Some(name) = file_name.to_str() {
17170                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17171                }
17172            }
17173        }
17174    }
17175
17176    pub fn toggle_git_blame(
17177        &mut self,
17178        _: &::git::Blame,
17179        window: &mut Window,
17180        cx: &mut Context<Self>,
17181    ) {
17182        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17183
17184        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17185            self.start_git_blame(true, window, cx);
17186        }
17187
17188        cx.notify();
17189    }
17190
17191    pub fn toggle_git_blame_inline(
17192        &mut self,
17193        _: &ToggleGitBlameInline,
17194        window: &mut Window,
17195        cx: &mut Context<Self>,
17196    ) {
17197        self.toggle_git_blame_inline_internal(true, window, cx);
17198        cx.notify();
17199    }
17200
17201    pub fn open_git_blame_commit(
17202        &mut self,
17203        _: &OpenGitBlameCommit,
17204        window: &mut Window,
17205        cx: &mut Context<Self>,
17206    ) {
17207        self.open_git_blame_commit_internal(window, cx);
17208    }
17209
17210    fn open_git_blame_commit_internal(
17211        &mut self,
17212        window: &mut Window,
17213        cx: &mut Context<Self>,
17214    ) -> Option<()> {
17215        let blame = self.blame.as_ref()?;
17216        let snapshot = self.snapshot(window, cx);
17217        let cursor = self.selections.newest::<Point>(cx).head();
17218        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17219        let blame_entry = blame
17220            .update(cx, |blame, cx| {
17221                blame
17222                    .blame_for_rows(
17223                        &[RowInfo {
17224                            buffer_id: Some(buffer.remote_id()),
17225                            buffer_row: Some(point.row),
17226                            ..Default::default()
17227                        }],
17228                        cx,
17229                    )
17230                    .next()
17231            })
17232            .flatten()?;
17233        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17234        let repo = blame.read(cx).repository(cx)?;
17235        let workspace = self.workspace()?.downgrade();
17236        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17237        None
17238    }
17239
17240    pub fn git_blame_inline_enabled(&self) -> bool {
17241        self.git_blame_inline_enabled
17242    }
17243
17244    pub fn toggle_selection_menu(
17245        &mut self,
17246        _: &ToggleSelectionMenu,
17247        _: &mut Window,
17248        cx: &mut Context<Self>,
17249    ) {
17250        self.show_selection_menu = self
17251            .show_selection_menu
17252            .map(|show_selections_menu| !show_selections_menu)
17253            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17254
17255        cx.notify();
17256    }
17257
17258    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17259        self.show_selection_menu
17260            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17261    }
17262
17263    fn start_git_blame(
17264        &mut self,
17265        user_triggered: bool,
17266        window: &mut Window,
17267        cx: &mut Context<Self>,
17268    ) {
17269        if let Some(project) = self.project.as_ref() {
17270            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17271                return;
17272            };
17273
17274            if buffer.read(cx).file().is_none() {
17275                return;
17276            }
17277
17278            let focused = self.focus_handle(cx).contains_focused(window, cx);
17279
17280            let project = project.clone();
17281            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17282            self.blame_subscription =
17283                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17284            self.blame = Some(blame);
17285        }
17286    }
17287
17288    fn toggle_git_blame_inline_internal(
17289        &mut self,
17290        user_triggered: bool,
17291        window: &mut Window,
17292        cx: &mut Context<Self>,
17293    ) {
17294        if self.git_blame_inline_enabled {
17295            self.git_blame_inline_enabled = false;
17296            self.show_git_blame_inline = false;
17297            self.show_git_blame_inline_delay_task.take();
17298        } else {
17299            self.git_blame_inline_enabled = true;
17300            self.start_git_blame_inline(user_triggered, window, cx);
17301        }
17302
17303        cx.notify();
17304    }
17305
17306    fn start_git_blame_inline(
17307        &mut self,
17308        user_triggered: bool,
17309        window: &mut Window,
17310        cx: &mut Context<Self>,
17311    ) {
17312        self.start_git_blame(user_triggered, window, cx);
17313
17314        if ProjectSettings::get_global(cx)
17315            .git
17316            .inline_blame_delay()
17317            .is_some()
17318        {
17319            self.start_inline_blame_timer(window, cx);
17320        } else {
17321            self.show_git_blame_inline = true
17322        }
17323    }
17324
17325    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17326        self.blame.as_ref()
17327    }
17328
17329    pub fn show_git_blame_gutter(&self) -> bool {
17330        self.show_git_blame_gutter
17331    }
17332
17333    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17334        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17335    }
17336
17337    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17338        self.show_git_blame_inline
17339            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17340            && !self.newest_selection_head_on_empty_line(cx)
17341            && self.has_blame_entries(cx)
17342    }
17343
17344    fn has_blame_entries(&self, cx: &App) -> bool {
17345        self.blame()
17346            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17347    }
17348
17349    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17350        let cursor_anchor = self.selections.newest_anchor().head();
17351
17352        let snapshot = self.buffer.read(cx).snapshot(cx);
17353        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17354
17355        snapshot.line_len(buffer_row) == 0
17356    }
17357
17358    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17359        let buffer_and_selection = maybe!({
17360            let selection = self.selections.newest::<Point>(cx);
17361            let selection_range = selection.range();
17362
17363            let multi_buffer = self.buffer().read(cx);
17364            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17365            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17366
17367            let (buffer, range, _) = if selection.reversed {
17368                buffer_ranges.first()
17369            } else {
17370                buffer_ranges.last()
17371            }?;
17372
17373            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17374                ..text::ToPoint::to_point(&range.end, &buffer).row;
17375            Some((
17376                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17377                selection,
17378            ))
17379        });
17380
17381        let Some((buffer, selection)) = buffer_and_selection else {
17382            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17383        };
17384
17385        let Some(project) = self.project.as_ref() else {
17386            return Task::ready(Err(anyhow!("editor does not have project")));
17387        };
17388
17389        project.update(cx, |project, cx| {
17390            project.get_permalink_to_line(&buffer, selection, cx)
17391        })
17392    }
17393
17394    pub fn copy_permalink_to_line(
17395        &mut self,
17396        _: &CopyPermalinkToLine,
17397        window: &mut Window,
17398        cx: &mut Context<Self>,
17399    ) {
17400        let permalink_task = self.get_permalink_to_line(cx);
17401        let workspace = self.workspace();
17402
17403        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17404            Ok(permalink) => {
17405                cx.update(|_, cx| {
17406                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17407                })
17408                .ok();
17409            }
17410            Err(err) => {
17411                let message = format!("Failed to copy permalink: {err}");
17412
17413                anyhow::Result::<()>::Err(err).log_err();
17414
17415                if let Some(workspace) = workspace {
17416                    workspace
17417                        .update_in(cx, |workspace, _, cx| {
17418                            struct CopyPermalinkToLine;
17419
17420                            workspace.show_toast(
17421                                Toast::new(
17422                                    NotificationId::unique::<CopyPermalinkToLine>(),
17423                                    message,
17424                                ),
17425                                cx,
17426                            )
17427                        })
17428                        .ok();
17429                }
17430            }
17431        })
17432        .detach();
17433    }
17434
17435    pub fn copy_file_location(
17436        &mut self,
17437        _: &CopyFileLocation,
17438        _: &mut Window,
17439        cx: &mut Context<Self>,
17440    ) {
17441        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17442        if let Some(file) = self.target_file(cx) {
17443            if let Some(path) = file.path().to_str() {
17444                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17445            }
17446        }
17447    }
17448
17449    pub fn open_permalink_to_line(
17450        &mut self,
17451        _: &OpenPermalinkToLine,
17452        window: &mut Window,
17453        cx: &mut Context<Self>,
17454    ) {
17455        let permalink_task = self.get_permalink_to_line(cx);
17456        let workspace = self.workspace();
17457
17458        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17459            Ok(permalink) => {
17460                cx.update(|_, cx| {
17461                    cx.open_url(permalink.as_ref());
17462                })
17463                .ok();
17464            }
17465            Err(err) => {
17466                let message = format!("Failed to open permalink: {err}");
17467
17468                anyhow::Result::<()>::Err(err).log_err();
17469
17470                if let Some(workspace) = workspace {
17471                    workspace
17472                        .update(cx, |workspace, cx| {
17473                            struct OpenPermalinkToLine;
17474
17475                            workspace.show_toast(
17476                                Toast::new(
17477                                    NotificationId::unique::<OpenPermalinkToLine>(),
17478                                    message,
17479                                ),
17480                                cx,
17481                            )
17482                        })
17483                        .ok();
17484                }
17485            }
17486        })
17487        .detach();
17488    }
17489
17490    pub fn insert_uuid_v4(
17491        &mut self,
17492        _: &InsertUuidV4,
17493        window: &mut Window,
17494        cx: &mut Context<Self>,
17495    ) {
17496        self.insert_uuid(UuidVersion::V4, window, cx);
17497    }
17498
17499    pub fn insert_uuid_v7(
17500        &mut self,
17501        _: &InsertUuidV7,
17502        window: &mut Window,
17503        cx: &mut Context<Self>,
17504    ) {
17505        self.insert_uuid(UuidVersion::V7, window, cx);
17506    }
17507
17508    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17509        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17510        self.transact(window, cx, |this, window, cx| {
17511            let edits = this
17512                .selections
17513                .all::<Point>(cx)
17514                .into_iter()
17515                .map(|selection| {
17516                    let uuid = match version {
17517                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17518                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17519                    };
17520
17521                    (selection.range(), uuid.to_string())
17522                });
17523            this.edit(edits, cx);
17524            this.refresh_inline_completion(true, false, window, cx);
17525        });
17526    }
17527
17528    pub fn open_selections_in_multibuffer(
17529        &mut self,
17530        _: &OpenSelectionsInMultibuffer,
17531        window: &mut Window,
17532        cx: &mut Context<Self>,
17533    ) {
17534        let multibuffer = self.buffer.read(cx);
17535
17536        let Some(buffer) = multibuffer.as_singleton() else {
17537            return;
17538        };
17539
17540        let Some(workspace) = self.workspace() else {
17541            return;
17542        };
17543
17544        let locations = self
17545            .selections
17546            .disjoint_anchors()
17547            .iter()
17548            .map(|range| Location {
17549                buffer: buffer.clone(),
17550                range: range.start.text_anchor..range.end.text_anchor,
17551            })
17552            .collect::<Vec<_>>();
17553
17554        let title = multibuffer.title(cx).to_string();
17555
17556        cx.spawn_in(window, async move |_, cx| {
17557            workspace.update_in(cx, |workspace, window, cx| {
17558                Self::open_locations_in_multibuffer(
17559                    workspace,
17560                    locations,
17561                    format!("Selections for '{title}'"),
17562                    false,
17563                    MultibufferSelectionMode::All,
17564                    window,
17565                    cx,
17566                );
17567            })
17568        })
17569        .detach();
17570    }
17571
17572    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17573    /// last highlight added will be used.
17574    ///
17575    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17576    pub fn highlight_rows<T: 'static>(
17577        &mut self,
17578        range: Range<Anchor>,
17579        color: Hsla,
17580        options: RowHighlightOptions,
17581        cx: &mut Context<Self>,
17582    ) {
17583        let snapshot = self.buffer().read(cx).snapshot(cx);
17584        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17585        let ix = row_highlights.binary_search_by(|highlight| {
17586            Ordering::Equal
17587                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17588                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17589        });
17590
17591        if let Err(mut ix) = ix {
17592            let index = post_inc(&mut self.highlight_order);
17593
17594            // If this range intersects with the preceding highlight, then merge it with
17595            // the preceding highlight. Otherwise insert a new highlight.
17596            let mut merged = false;
17597            if ix > 0 {
17598                let prev_highlight = &mut row_highlights[ix - 1];
17599                if prev_highlight
17600                    .range
17601                    .end
17602                    .cmp(&range.start, &snapshot)
17603                    .is_ge()
17604                {
17605                    ix -= 1;
17606                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17607                        prev_highlight.range.end = range.end;
17608                    }
17609                    merged = true;
17610                    prev_highlight.index = index;
17611                    prev_highlight.color = color;
17612                    prev_highlight.options = options;
17613                }
17614            }
17615
17616            if !merged {
17617                row_highlights.insert(
17618                    ix,
17619                    RowHighlight {
17620                        range: range.clone(),
17621                        index,
17622                        color,
17623                        options,
17624                        type_id: TypeId::of::<T>(),
17625                    },
17626                );
17627            }
17628
17629            // If any of the following highlights intersect with this one, merge them.
17630            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17631                let highlight = &row_highlights[ix];
17632                if next_highlight
17633                    .range
17634                    .start
17635                    .cmp(&highlight.range.end, &snapshot)
17636                    .is_le()
17637                {
17638                    if next_highlight
17639                        .range
17640                        .end
17641                        .cmp(&highlight.range.end, &snapshot)
17642                        .is_gt()
17643                    {
17644                        row_highlights[ix].range.end = next_highlight.range.end;
17645                    }
17646                    row_highlights.remove(ix + 1);
17647                } else {
17648                    break;
17649                }
17650            }
17651        }
17652    }
17653
17654    /// Remove any highlighted row ranges of the given type that intersect the
17655    /// given ranges.
17656    pub fn remove_highlighted_rows<T: 'static>(
17657        &mut self,
17658        ranges_to_remove: Vec<Range<Anchor>>,
17659        cx: &mut Context<Self>,
17660    ) {
17661        let snapshot = self.buffer().read(cx).snapshot(cx);
17662        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17663        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17664        row_highlights.retain(|highlight| {
17665            while let Some(range_to_remove) = ranges_to_remove.peek() {
17666                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17667                    Ordering::Less | Ordering::Equal => {
17668                        ranges_to_remove.next();
17669                    }
17670                    Ordering::Greater => {
17671                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17672                            Ordering::Less | Ordering::Equal => {
17673                                return false;
17674                            }
17675                            Ordering::Greater => break,
17676                        }
17677                    }
17678                }
17679            }
17680
17681            true
17682        })
17683    }
17684
17685    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17686    pub fn clear_row_highlights<T: 'static>(&mut self) {
17687        self.highlighted_rows.remove(&TypeId::of::<T>());
17688    }
17689
17690    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17691    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17692        self.highlighted_rows
17693            .get(&TypeId::of::<T>())
17694            .map_or(&[] as &[_], |vec| vec.as_slice())
17695            .iter()
17696            .map(|highlight| (highlight.range.clone(), highlight.color))
17697    }
17698
17699    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17700    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17701    /// Allows to ignore certain kinds of highlights.
17702    pub fn highlighted_display_rows(
17703        &self,
17704        window: &mut Window,
17705        cx: &mut App,
17706    ) -> BTreeMap<DisplayRow, LineHighlight> {
17707        let snapshot = self.snapshot(window, cx);
17708        let mut used_highlight_orders = HashMap::default();
17709        self.highlighted_rows
17710            .iter()
17711            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17712            .fold(
17713                BTreeMap::<DisplayRow, LineHighlight>::new(),
17714                |mut unique_rows, highlight| {
17715                    let start = highlight.range.start.to_display_point(&snapshot);
17716                    let end = highlight.range.end.to_display_point(&snapshot);
17717                    let start_row = start.row().0;
17718                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17719                        && end.column() == 0
17720                    {
17721                        end.row().0.saturating_sub(1)
17722                    } else {
17723                        end.row().0
17724                    };
17725                    for row in start_row..=end_row {
17726                        let used_index =
17727                            used_highlight_orders.entry(row).or_insert(highlight.index);
17728                        if highlight.index >= *used_index {
17729                            *used_index = highlight.index;
17730                            unique_rows.insert(
17731                                DisplayRow(row),
17732                                LineHighlight {
17733                                    include_gutter: highlight.options.include_gutter,
17734                                    border: None,
17735                                    background: highlight.color.into(),
17736                                    type_id: Some(highlight.type_id),
17737                                },
17738                            );
17739                        }
17740                    }
17741                    unique_rows
17742                },
17743            )
17744    }
17745
17746    pub fn highlighted_display_row_for_autoscroll(
17747        &self,
17748        snapshot: &DisplaySnapshot,
17749    ) -> Option<DisplayRow> {
17750        self.highlighted_rows
17751            .values()
17752            .flat_map(|highlighted_rows| highlighted_rows.iter())
17753            .filter_map(|highlight| {
17754                if highlight.options.autoscroll {
17755                    Some(highlight.range.start.to_display_point(snapshot).row())
17756                } else {
17757                    None
17758                }
17759            })
17760            .min()
17761    }
17762
17763    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17764        self.highlight_background::<SearchWithinRange>(
17765            ranges,
17766            |colors| colors.editor_document_highlight_read_background,
17767            cx,
17768        )
17769    }
17770
17771    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17772        self.breadcrumb_header = Some(new_header);
17773    }
17774
17775    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17776        self.clear_background_highlights::<SearchWithinRange>(cx);
17777    }
17778
17779    pub fn highlight_background<T: 'static>(
17780        &mut self,
17781        ranges: &[Range<Anchor>],
17782        color_fetcher: fn(&ThemeColors) -> Hsla,
17783        cx: &mut Context<Self>,
17784    ) {
17785        self.background_highlights
17786            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17787        self.scrollbar_marker_state.dirty = true;
17788        cx.notify();
17789    }
17790
17791    pub fn clear_background_highlights<T: 'static>(
17792        &mut self,
17793        cx: &mut Context<Self>,
17794    ) -> Option<BackgroundHighlight> {
17795        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17796        if !text_highlights.1.is_empty() {
17797            self.scrollbar_marker_state.dirty = true;
17798            cx.notify();
17799        }
17800        Some(text_highlights)
17801    }
17802
17803    pub fn highlight_gutter<T: 'static>(
17804        &mut self,
17805        ranges: &[Range<Anchor>],
17806        color_fetcher: fn(&App) -> Hsla,
17807        cx: &mut Context<Self>,
17808    ) {
17809        self.gutter_highlights
17810            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17811        cx.notify();
17812    }
17813
17814    pub fn clear_gutter_highlights<T: 'static>(
17815        &mut self,
17816        cx: &mut Context<Self>,
17817    ) -> Option<GutterHighlight> {
17818        cx.notify();
17819        self.gutter_highlights.remove(&TypeId::of::<T>())
17820    }
17821
17822    #[cfg(feature = "test-support")]
17823    pub fn all_text_background_highlights(
17824        &self,
17825        window: &mut Window,
17826        cx: &mut Context<Self>,
17827    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17828        let snapshot = self.snapshot(window, cx);
17829        let buffer = &snapshot.buffer_snapshot;
17830        let start = buffer.anchor_before(0);
17831        let end = buffer.anchor_after(buffer.len());
17832        let theme = cx.theme().colors();
17833        self.background_highlights_in_range(start..end, &snapshot, theme)
17834    }
17835
17836    #[cfg(feature = "test-support")]
17837    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17838        let snapshot = self.buffer().read(cx).snapshot(cx);
17839
17840        let highlights = self
17841            .background_highlights
17842            .get(&TypeId::of::<items::BufferSearchHighlights>());
17843
17844        if let Some((_color, ranges)) = highlights {
17845            ranges
17846                .iter()
17847                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17848                .collect_vec()
17849        } else {
17850            vec![]
17851        }
17852    }
17853
17854    fn document_highlights_for_position<'a>(
17855        &'a self,
17856        position: Anchor,
17857        buffer: &'a MultiBufferSnapshot,
17858    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17859        let read_highlights = self
17860            .background_highlights
17861            .get(&TypeId::of::<DocumentHighlightRead>())
17862            .map(|h| &h.1);
17863        let write_highlights = self
17864            .background_highlights
17865            .get(&TypeId::of::<DocumentHighlightWrite>())
17866            .map(|h| &h.1);
17867        let left_position = position.bias_left(buffer);
17868        let right_position = position.bias_right(buffer);
17869        read_highlights
17870            .into_iter()
17871            .chain(write_highlights)
17872            .flat_map(move |ranges| {
17873                let start_ix = match ranges.binary_search_by(|probe| {
17874                    let cmp = probe.end.cmp(&left_position, buffer);
17875                    if cmp.is_ge() {
17876                        Ordering::Greater
17877                    } else {
17878                        Ordering::Less
17879                    }
17880                }) {
17881                    Ok(i) | Err(i) => i,
17882                };
17883
17884                ranges[start_ix..]
17885                    .iter()
17886                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17887            })
17888    }
17889
17890    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17891        self.background_highlights
17892            .get(&TypeId::of::<T>())
17893            .map_or(false, |(_, highlights)| !highlights.is_empty())
17894    }
17895
17896    pub fn background_highlights_in_range(
17897        &self,
17898        search_range: Range<Anchor>,
17899        display_snapshot: &DisplaySnapshot,
17900        theme: &ThemeColors,
17901    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17902        let mut results = Vec::new();
17903        for (color_fetcher, ranges) in self.background_highlights.values() {
17904            let color = color_fetcher(theme);
17905            let start_ix = match ranges.binary_search_by(|probe| {
17906                let cmp = probe
17907                    .end
17908                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17909                if cmp.is_gt() {
17910                    Ordering::Greater
17911                } else {
17912                    Ordering::Less
17913                }
17914            }) {
17915                Ok(i) | Err(i) => i,
17916            };
17917            for range in &ranges[start_ix..] {
17918                if range
17919                    .start
17920                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17921                    .is_ge()
17922                {
17923                    break;
17924                }
17925
17926                let start = range.start.to_display_point(display_snapshot);
17927                let end = range.end.to_display_point(display_snapshot);
17928                results.push((start..end, color))
17929            }
17930        }
17931        results
17932    }
17933
17934    pub fn background_highlight_row_ranges<T: 'static>(
17935        &self,
17936        search_range: Range<Anchor>,
17937        display_snapshot: &DisplaySnapshot,
17938        count: usize,
17939    ) -> Vec<RangeInclusive<DisplayPoint>> {
17940        let mut results = Vec::new();
17941        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17942            return vec![];
17943        };
17944
17945        let start_ix = match ranges.binary_search_by(|probe| {
17946            let cmp = probe
17947                .end
17948                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17949            if cmp.is_gt() {
17950                Ordering::Greater
17951            } else {
17952                Ordering::Less
17953            }
17954        }) {
17955            Ok(i) | Err(i) => i,
17956        };
17957        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17958            if let (Some(start_display), Some(end_display)) = (start, end) {
17959                results.push(
17960                    start_display.to_display_point(display_snapshot)
17961                        ..=end_display.to_display_point(display_snapshot),
17962                );
17963            }
17964        };
17965        let mut start_row: Option<Point> = None;
17966        let mut end_row: Option<Point> = None;
17967        if ranges.len() > count {
17968            return Vec::new();
17969        }
17970        for range in &ranges[start_ix..] {
17971            if range
17972                .start
17973                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17974                .is_ge()
17975            {
17976                break;
17977            }
17978            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17979            if let Some(current_row) = &end_row {
17980                if end.row == current_row.row {
17981                    continue;
17982                }
17983            }
17984            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17985            if start_row.is_none() {
17986                assert_eq!(end_row, None);
17987                start_row = Some(start);
17988                end_row = Some(end);
17989                continue;
17990            }
17991            if let Some(current_end) = end_row.as_mut() {
17992                if start.row > current_end.row + 1 {
17993                    push_region(start_row, end_row);
17994                    start_row = Some(start);
17995                    end_row = Some(end);
17996                } else {
17997                    // Merge two hunks.
17998                    *current_end = end;
17999                }
18000            } else {
18001                unreachable!();
18002            }
18003        }
18004        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18005        push_region(start_row, end_row);
18006        results
18007    }
18008
18009    pub fn gutter_highlights_in_range(
18010        &self,
18011        search_range: Range<Anchor>,
18012        display_snapshot: &DisplaySnapshot,
18013        cx: &App,
18014    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18015        let mut results = Vec::new();
18016        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18017            let color = color_fetcher(cx);
18018            let start_ix = match ranges.binary_search_by(|probe| {
18019                let cmp = probe
18020                    .end
18021                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18022                if cmp.is_gt() {
18023                    Ordering::Greater
18024                } else {
18025                    Ordering::Less
18026                }
18027            }) {
18028                Ok(i) | Err(i) => i,
18029            };
18030            for range in &ranges[start_ix..] {
18031                if range
18032                    .start
18033                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18034                    .is_ge()
18035                {
18036                    break;
18037                }
18038
18039                let start = range.start.to_display_point(display_snapshot);
18040                let end = range.end.to_display_point(display_snapshot);
18041                results.push((start..end, color))
18042            }
18043        }
18044        results
18045    }
18046
18047    /// Get the text ranges corresponding to the redaction query
18048    pub fn redacted_ranges(
18049        &self,
18050        search_range: Range<Anchor>,
18051        display_snapshot: &DisplaySnapshot,
18052        cx: &App,
18053    ) -> Vec<Range<DisplayPoint>> {
18054        display_snapshot
18055            .buffer_snapshot
18056            .redacted_ranges(search_range, |file| {
18057                if let Some(file) = file {
18058                    file.is_private()
18059                        && EditorSettings::get(
18060                            Some(SettingsLocation {
18061                                worktree_id: file.worktree_id(cx),
18062                                path: file.path().as_ref(),
18063                            }),
18064                            cx,
18065                        )
18066                        .redact_private_values
18067                } else {
18068                    false
18069                }
18070            })
18071            .map(|range| {
18072                range.start.to_display_point(display_snapshot)
18073                    ..range.end.to_display_point(display_snapshot)
18074            })
18075            .collect()
18076    }
18077
18078    pub fn highlight_text<T: 'static>(
18079        &mut self,
18080        ranges: Vec<Range<Anchor>>,
18081        style: HighlightStyle,
18082        cx: &mut Context<Self>,
18083    ) {
18084        self.display_map.update(cx, |map, _| {
18085            map.highlight_text(TypeId::of::<T>(), ranges, style)
18086        });
18087        cx.notify();
18088    }
18089
18090    pub(crate) fn highlight_inlays<T: 'static>(
18091        &mut self,
18092        highlights: Vec<InlayHighlight>,
18093        style: HighlightStyle,
18094        cx: &mut Context<Self>,
18095    ) {
18096        self.display_map.update(cx, |map, _| {
18097            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18098        });
18099        cx.notify();
18100    }
18101
18102    pub fn text_highlights<'a, T: 'static>(
18103        &'a self,
18104        cx: &'a App,
18105    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18106        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18107    }
18108
18109    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18110        let cleared = self
18111            .display_map
18112            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18113        if cleared {
18114            cx.notify();
18115        }
18116    }
18117
18118    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18119        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18120            && self.focus_handle.is_focused(window)
18121    }
18122
18123    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18124        self.show_cursor_when_unfocused = is_enabled;
18125        cx.notify();
18126    }
18127
18128    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18129        cx.notify();
18130    }
18131
18132    fn on_debug_session_event(
18133        &mut self,
18134        _session: Entity<Session>,
18135        event: &SessionEvent,
18136        cx: &mut Context<Self>,
18137    ) {
18138        match event {
18139            SessionEvent::InvalidateInlineValue => {
18140                self.refresh_inline_values(cx);
18141            }
18142            _ => {}
18143        }
18144    }
18145
18146    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18147        let Some(project) = self.project.clone() else {
18148            return;
18149        };
18150
18151        if !self.inline_value_cache.enabled {
18152            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18153            self.splice_inlays(&inlays, Vec::new(), cx);
18154            return;
18155        }
18156
18157        let current_execution_position = self
18158            .highlighted_rows
18159            .get(&TypeId::of::<ActiveDebugLine>())
18160            .and_then(|lines| lines.last().map(|line| line.range.start));
18161
18162        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18163            let inline_values = editor
18164                .update(cx, |editor, cx| {
18165                    let Some(current_execution_position) = current_execution_position else {
18166                        return Some(Task::ready(Ok(Vec::new())));
18167                    };
18168
18169                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18170                        let snapshot = buffer.snapshot(cx);
18171
18172                        let excerpt = snapshot.excerpt_containing(
18173                            current_execution_position..current_execution_position,
18174                        )?;
18175
18176                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18177                    })?;
18178
18179                    let range =
18180                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18181
18182                    project.inline_values(buffer, range, cx)
18183                })
18184                .ok()
18185                .flatten()?
18186                .await
18187                .context("refreshing debugger inlays")
18188                .log_err()?;
18189
18190            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18191
18192            for (buffer_id, inline_value) in inline_values
18193                .into_iter()
18194                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18195            {
18196                buffer_inline_values
18197                    .entry(buffer_id)
18198                    .or_default()
18199                    .push(inline_value);
18200            }
18201
18202            editor
18203                .update(cx, |editor, cx| {
18204                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18205                    let mut new_inlays = Vec::default();
18206
18207                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18208                        let buffer_id = buffer_snapshot.remote_id();
18209                        buffer_inline_values
18210                            .get(&buffer_id)
18211                            .into_iter()
18212                            .flatten()
18213                            .for_each(|hint| {
18214                                let inlay = Inlay::debugger_hint(
18215                                    post_inc(&mut editor.next_inlay_id),
18216                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18217                                    hint.text(),
18218                                );
18219
18220                                new_inlays.push(inlay);
18221                            });
18222                    }
18223
18224                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18225                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18226
18227                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18228                })
18229                .ok()?;
18230            Some(())
18231        });
18232    }
18233
18234    fn on_buffer_event(
18235        &mut self,
18236        multibuffer: &Entity<MultiBuffer>,
18237        event: &multi_buffer::Event,
18238        window: &mut Window,
18239        cx: &mut Context<Self>,
18240    ) {
18241        match event {
18242            multi_buffer::Event::Edited {
18243                singleton_buffer_edited,
18244                edited_buffer: buffer_edited,
18245            } => {
18246                self.scrollbar_marker_state.dirty = true;
18247                self.active_indent_guides_state.dirty = true;
18248                self.refresh_active_diagnostics(cx);
18249                self.refresh_code_actions(window, cx);
18250                self.refresh_selected_text_highlights(true, window, cx);
18251                refresh_matching_bracket_highlights(self, window, cx);
18252                if self.has_active_inline_completion() {
18253                    self.update_visible_inline_completion(window, cx);
18254                }
18255                if let Some(buffer) = buffer_edited {
18256                    let buffer_id = buffer.read(cx).remote_id();
18257                    if !self.registered_buffers.contains_key(&buffer_id) {
18258                        if let Some(project) = self.project.as_ref() {
18259                            project.update(cx, |project, cx| {
18260                                self.registered_buffers.insert(
18261                                    buffer_id,
18262                                    project.register_buffer_with_language_servers(&buffer, cx),
18263                                );
18264                            })
18265                        }
18266                    }
18267                }
18268                cx.emit(EditorEvent::BufferEdited);
18269                cx.emit(SearchEvent::MatchesInvalidated);
18270                if *singleton_buffer_edited {
18271                    if let Some(project) = &self.project {
18272                        #[allow(clippy::mutable_key_type)]
18273                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18274                            multibuffer
18275                                .all_buffers()
18276                                .into_iter()
18277                                .filter_map(|buffer| {
18278                                    buffer.update(cx, |buffer, cx| {
18279                                        let language = buffer.language()?;
18280                                        let should_discard = project.update(cx, |project, cx| {
18281                                            project.is_local()
18282                                                && !project.has_language_servers_for(buffer, cx)
18283                                        });
18284                                        should_discard.not().then_some(language.clone())
18285                                    })
18286                                })
18287                                .collect::<HashSet<_>>()
18288                        });
18289                        if !languages_affected.is_empty() {
18290                            self.refresh_inlay_hints(
18291                                InlayHintRefreshReason::BufferEdited(languages_affected),
18292                                cx,
18293                            );
18294                        }
18295                    }
18296                }
18297
18298                let Some(project) = &self.project else { return };
18299                let (telemetry, is_via_ssh) = {
18300                    let project = project.read(cx);
18301                    let telemetry = project.client().telemetry().clone();
18302                    let is_via_ssh = project.is_via_ssh();
18303                    (telemetry, is_via_ssh)
18304                };
18305                refresh_linked_ranges(self, window, cx);
18306                telemetry.log_edit_event("editor", is_via_ssh);
18307            }
18308            multi_buffer::Event::ExcerptsAdded {
18309                buffer,
18310                predecessor,
18311                excerpts,
18312            } => {
18313                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18314                let buffer_id = buffer.read(cx).remote_id();
18315                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18316                    if let Some(project) = &self.project {
18317                        update_uncommitted_diff_for_buffer(
18318                            cx.entity(),
18319                            project,
18320                            [buffer.clone()],
18321                            self.buffer.clone(),
18322                            cx,
18323                        )
18324                        .detach();
18325                    }
18326                }
18327                cx.emit(EditorEvent::ExcerptsAdded {
18328                    buffer: buffer.clone(),
18329                    predecessor: *predecessor,
18330                    excerpts: excerpts.clone(),
18331                });
18332                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18333            }
18334            multi_buffer::Event::ExcerptsRemoved {
18335                ids,
18336                removed_buffer_ids,
18337            } => {
18338                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18339                let buffer = self.buffer.read(cx);
18340                self.registered_buffers
18341                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18342                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18343                cx.emit(EditorEvent::ExcerptsRemoved {
18344                    ids: ids.clone(),
18345                    removed_buffer_ids: removed_buffer_ids.clone(),
18346                })
18347            }
18348            multi_buffer::Event::ExcerptsEdited {
18349                excerpt_ids,
18350                buffer_ids,
18351            } => {
18352                self.display_map.update(cx, |map, cx| {
18353                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18354                });
18355                cx.emit(EditorEvent::ExcerptsEdited {
18356                    ids: excerpt_ids.clone(),
18357                })
18358            }
18359            multi_buffer::Event::ExcerptsExpanded { ids } => {
18360                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18361                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18362            }
18363            multi_buffer::Event::Reparsed(buffer_id) => {
18364                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18365                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18366
18367                cx.emit(EditorEvent::Reparsed(*buffer_id));
18368            }
18369            multi_buffer::Event::DiffHunksToggled => {
18370                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18371            }
18372            multi_buffer::Event::LanguageChanged(buffer_id) => {
18373                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18374                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18375                cx.emit(EditorEvent::Reparsed(*buffer_id));
18376                cx.notify();
18377            }
18378            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18379            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18380            multi_buffer::Event::FileHandleChanged
18381            | multi_buffer::Event::Reloaded
18382            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18383            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18384            multi_buffer::Event::DiagnosticsUpdated => {
18385                self.refresh_active_diagnostics(cx);
18386                self.refresh_inline_diagnostics(true, window, cx);
18387                self.scrollbar_marker_state.dirty = true;
18388                cx.notify();
18389            }
18390            _ => {}
18391        };
18392    }
18393
18394    pub fn start_temporary_diff_override(&mut self) {
18395        self.load_diff_task.take();
18396        self.temporary_diff_override = true;
18397    }
18398
18399    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18400        self.temporary_diff_override = false;
18401        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18402        self.buffer.update(cx, |buffer, cx| {
18403            buffer.set_all_diff_hunks_collapsed(cx);
18404        });
18405
18406        if let Some(project) = self.project.clone() {
18407            self.load_diff_task = Some(
18408                update_uncommitted_diff_for_buffer(
18409                    cx.entity(),
18410                    &project,
18411                    self.buffer.read(cx).all_buffers(),
18412                    self.buffer.clone(),
18413                    cx,
18414                )
18415                .shared(),
18416            );
18417        }
18418    }
18419
18420    fn on_display_map_changed(
18421        &mut self,
18422        _: Entity<DisplayMap>,
18423        _: &mut Window,
18424        cx: &mut Context<Self>,
18425    ) {
18426        cx.notify();
18427    }
18428
18429    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18430        let new_severity = if self.diagnostics_enabled() {
18431            EditorSettings::get_global(cx)
18432                .diagnostics_max_severity
18433                .unwrap_or(DiagnosticSeverity::Hint)
18434        } else {
18435            DiagnosticSeverity::Off
18436        };
18437        self.set_max_diagnostics_severity(new_severity, cx);
18438        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18439        self.update_edit_prediction_settings(cx);
18440        self.refresh_inline_completion(true, false, window, cx);
18441        self.refresh_inlay_hints(
18442            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18443                self.selections.newest_anchor().head(),
18444                &self.buffer.read(cx).snapshot(cx),
18445                cx,
18446            )),
18447            cx,
18448        );
18449
18450        let old_cursor_shape = self.cursor_shape;
18451
18452        {
18453            let editor_settings = EditorSettings::get_global(cx);
18454            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18455            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18456            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18457            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18458        }
18459
18460        if old_cursor_shape != self.cursor_shape {
18461            cx.emit(EditorEvent::CursorShapeChanged);
18462        }
18463
18464        let project_settings = ProjectSettings::get_global(cx);
18465        self.serialize_dirty_buffers =
18466            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18467
18468        if self.mode.is_full() {
18469            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18470            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18471            if self.show_inline_diagnostics != show_inline_diagnostics {
18472                self.show_inline_diagnostics = show_inline_diagnostics;
18473                self.refresh_inline_diagnostics(false, window, cx);
18474            }
18475
18476            if self.git_blame_inline_enabled != inline_blame_enabled {
18477                self.toggle_git_blame_inline_internal(false, window, cx);
18478            }
18479
18480            let minimap_settings = EditorSettings::get_global(cx).minimap;
18481            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18482                self.set_minimap_visibility(
18483                    self.minimap_visibility.toggle_visibility(),
18484                    window,
18485                    cx,
18486                );
18487            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18488                minimap_entity.update(cx, |minimap_editor, cx| {
18489                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18490                })
18491            }
18492        }
18493
18494        cx.notify();
18495    }
18496
18497    pub fn set_searchable(&mut self, searchable: bool) {
18498        self.searchable = searchable;
18499    }
18500
18501    pub fn searchable(&self) -> bool {
18502        self.searchable
18503    }
18504
18505    fn open_proposed_changes_editor(
18506        &mut self,
18507        _: &OpenProposedChangesEditor,
18508        window: &mut Window,
18509        cx: &mut Context<Self>,
18510    ) {
18511        let Some(workspace) = self.workspace() else {
18512            cx.propagate();
18513            return;
18514        };
18515
18516        let selections = self.selections.all::<usize>(cx);
18517        let multi_buffer = self.buffer.read(cx);
18518        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18519        let mut new_selections_by_buffer = HashMap::default();
18520        for selection in selections {
18521            for (buffer, range, _) in
18522                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18523            {
18524                let mut range = range.to_point(buffer);
18525                range.start.column = 0;
18526                range.end.column = buffer.line_len(range.end.row);
18527                new_selections_by_buffer
18528                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18529                    .or_insert(Vec::new())
18530                    .push(range)
18531            }
18532        }
18533
18534        let proposed_changes_buffers = new_selections_by_buffer
18535            .into_iter()
18536            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18537            .collect::<Vec<_>>();
18538        let proposed_changes_editor = cx.new(|cx| {
18539            ProposedChangesEditor::new(
18540                "Proposed changes",
18541                proposed_changes_buffers,
18542                self.project.clone(),
18543                window,
18544                cx,
18545            )
18546        });
18547
18548        window.defer(cx, move |window, cx| {
18549            workspace.update(cx, |workspace, cx| {
18550                workspace.active_pane().update(cx, |pane, cx| {
18551                    pane.add_item(
18552                        Box::new(proposed_changes_editor),
18553                        true,
18554                        true,
18555                        None,
18556                        window,
18557                        cx,
18558                    );
18559                });
18560            });
18561        });
18562    }
18563
18564    pub fn open_excerpts_in_split(
18565        &mut self,
18566        _: &OpenExcerptsSplit,
18567        window: &mut Window,
18568        cx: &mut Context<Self>,
18569    ) {
18570        self.open_excerpts_common(None, true, window, cx)
18571    }
18572
18573    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18574        self.open_excerpts_common(None, false, window, cx)
18575    }
18576
18577    fn open_excerpts_common(
18578        &mut self,
18579        jump_data: Option<JumpData>,
18580        split: bool,
18581        window: &mut Window,
18582        cx: &mut Context<Self>,
18583    ) {
18584        let Some(workspace) = self.workspace() else {
18585            cx.propagate();
18586            return;
18587        };
18588
18589        if self.buffer.read(cx).is_singleton() {
18590            cx.propagate();
18591            return;
18592        }
18593
18594        let mut new_selections_by_buffer = HashMap::default();
18595        match &jump_data {
18596            Some(JumpData::MultiBufferPoint {
18597                excerpt_id,
18598                position,
18599                anchor,
18600                line_offset_from_top,
18601            }) => {
18602                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18603                if let Some(buffer) = multi_buffer_snapshot
18604                    .buffer_id_for_excerpt(*excerpt_id)
18605                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18606                {
18607                    let buffer_snapshot = buffer.read(cx).snapshot();
18608                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18609                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18610                    } else {
18611                        buffer_snapshot.clip_point(*position, Bias::Left)
18612                    };
18613                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18614                    new_selections_by_buffer.insert(
18615                        buffer,
18616                        (
18617                            vec![jump_to_offset..jump_to_offset],
18618                            Some(*line_offset_from_top),
18619                        ),
18620                    );
18621                }
18622            }
18623            Some(JumpData::MultiBufferRow {
18624                row,
18625                line_offset_from_top,
18626            }) => {
18627                let point = MultiBufferPoint::new(row.0, 0);
18628                if let Some((buffer, buffer_point, _)) =
18629                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18630                {
18631                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18632                    new_selections_by_buffer
18633                        .entry(buffer)
18634                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18635                        .0
18636                        .push(buffer_offset..buffer_offset)
18637                }
18638            }
18639            None => {
18640                let selections = self.selections.all::<usize>(cx);
18641                let multi_buffer = self.buffer.read(cx);
18642                for selection in selections {
18643                    for (snapshot, range, _, anchor) in multi_buffer
18644                        .snapshot(cx)
18645                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18646                    {
18647                        if let Some(anchor) = anchor {
18648                            // selection is in a deleted hunk
18649                            let Some(buffer_id) = anchor.buffer_id else {
18650                                continue;
18651                            };
18652                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18653                                continue;
18654                            };
18655                            let offset = text::ToOffset::to_offset(
18656                                &anchor.text_anchor,
18657                                &buffer_handle.read(cx).snapshot(),
18658                            );
18659                            let range = offset..offset;
18660                            new_selections_by_buffer
18661                                .entry(buffer_handle)
18662                                .or_insert((Vec::new(), None))
18663                                .0
18664                                .push(range)
18665                        } else {
18666                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18667                            else {
18668                                continue;
18669                            };
18670                            new_selections_by_buffer
18671                                .entry(buffer_handle)
18672                                .or_insert((Vec::new(), None))
18673                                .0
18674                                .push(range)
18675                        }
18676                    }
18677                }
18678            }
18679        }
18680
18681        new_selections_by_buffer
18682            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18683
18684        if new_selections_by_buffer.is_empty() {
18685            return;
18686        }
18687
18688        // We defer the pane interaction because we ourselves are a workspace item
18689        // and activating a new item causes the pane to call a method on us reentrantly,
18690        // which panics if we're on the stack.
18691        window.defer(cx, move |window, cx| {
18692            workspace.update(cx, |workspace, cx| {
18693                let pane = if split {
18694                    workspace.adjacent_pane(window, cx)
18695                } else {
18696                    workspace.active_pane().clone()
18697                };
18698
18699                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18700                    let editor = buffer
18701                        .read(cx)
18702                        .file()
18703                        .is_none()
18704                        .then(|| {
18705                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18706                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18707                            // Instead, we try to activate the existing editor in the pane first.
18708                            let (editor, pane_item_index) =
18709                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18710                                    let editor = item.downcast::<Editor>()?;
18711                                    let singleton_buffer =
18712                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18713                                    if singleton_buffer == buffer {
18714                                        Some((editor, i))
18715                                    } else {
18716                                        None
18717                                    }
18718                                })?;
18719                            pane.update(cx, |pane, cx| {
18720                                pane.activate_item(pane_item_index, true, true, window, cx)
18721                            });
18722                            Some(editor)
18723                        })
18724                        .flatten()
18725                        .unwrap_or_else(|| {
18726                            workspace.open_project_item::<Self>(
18727                                pane.clone(),
18728                                buffer,
18729                                true,
18730                                true,
18731                                window,
18732                                cx,
18733                            )
18734                        });
18735
18736                    editor.update(cx, |editor, cx| {
18737                        let autoscroll = match scroll_offset {
18738                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18739                            None => Autoscroll::newest(),
18740                        };
18741                        let nav_history = editor.nav_history.take();
18742                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18743                            s.select_ranges(ranges);
18744                        });
18745                        editor.nav_history = nav_history;
18746                    });
18747                }
18748            })
18749        });
18750    }
18751
18752    // For now, don't allow opening excerpts in buffers that aren't backed by
18753    // regular project files.
18754    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18755        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18756    }
18757
18758    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18759        let snapshot = self.buffer.read(cx).read(cx);
18760        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18761        Some(
18762            ranges
18763                .iter()
18764                .map(move |range| {
18765                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18766                })
18767                .collect(),
18768        )
18769    }
18770
18771    fn selection_replacement_ranges(
18772        &self,
18773        range: Range<OffsetUtf16>,
18774        cx: &mut App,
18775    ) -> Vec<Range<OffsetUtf16>> {
18776        let selections = self.selections.all::<OffsetUtf16>(cx);
18777        let newest_selection = selections
18778            .iter()
18779            .max_by_key(|selection| selection.id)
18780            .unwrap();
18781        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18782        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18783        let snapshot = self.buffer.read(cx).read(cx);
18784        selections
18785            .into_iter()
18786            .map(|mut selection| {
18787                selection.start.0 =
18788                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18789                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18790                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18791                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18792            })
18793            .collect()
18794    }
18795
18796    fn report_editor_event(
18797        &self,
18798        event_type: &'static str,
18799        file_extension: Option<String>,
18800        cx: &App,
18801    ) {
18802        if cfg!(any(test, feature = "test-support")) {
18803            return;
18804        }
18805
18806        let Some(project) = &self.project else { return };
18807
18808        // If None, we are in a file without an extension
18809        let file = self
18810            .buffer
18811            .read(cx)
18812            .as_singleton()
18813            .and_then(|b| b.read(cx).file());
18814        let file_extension = file_extension.or(file
18815            .as_ref()
18816            .and_then(|file| Path::new(file.file_name(cx)).extension())
18817            .and_then(|e| e.to_str())
18818            .map(|a| a.to_string()));
18819
18820        let vim_mode = vim_enabled(cx);
18821
18822        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18823        let copilot_enabled = edit_predictions_provider
18824            == language::language_settings::EditPredictionProvider::Copilot;
18825        let copilot_enabled_for_language = self
18826            .buffer
18827            .read(cx)
18828            .language_settings(cx)
18829            .show_edit_predictions;
18830
18831        let project = project.read(cx);
18832        telemetry::event!(
18833            event_type,
18834            file_extension,
18835            vim_mode,
18836            copilot_enabled,
18837            copilot_enabled_for_language,
18838            edit_predictions_provider,
18839            is_via_ssh = project.is_via_ssh(),
18840        );
18841    }
18842
18843    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18844    /// with each line being an array of {text, highlight} objects.
18845    fn copy_highlight_json(
18846        &mut self,
18847        _: &CopyHighlightJson,
18848        window: &mut Window,
18849        cx: &mut Context<Self>,
18850    ) {
18851        #[derive(Serialize)]
18852        struct Chunk<'a> {
18853            text: String,
18854            highlight: Option<&'a str>,
18855        }
18856
18857        let snapshot = self.buffer.read(cx).snapshot(cx);
18858        let range = self
18859            .selected_text_range(false, window, cx)
18860            .and_then(|selection| {
18861                if selection.range.is_empty() {
18862                    None
18863                } else {
18864                    Some(selection.range)
18865                }
18866            })
18867            .unwrap_or_else(|| 0..snapshot.len());
18868
18869        let chunks = snapshot.chunks(range, true);
18870        let mut lines = Vec::new();
18871        let mut line: VecDeque<Chunk> = VecDeque::new();
18872
18873        let Some(style) = self.style.as_ref() else {
18874            return;
18875        };
18876
18877        for chunk in chunks {
18878            let highlight = chunk
18879                .syntax_highlight_id
18880                .and_then(|id| id.name(&style.syntax));
18881            let mut chunk_lines = chunk.text.split('\n').peekable();
18882            while let Some(text) = chunk_lines.next() {
18883                let mut merged_with_last_token = false;
18884                if let Some(last_token) = line.back_mut() {
18885                    if last_token.highlight == highlight {
18886                        last_token.text.push_str(text);
18887                        merged_with_last_token = true;
18888                    }
18889                }
18890
18891                if !merged_with_last_token {
18892                    line.push_back(Chunk {
18893                        text: text.into(),
18894                        highlight,
18895                    });
18896                }
18897
18898                if chunk_lines.peek().is_some() {
18899                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18900                        line.pop_front();
18901                    }
18902                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18903                        line.pop_back();
18904                    }
18905
18906                    lines.push(mem::take(&mut line));
18907                }
18908            }
18909        }
18910
18911        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18912            return;
18913        };
18914        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18915    }
18916
18917    pub fn open_context_menu(
18918        &mut self,
18919        _: &OpenContextMenu,
18920        window: &mut Window,
18921        cx: &mut Context<Self>,
18922    ) {
18923        self.request_autoscroll(Autoscroll::newest(), cx);
18924        let position = self.selections.newest_display(cx).start;
18925        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18926    }
18927
18928    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18929        &self.inlay_hint_cache
18930    }
18931
18932    pub fn replay_insert_event(
18933        &mut self,
18934        text: &str,
18935        relative_utf16_range: Option<Range<isize>>,
18936        window: &mut Window,
18937        cx: &mut Context<Self>,
18938    ) {
18939        if !self.input_enabled {
18940            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18941            return;
18942        }
18943        if let Some(relative_utf16_range) = relative_utf16_range {
18944            let selections = self.selections.all::<OffsetUtf16>(cx);
18945            self.change_selections(None, window, cx, |s| {
18946                let new_ranges = selections.into_iter().map(|range| {
18947                    let start = OffsetUtf16(
18948                        range
18949                            .head()
18950                            .0
18951                            .saturating_add_signed(relative_utf16_range.start),
18952                    );
18953                    let end = OffsetUtf16(
18954                        range
18955                            .head()
18956                            .0
18957                            .saturating_add_signed(relative_utf16_range.end),
18958                    );
18959                    start..end
18960                });
18961                s.select_ranges(new_ranges);
18962            });
18963        }
18964
18965        self.handle_input(text, window, cx);
18966    }
18967
18968    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18969        let Some(provider) = self.semantics_provider.as_ref() else {
18970            return false;
18971        };
18972
18973        let mut supports = false;
18974        self.buffer().update(cx, |this, cx| {
18975            this.for_each_buffer(|buffer| {
18976                supports |= provider.supports_inlay_hints(buffer, cx);
18977            });
18978        });
18979
18980        supports
18981    }
18982
18983    pub fn is_focused(&self, window: &Window) -> bool {
18984        self.focus_handle.is_focused(window)
18985    }
18986
18987    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18988        cx.emit(EditorEvent::Focused);
18989
18990        if let Some(descendant) = self
18991            .last_focused_descendant
18992            .take()
18993            .and_then(|descendant| descendant.upgrade())
18994        {
18995            window.focus(&descendant);
18996        } else {
18997            if let Some(blame) = self.blame.as_ref() {
18998                blame.update(cx, GitBlame::focus)
18999            }
19000
19001            self.blink_manager.update(cx, BlinkManager::enable);
19002            self.show_cursor_names(window, cx);
19003            self.buffer.update(cx, |buffer, cx| {
19004                buffer.finalize_last_transaction(cx);
19005                if self.leader_id.is_none() {
19006                    buffer.set_active_selections(
19007                        &self.selections.disjoint_anchors(),
19008                        self.selections.line_mode,
19009                        self.cursor_shape,
19010                        cx,
19011                    );
19012                }
19013            });
19014        }
19015    }
19016
19017    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19018        cx.emit(EditorEvent::FocusedIn)
19019    }
19020
19021    fn handle_focus_out(
19022        &mut self,
19023        event: FocusOutEvent,
19024        _window: &mut Window,
19025        cx: &mut Context<Self>,
19026    ) {
19027        if event.blurred != self.focus_handle {
19028            self.last_focused_descendant = Some(event.blurred);
19029        }
19030        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19031    }
19032
19033    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19034        self.blink_manager.update(cx, BlinkManager::disable);
19035        self.buffer
19036            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19037
19038        if let Some(blame) = self.blame.as_ref() {
19039            blame.update(cx, GitBlame::blur)
19040        }
19041        if !self.hover_state.focused(window, cx) {
19042            hide_hover(self, cx);
19043        }
19044        if !self
19045            .context_menu
19046            .borrow()
19047            .as_ref()
19048            .is_some_and(|context_menu| context_menu.focused(window, cx))
19049        {
19050            self.hide_context_menu(window, cx);
19051        }
19052        self.discard_inline_completion(false, cx);
19053        cx.emit(EditorEvent::Blurred);
19054        cx.notify();
19055    }
19056
19057    pub fn register_action<A: Action>(
19058        &mut self,
19059        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19060    ) -> Subscription {
19061        let id = self.next_editor_action_id.post_inc();
19062        let listener = Arc::new(listener);
19063        self.editor_actions.borrow_mut().insert(
19064            id,
19065            Box::new(move |window, _| {
19066                let listener = listener.clone();
19067                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19068                    let action = action.downcast_ref().unwrap();
19069                    if phase == DispatchPhase::Bubble {
19070                        listener(action, window, cx)
19071                    }
19072                })
19073            }),
19074        );
19075
19076        let editor_actions = self.editor_actions.clone();
19077        Subscription::new(move || {
19078            editor_actions.borrow_mut().remove(&id);
19079        })
19080    }
19081
19082    pub fn file_header_size(&self) -> u32 {
19083        FILE_HEADER_HEIGHT
19084    }
19085
19086    pub fn restore(
19087        &mut self,
19088        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19089        window: &mut Window,
19090        cx: &mut Context<Self>,
19091    ) {
19092        let workspace = self.workspace();
19093        let project = self.project.as_ref();
19094        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19095            let mut tasks = Vec::new();
19096            for (buffer_id, changes) in revert_changes {
19097                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19098                    buffer.update(cx, |buffer, cx| {
19099                        buffer.edit(
19100                            changes
19101                                .into_iter()
19102                                .map(|(range, text)| (range, text.to_string())),
19103                            None,
19104                            cx,
19105                        );
19106                    });
19107
19108                    if let Some(project) =
19109                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19110                    {
19111                        project.update(cx, |project, cx| {
19112                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19113                        })
19114                    }
19115                }
19116            }
19117            tasks
19118        });
19119        cx.spawn_in(window, async move |_, cx| {
19120            for (buffer, task) in save_tasks {
19121                let result = task.await;
19122                if result.is_err() {
19123                    let Some(path) = buffer
19124                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19125                        .ok()
19126                    else {
19127                        continue;
19128                    };
19129                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19130                        let Some(task) = cx
19131                            .update_window_entity(&workspace, |workspace, window, cx| {
19132                                workspace
19133                                    .open_path_preview(path, None, false, false, false, window, cx)
19134                            })
19135                            .ok()
19136                        else {
19137                            continue;
19138                        };
19139                        task.await.log_err();
19140                    }
19141                }
19142            }
19143        })
19144        .detach();
19145        self.change_selections(None, window, cx, |selections| selections.refresh());
19146    }
19147
19148    pub fn to_pixel_point(
19149        &self,
19150        source: multi_buffer::Anchor,
19151        editor_snapshot: &EditorSnapshot,
19152        window: &mut Window,
19153    ) -> Option<gpui::Point<Pixels>> {
19154        let source_point = source.to_display_point(editor_snapshot);
19155        self.display_to_pixel_point(source_point, editor_snapshot, window)
19156    }
19157
19158    pub fn display_to_pixel_point(
19159        &self,
19160        source: DisplayPoint,
19161        editor_snapshot: &EditorSnapshot,
19162        window: &mut Window,
19163    ) -> Option<gpui::Point<Pixels>> {
19164        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19165        let text_layout_details = self.text_layout_details(window);
19166        let scroll_top = text_layout_details
19167            .scroll_anchor
19168            .scroll_position(editor_snapshot)
19169            .y;
19170
19171        if source.row().as_f32() < scroll_top.floor() {
19172            return None;
19173        }
19174        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19175        let source_y = line_height * (source.row().as_f32() - scroll_top);
19176        Some(gpui::Point::new(source_x, source_y))
19177    }
19178
19179    pub fn has_visible_completions_menu(&self) -> bool {
19180        !self.edit_prediction_preview_is_active()
19181            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19182                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19183            })
19184    }
19185
19186    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19187        if self.mode.is_minimap() {
19188            return;
19189        }
19190        self.addons
19191            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19192    }
19193
19194    pub fn unregister_addon<T: Addon>(&mut self) {
19195        self.addons.remove(&std::any::TypeId::of::<T>());
19196    }
19197
19198    pub fn addon<T: Addon>(&self) -> Option<&T> {
19199        let type_id = std::any::TypeId::of::<T>();
19200        self.addons
19201            .get(&type_id)
19202            .and_then(|item| item.to_any().downcast_ref::<T>())
19203    }
19204
19205    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19206        let type_id = std::any::TypeId::of::<T>();
19207        self.addons
19208            .get_mut(&type_id)
19209            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19210    }
19211
19212    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19213        let text_layout_details = self.text_layout_details(window);
19214        let style = &text_layout_details.editor_style;
19215        let font_id = window.text_system().resolve_font(&style.text.font());
19216        let font_size = style.text.font_size.to_pixels(window.rem_size());
19217        let line_height = style.text.line_height_in_pixels(window.rem_size());
19218        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19219
19220        gpui::Size::new(em_width, line_height)
19221    }
19222
19223    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19224        self.load_diff_task.clone()
19225    }
19226
19227    fn read_metadata_from_db(
19228        &mut self,
19229        item_id: u64,
19230        workspace_id: WorkspaceId,
19231        window: &mut Window,
19232        cx: &mut Context<Editor>,
19233    ) {
19234        if self.is_singleton(cx)
19235            && !self.mode.is_minimap()
19236            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19237        {
19238            let buffer_snapshot = OnceCell::new();
19239
19240            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19241                if !folds.is_empty() {
19242                    let snapshot =
19243                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19244                    self.fold_ranges(
19245                        folds
19246                            .into_iter()
19247                            .map(|(start, end)| {
19248                                snapshot.clip_offset(start, Bias::Left)
19249                                    ..snapshot.clip_offset(end, Bias::Right)
19250                            })
19251                            .collect(),
19252                        false,
19253                        window,
19254                        cx,
19255                    );
19256                }
19257            }
19258
19259            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19260                if !selections.is_empty() {
19261                    let snapshot =
19262                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19263                    self.change_selections(None, window, cx, |s| {
19264                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19265                            snapshot.clip_offset(start, Bias::Left)
19266                                ..snapshot.clip_offset(end, Bias::Right)
19267                        }));
19268                    });
19269                }
19270            };
19271        }
19272
19273        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19274    }
19275}
19276
19277fn vim_enabled(cx: &App) -> bool {
19278    cx.global::<SettingsStore>()
19279        .raw_user_settings()
19280        .get("vim_mode")
19281        == Some(&serde_json::Value::Bool(true))
19282}
19283
19284// Consider user intent and default settings
19285fn choose_completion_range(
19286    completion: &Completion,
19287    intent: CompletionIntent,
19288    buffer: &Entity<Buffer>,
19289    cx: &mut Context<Editor>,
19290) -> Range<usize> {
19291    fn should_replace(
19292        completion: &Completion,
19293        insert_range: &Range<text::Anchor>,
19294        intent: CompletionIntent,
19295        completion_mode_setting: LspInsertMode,
19296        buffer: &Buffer,
19297    ) -> bool {
19298        // specific actions take precedence over settings
19299        match intent {
19300            CompletionIntent::CompleteWithInsert => return false,
19301            CompletionIntent::CompleteWithReplace => return true,
19302            CompletionIntent::Complete | CompletionIntent::Compose => {}
19303        }
19304
19305        match completion_mode_setting {
19306            LspInsertMode::Insert => false,
19307            LspInsertMode::Replace => true,
19308            LspInsertMode::ReplaceSubsequence => {
19309                let mut text_to_replace = buffer.chars_for_range(
19310                    buffer.anchor_before(completion.replace_range.start)
19311                        ..buffer.anchor_after(completion.replace_range.end),
19312                );
19313                let mut completion_text = completion.new_text.chars();
19314
19315                // is `text_to_replace` a subsequence of `completion_text`
19316                text_to_replace
19317                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19318            }
19319            LspInsertMode::ReplaceSuffix => {
19320                let range_after_cursor = insert_range.end..completion.replace_range.end;
19321
19322                let text_after_cursor = buffer
19323                    .text_for_range(
19324                        buffer.anchor_before(range_after_cursor.start)
19325                            ..buffer.anchor_after(range_after_cursor.end),
19326                    )
19327                    .collect::<String>();
19328                completion.new_text.ends_with(&text_after_cursor)
19329            }
19330        }
19331    }
19332
19333    let buffer = buffer.read(cx);
19334
19335    if let CompletionSource::Lsp {
19336        insert_range: Some(insert_range),
19337        ..
19338    } = &completion.source
19339    {
19340        let completion_mode_setting =
19341            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19342                .completions
19343                .lsp_insert_mode;
19344
19345        if !should_replace(
19346            completion,
19347            &insert_range,
19348            intent,
19349            completion_mode_setting,
19350            buffer,
19351        ) {
19352            return insert_range.to_offset(buffer);
19353        }
19354    }
19355
19356    completion.replace_range.to_offset(buffer)
19357}
19358
19359fn insert_extra_newline_brackets(
19360    buffer: &MultiBufferSnapshot,
19361    range: Range<usize>,
19362    language: &language::LanguageScope,
19363) -> bool {
19364    let leading_whitespace_len = buffer
19365        .reversed_chars_at(range.start)
19366        .take_while(|c| c.is_whitespace() && *c != '\n')
19367        .map(|c| c.len_utf8())
19368        .sum::<usize>();
19369    let trailing_whitespace_len = buffer
19370        .chars_at(range.end)
19371        .take_while(|c| c.is_whitespace() && *c != '\n')
19372        .map(|c| c.len_utf8())
19373        .sum::<usize>();
19374    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19375
19376    language.brackets().any(|(pair, enabled)| {
19377        let pair_start = pair.start.trim_end();
19378        let pair_end = pair.end.trim_start();
19379
19380        enabled
19381            && pair.newline
19382            && buffer.contains_str_at(range.end, pair_end)
19383            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19384    })
19385}
19386
19387fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19388    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19389        [(buffer, range, _)] => (*buffer, range.clone()),
19390        _ => return false,
19391    };
19392    let pair = {
19393        let mut result: Option<BracketMatch> = None;
19394
19395        for pair in buffer
19396            .all_bracket_ranges(range.clone())
19397            .filter(move |pair| {
19398                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19399            })
19400        {
19401            let len = pair.close_range.end - pair.open_range.start;
19402
19403            if let Some(existing) = &result {
19404                let existing_len = existing.close_range.end - existing.open_range.start;
19405                if len > existing_len {
19406                    continue;
19407                }
19408            }
19409
19410            result = Some(pair);
19411        }
19412
19413        result
19414    };
19415    let Some(pair) = pair else {
19416        return false;
19417    };
19418    pair.newline_only
19419        && buffer
19420            .chars_for_range(pair.open_range.end..range.start)
19421            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19422            .all(|c| c.is_whitespace() && c != '\n')
19423}
19424
19425fn update_uncommitted_diff_for_buffer(
19426    editor: Entity<Editor>,
19427    project: &Entity<Project>,
19428    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19429    buffer: Entity<MultiBuffer>,
19430    cx: &mut App,
19431) -> Task<()> {
19432    let mut tasks = Vec::new();
19433    project.update(cx, |project, cx| {
19434        for buffer in buffers {
19435            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19436                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19437            }
19438        }
19439    });
19440    cx.spawn(async move |cx| {
19441        let diffs = future::join_all(tasks).await;
19442        if editor
19443            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19444            .unwrap_or(false)
19445        {
19446            return;
19447        }
19448
19449        buffer
19450            .update(cx, |buffer, cx| {
19451                for diff in diffs.into_iter().flatten() {
19452                    buffer.add_diff(diff, cx);
19453                }
19454            })
19455            .ok();
19456    })
19457}
19458
19459fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19460    let tab_size = tab_size.get() as usize;
19461    let mut width = offset;
19462
19463    for ch in text.chars() {
19464        width += if ch == '\t' {
19465            tab_size - (width % tab_size)
19466        } else {
19467            1
19468        };
19469    }
19470
19471    width - offset
19472}
19473
19474#[cfg(test)]
19475mod tests {
19476    use super::*;
19477
19478    #[test]
19479    fn test_string_size_with_expanded_tabs() {
19480        let nz = |val| NonZeroU32::new(val).unwrap();
19481        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19482        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19483        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19484        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19485        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19486        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19487        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19488        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19489    }
19490}
19491
19492/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19493struct WordBreakingTokenizer<'a> {
19494    input: &'a str,
19495}
19496
19497impl<'a> WordBreakingTokenizer<'a> {
19498    fn new(input: &'a str) -> Self {
19499        Self { input }
19500    }
19501}
19502
19503fn is_char_ideographic(ch: char) -> bool {
19504    use unicode_script::Script::*;
19505    use unicode_script::UnicodeScript;
19506    matches!(ch.script(), Han | Tangut | Yi)
19507}
19508
19509fn is_grapheme_ideographic(text: &str) -> bool {
19510    text.chars().any(is_char_ideographic)
19511}
19512
19513fn is_grapheme_whitespace(text: &str) -> bool {
19514    text.chars().any(|x| x.is_whitespace())
19515}
19516
19517fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19518    text.chars().next().map_or(false, |ch| {
19519        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19520    })
19521}
19522
19523#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19524enum WordBreakToken<'a> {
19525    Word { token: &'a str, grapheme_len: usize },
19526    InlineWhitespace { token: &'a str, grapheme_len: usize },
19527    Newline,
19528}
19529
19530impl<'a> Iterator for WordBreakingTokenizer<'a> {
19531    /// Yields a span, the count of graphemes in the token, and whether it was
19532    /// whitespace. Note that it also breaks at word boundaries.
19533    type Item = WordBreakToken<'a>;
19534
19535    fn next(&mut self) -> Option<Self::Item> {
19536        use unicode_segmentation::UnicodeSegmentation;
19537        if self.input.is_empty() {
19538            return None;
19539        }
19540
19541        let mut iter = self.input.graphemes(true).peekable();
19542        let mut offset = 0;
19543        let mut grapheme_len = 0;
19544        if let Some(first_grapheme) = iter.next() {
19545            let is_newline = first_grapheme == "\n";
19546            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19547            offset += first_grapheme.len();
19548            grapheme_len += 1;
19549            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19550                if let Some(grapheme) = iter.peek().copied() {
19551                    if should_stay_with_preceding_ideograph(grapheme) {
19552                        offset += grapheme.len();
19553                        grapheme_len += 1;
19554                    }
19555                }
19556            } else {
19557                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19558                let mut next_word_bound = words.peek().copied();
19559                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19560                    next_word_bound = words.next();
19561                }
19562                while let Some(grapheme) = iter.peek().copied() {
19563                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19564                        break;
19565                    };
19566                    if is_grapheme_whitespace(grapheme) != is_whitespace
19567                        || (grapheme == "\n") != is_newline
19568                    {
19569                        break;
19570                    };
19571                    offset += grapheme.len();
19572                    grapheme_len += 1;
19573                    iter.next();
19574                }
19575            }
19576            let token = &self.input[..offset];
19577            self.input = &self.input[offset..];
19578            if token == "\n" {
19579                Some(WordBreakToken::Newline)
19580            } else if is_whitespace {
19581                Some(WordBreakToken::InlineWhitespace {
19582                    token,
19583                    grapheme_len,
19584                })
19585            } else {
19586                Some(WordBreakToken::Word {
19587                    token,
19588                    grapheme_len,
19589                })
19590            }
19591        } else {
19592            None
19593        }
19594    }
19595}
19596
19597#[test]
19598fn test_word_breaking_tokenizer() {
19599    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19600        ("", &[]),
19601        ("  ", &[whitespace("  ", 2)]),
19602        ("Ʒ", &[word("Ʒ", 1)]),
19603        ("Ǽ", &[word("Ǽ", 1)]),
19604        ("", &[word("", 1)]),
19605        ("⋑⋑", &[word("⋑⋑", 2)]),
19606        (
19607            "原理,进而",
19608            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19609        ),
19610        (
19611            "hello world",
19612            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19613        ),
19614        (
19615            "hello, world",
19616            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19617        ),
19618        (
19619            "  hello world",
19620            &[
19621                whitespace("  ", 2),
19622                word("hello", 5),
19623                whitespace(" ", 1),
19624                word("world", 5),
19625            ],
19626        ),
19627        (
19628            "这是什么 \n 钢笔",
19629            &[
19630                word("", 1),
19631                word("", 1),
19632                word("", 1),
19633                word("", 1),
19634                whitespace(" ", 1),
19635                newline(),
19636                whitespace(" ", 1),
19637                word("", 1),
19638                word("", 1),
19639            ],
19640        ),
19641        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19642    ];
19643
19644    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19645        WordBreakToken::Word {
19646            token,
19647            grapheme_len,
19648        }
19649    }
19650
19651    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19652        WordBreakToken::InlineWhitespace {
19653            token,
19654            grapheme_len,
19655        }
19656    }
19657
19658    fn newline() -> WordBreakToken<'static> {
19659        WordBreakToken::Newline
19660    }
19661
19662    for (input, result) in tests {
19663        assert_eq!(
19664            WordBreakingTokenizer::new(input)
19665                .collect::<Vec<_>>()
19666                .as_slice(),
19667            *result,
19668        );
19669    }
19670}
19671
19672fn wrap_with_prefix(
19673    line_prefix: String,
19674    unwrapped_text: String,
19675    wrap_column: usize,
19676    tab_size: NonZeroU32,
19677    preserve_existing_whitespace: bool,
19678) -> String {
19679    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19680    let mut wrapped_text = String::new();
19681    let mut current_line = line_prefix.clone();
19682
19683    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19684    let mut current_line_len = line_prefix_len;
19685    let mut in_whitespace = false;
19686    for token in tokenizer {
19687        let have_preceding_whitespace = in_whitespace;
19688        match token {
19689            WordBreakToken::Word {
19690                token,
19691                grapheme_len,
19692            } => {
19693                in_whitespace = false;
19694                if current_line_len + grapheme_len > wrap_column
19695                    && current_line_len != line_prefix_len
19696                {
19697                    wrapped_text.push_str(current_line.trim_end());
19698                    wrapped_text.push('\n');
19699                    current_line.truncate(line_prefix.len());
19700                    current_line_len = line_prefix_len;
19701                }
19702                current_line.push_str(token);
19703                current_line_len += grapheme_len;
19704            }
19705            WordBreakToken::InlineWhitespace {
19706                mut token,
19707                mut grapheme_len,
19708            } => {
19709                in_whitespace = true;
19710                if have_preceding_whitespace && !preserve_existing_whitespace {
19711                    continue;
19712                }
19713                if !preserve_existing_whitespace {
19714                    token = " ";
19715                    grapheme_len = 1;
19716                }
19717                if current_line_len + grapheme_len > wrap_column {
19718                    wrapped_text.push_str(current_line.trim_end());
19719                    wrapped_text.push('\n');
19720                    current_line.truncate(line_prefix.len());
19721                    current_line_len = line_prefix_len;
19722                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19723                    current_line.push_str(token);
19724                    current_line_len += grapheme_len;
19725                }
19726            }
19727            WordBreakToken::Newline => {
19728                in_whitespace = true;
19729                if preserve_existing_whitespace {
19730                    wrapped_text.push_str(current_line.trim_end());
19731                    wrapped_text.push('\n');
19732                    current_line.truncate(line_prefix.len());
19733                    current_line_len = line_prefix_len;
19734                } else if have_preceding_whitespace {
19735                    continue;
19736                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19737                {
19738                    wrapped_text.push_str(current_line.trim_end());
19739                    wrapped_text.push('\n');
19740                    current_line.truncate(line_prefix.len());
19741                    current_line_len = line_prefix_len;
19742                } else if current_line_len != line_prefix_len {
19743                    current_line.push(' ');
19744                    current_line_len += 1;
19745                }
19746            }
19747        }
19748    }
19749
19750    if !current_line.is_empty() {
19751        wrapped_text.push_str(&current_line);
19752    }
19753    wrapped_text
19754}
19755
19756#[test]
19757fn test_wrap_with_prefix() {
19758    assert_eq!(
19759        wrap_with_prefix(
19760            "# ".to_string(),
19761            "abcdefg".to_string(),
19762            4,
19763            NonZeroU32::new(4).unwrap(),
19764            false,
19765        ),
19766        "# abcdefg"
19767    );
19768    assert_eq!(
19769        wrap_with_prefix(
19770            "".to_string(),
19771            "\thello world".to_string(),
19772            8,
19773            NonZeroU32::new(4).unwrap(),
19774            false,
19775        ),
19776        "hello\nworld"
19777    );
19778    assert_eq!(
19779        wrap_with_prefix(
19780            "// ".to_string(),
19781            "xx \nyy zz aa bb cc".to_string(),
19782            12,
19783            NonZeroU32::new(4).unwrap(),
19784            false,
19785        ),
19786        "// xx yy zz\n// aa bb cc"
19787    );
19788    assert_eq!(
19789        wrap_with_prefix(
19790            String::new(),
19791            "这是什么 \n 钢笔".to_string(),
19792            3,
19793            NonZeroU32::new(4).unwrap(),
19794            false,
19795        ),
19796        "这是什\n么 钢\n"
19797    );
19798}
19799
19800pub trait CollaborationHub {
19801    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19802    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19803    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19804}
19805
19806impl CollaborationHub for Entity<Project> {
19807    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19808        self.read(cx).collaborators()
19809    }
19810
19811    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19812        self.read(cx).user_store().read(cx).participant_indices()
19813    }
19814
19815    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19816        let this = self.read(cx);
19817        let user_ids = this.collaborators().values().map(|c| c.user_id);
19818        this.user_store().read_with(cx, |user_store, cx| {
19819            user_store.participant_names(user_ids, cx)
19820        })
19821    }
19822}
19823
19824pub trait SemanticsProvider {
19825    fn hover(
19826        &self,
19827        buffer: &Entity<Buffer>,
19828        position: text::Anchor,
19829        cx: &mut App,
19830    ) -> Option<Task<Vec<project::Hover>>>;
19831
19832    fn inline_values(
19833        &self,
19834        buffer_handle: Entity<Buffer>,
19835        range: Range<text::Anchor>,
19836        cx: &mut App,
19837    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19838
19839    fn inlay_hints(
19840        &self,
19841        buffer_handle: Entity<Buffer>,
19842        range: Range<text::Anchor>,
19843        cx: &mut App,
19844    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19845
19846    fn resolve_inlay_hint(
19847        &self,
19848        hint: InlayHint,
19849        buffer_handle: Entity<Buffer>,
19850        server_id: LanguageServerId,
19851        cx: &mut App,
19852    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19853
19854    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19855
19856    fn document_highlights(
19857        &self,
19858        buffer: &Entity<Buffer>,
19859        position: text::Anchor,
19860        cx: &mut App,
19861    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19862
19863    fn definitions(
19864        &self,
19865        buffer: &Entity<Buffer>,
19866        position: text::Anchor,
19867        kind: GotoDefinitionKind,
19868        cx: &mut App,
19869    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19870
19871    fn range_for_rename(
19872        &self,
19873        buffer: &Entity<Buffer>,
19874        position: text::Anchor,
19875        cx: &mut App,
19876    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19877
19878    fn perform_rename(
19879        &self,
19880        buffer: &Entity<Buffer>,
19881        position: text::Anchor,
19882        new_name: String,
19883        cx: &mut App,
19884    ) -> Option<Task<Result<ProjectTransaction>>>;
19885}
19886
19887pub trait CompletionProvider {
19888    fn completions(
19889        &self,
19890        excerpt_id: ExcerptId,
19891        buffer: &Entity<Buffer>,
19892        buffer_position: text::Anchor,
19893        trigger: CompletionContext,
19894        window: &mut Window,
19895        cx: &mut Context<Editor>,
19896    ) -> Task<Result<Option<Vec<Completion>>>>;
19897
19898    fn resolve_completions(
19899        &self,
19900        buffer: Entity<Buffer>,
19901        completion_indices: Vec<usize>,
19902        completions: Rc<RefCell<Box<[Completion]>>>,
19903        cx: &mut Context<Editor>,
19904    ) -> Task<Result<bool>>;
19905
19906    fn apply_additional_edits_for_completion(
19907        &self,
19908        _buffer: Entity<Buffer>,
19909        _completions: Rc<RefCell<Box<[Completion]>>>,
19910        _completion_index: usize,
19911        _push_to_history: bool,
19912        _cx: &mut Context<Editor>,
19913    ) -> Task<Result<Option<language::Transaction>>> {
19914        Task::ready(Ok(None))
19915    }
19916
19917    fn is_completion_trigger(
19918        &self,
19919        buffer: &Entity<Buffer>,
19920        position: language::Anchor,
19921        text: &str,
19922        trigger_in_words: bool,
19923        cx: &mut Context<Editor>,
19924    ) -> bool;
19925
19926    fn sort_completions(&self) -> bool {
19927        true
19928    }
19929
19930    fn filter_completions(&self) -> bool {
19931        true
19932    }
19933}
19934
19935pub trait CodeActionProvider {
19936    fn id(&self) -> Arc<str>;
19937
19938    fn code_actions(
19939        &self,
19940        buffer: &Entity<Buffer>,
19941        range: Range<text::Anchor>,
19942        window: &mut Window,
19943        cx: &mut App,
19944    ) -> Task<Result<Vec<CodeAction>>>;
19945
19946    fn apply_code_action(
19947        &self,
19948        buffer_handle: Entity<Buffer>,
19949        action: CodeAction,
19950        excerpt_id: ExcerptId,
19951        push_to_history: bool,
19952        window: &mut Window,
19953        cx: &mut App,
19954    ) -> Task<Result<ProjectTransaction>>;
19955}
19956
19957impl CodeActionProvider for Entity<Project> {
19958    fn id(&self) -> Arc<str> {
19959        "project".into()
19960    }
19961
19962    fn code_actions(
19963        &self,
19964        buffer: &Entity<Buffer>,
19965        range: Range<text::Anchor>,
19966        _window: &mut Window,
19967        cx: &mut App,
19968    ) -> Task<Result<Vec<CodeAction>>> {
19969        self.update(cx, |project, cx| {
19970            let code_lens = project.code_lens(buffer, range.clone(), cx);
19971            let code_actions = project.code_actions(buffer, range, None, cx);
19972            cx.background_spawn(async move {
19973                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19974                Ok(code_lens
19975                    .context("code lens fetch")?
19976                    .into_iter()
19977                    .chain(code_actions.context("code action fetch")?)
19978                    .collect())
19979            })
19980        })
19981    }
19982
19983    fn apply_code_action(
19984        &self,
19985        buffer_handle: Entity<Buffer>,
19986        action: CodeAction,
19987        _excerpt_id: ExcerptId,
19988        push_to_history: bool,
19989        _window: &mut Window,
19990        cx: &mut App,
19991    ) -> Task<Result<ProjectTransaction>> {
19992        self.update(cx, |project, cx| {
19993            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19994        })
19995    }
19996}
19997
19998fn snippet_completions(
19999    project: &Project,
20000    buffer: &Entity<Buffer>,
20001    buffer_position: text::Anchor,
20002    cx: &mut App,
20003) -> Task<Result<Vec<Completion>>> {
20004    let languages = buffer.read(cx).languages_at(buffer_position);
20005    let snippet_store = project.snippets().read(cx);
20006
20007    let scopes: Vec<_> = languages
20008        .iter()
20009        .filter_map(|language| {
20010            let language_name = language.lsp_id();
20011            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20012
20013            if snippets.is_empty() {
20014                None
20015            } else {
20016                Some((language.default_scope(), snippets))
20017            }
20018        })
20019        .collect();
20020
20021    if scopes.is_empty() {
20022        return Task::ready(Ok(vec![]));
20023    }
20024
20025    let snapshot = buffer.read(cx).text_snapshot();
20026    let chars: String = snapshot
20027        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20028        .collect();
20029    let executor = cx.background_executor().clone();
20030
20031    cx.background_spawn(async move {
20032        let mut all_results: Vec<Completion> = Vec::new();
20033        for (scope, snippets) in scopes.into_iter() {
20034            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20035            let mut last_word = chars
20036                .chars()
20037                .take_while(|c| classifier.is_word(*c))
20038                .collect::<String>();
20039            last_word = last_word.chars().rev().collect();
20040
20041            if last_word.is_empty() {
20042                return Ok(vec![]);
20043            }
20044
20045            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20046            let to_lsp = |point: &text::Anchor| {
20047                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20048                point_to_lsp(end)
20049            };
20050            let lsp_end = to_lsp(&buffer_position);
20051
20052            let candidates = snippets
20053                .iter()
20054                .enumerate()
20055                .flat_map(|(ix, snippet)| {
20056                    snippet
20057                        .prefix
20058                        .iter()
20059                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20060                })
20061                .collect::<Vec<StringMatchCandidate>>();
20062
20063            let mut matches = fuzzy::match_strings(
20064                &candidates,
20065                &last_word,
20066                last_word.chars().any(|c| c.is_uppercase()),
20067                100,
20068                &Default::default(),
20069                executor.clone(),
20070            )
20071            .await;
20072
20073            // Remove all candidates where the query's start does not match the start of any word in the candidate
20074            if let Some(query_start) = last_word.chars().next() {
20075                matches.retain(|string_match| {
20076                    split_words(&string_match.string).any(|word| {
20077                        // Check that the first codepoint of the word as lowercase matches the first
20078                        // codepoint of the query as lowercase
20079                        word.chars()
20080                            .flat_map(|codepoint| codepoint.to_lowercase())
20081                            .zip(query_start.to_lowercase())
20082                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20083                    })
20084                });
20085            }
20086
20087            let matched_strings = matches
20088                .into_iter()
20089                .map(|m| m.string)
20090                .collect::<HashSet<_>>();
20091
20092            let mut result: Vec<Completion> = snippets
20093                .iter()
20094                .filter_map(|snippet| {
20095                    let matching_prefix = snippet
20096                        .prefix
20097                        .iter()
20098                        .find(|prefix| matched_strings.contains(*prefix))?;
20099                    let start = as_offset - last_word.len();
20100                    let start = snapshot.anchor_before(start);
20101                    let range = start..buffer_position;
20102                    let lsp_start = to_lsp(&start);
20103                    let lsp_range = lsp::Range {
20104                        start: lsp_start,
20105                        end: lsp_end,
20106                    };
20107                    Some(Completion {
20108                        replace_range: range,
20109                        new_text: snippet.body.clone(),
20110                        source: CompletionSource::Lsp {
20111                            insert_range: None,
20112                            server_id: LanguageServerId(usize::MAX),
20113                            resolved: true,
20114                            lsp_completion: Box::new(lsp::CompletionItem {
20115                                label: snippet.prefix.first().unwrap().clone(),
20116                                kind: Some(CompletionItemKind::SNIPPET),
20117                                label_details: snippet.description.as_ref().map(|description| {
20118                                    lsp::CompletionItemLabelDetails {
20119                                        detail: Some(description.clone()),
20120                                        description: None,
20121                                    }
20122                                }),
20123                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20124                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20125                                    lsp::InsertReplaceEdit {
20126                                        new_text: snippet.body.clone(),
20127                                        insert: lsp_range,
20128                                        replace: lsp_range,
20129                                    },
20130                                )),
20131                                filter_text: Some(snippet.body.clone()),
20132                                sort_text: Some(char::MAX.to_string()),
20133                                ..lsp::CompletionItem::default()
20134                            }),
20135                            lsp_defaults: None,
20136                        },
20137                        label: CodeLabel {
20138                            text: matching_prefix.clone(),
20139                            runs: Vec::new(),
20140                            filter_range: 0..matching_prefix.len(),
20141                        },
20142                        icon_path: None,
20143                        documentation: Some(
20144                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20145                                single_line: snippet.name.clone().into(),
20146                                plain_text: snippet
20147                                    .description
20148                                    .clone()
20149                                    .map(|description| description.into()),
20150                            },
20151                        ),
20152                        insert_text_mode: None,
20153                        confirm: None,
20154                    })
20155                })
20156                .collect();
20157
20158            all_results.append(&mut result);
20159        }
20160
20161        Ok(all_results)
20162    })
20163}
20164
20165impl CompletionProvider for Entity<Project> {
20166    fn completions(
20167        &self,
20168        _excerpt_id: ExcerptId,
20169        buffer: &Entity<Buffer>,
20170        buffer_position: text::Anchor,
20171        options: CompletionContext,
20172        _window: &mut Window,
20173        cx: &mut Context<Editor>,
20174    ) -> Task<Result<Option<Vec<Completion>>>> {
20175        self.update(cx, |project, cx| {
20176            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20177            let project_completions = project.completions(buffer, buffer_position, options, cx);
20178            cx.background_spawn(async move {
20179                let snippets_completions = snippets.await?;
20180                match project_completions.await? {
20181                    Some(mut completions) => {
20182                        completions.extend(snippets_completions);
20183                        Ok(Some(completions))
20184                    }
20185                    None => {
20186                        if snippets_completions.is_empty() {
20187                            Ok(None)
20188                        } else {
20189                            Ok(Some(snippets_completions))
20190                        }
20191                    }
20192                }
20193            })
20194        })
20195    }
20196
20197    fn resolve_completions(
20198        &self,
20199        buffer: Entity<Buffer>,
20200        completion_indices: Vec<usize>,
20201        completions: Rc<RefCell<Box<[Completion]>>>,
20202        cx: &mut Context<Editor>,
20203    ) -> Task<Result<bool>> {
20204        self.update(cx, |project, cx| {
20205            project.lsp_store().update(cx, |lsp_store, cx| {
20206                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20207            })
20208        })
20209    }
20210
20211    fn apply_additional_edits_for_completion(
20212        &self,
20213        buffer: Entity<Buffer>,
20214        completions: Rc<RefCell<Box<[Completion]>>>,
20215        completion_index: usize,
20216        push_to_history: bool,
20217        cx: &mut Context<Editor>,
20218    ) -> Task<Result<Option<language::Transaction>>> {
20219        self.update(cx, |project, cx| {
20220            project.lsp_store().update(cx, |lsp_store, cx| {
20221                lsp_store.apply_additional_edits_for_completion(
20222                    buffer,
20223                    completions,
20224                    completion_index,
20225                    push_to_history,
20226                    cx,
20227                )
20228            })
20229        })
20230    }
20231
20232    fn is_completion_trigger(
20233        &self,
20234        buffer: &Entity<Buffer>,
20235        position: language::Anchor,
20236        text: &str,
20237        trigger_in_words: bool,
20238        cx: &mut Context<Editor>,
20239    ) -> bool {
20240        let mut chars = text.chars();
20241        let char = if let Some(char) = chars.next() {
20242            char
20243        } else {
20244            return false;
20245        };
20246        if chars.next().is_some() {
20247            return false;
20248        }
20249
20250        let buffer = buffer.read(cx);
20251        let snapshot = buffer.snapshot();
20252        if !snapshot.settings_at(position, cx).show_completions_on_input {
20253            return false;
20254        }
20255        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20256        if trigger_in_words && classifier.is_word(char) {
20257            return true;
20258        }
20259
20260        buffer.completion_triggers().contains(text)
20261    }
20262}
20263
20264impl SemanticsProvider for Entity<Project> {
20265    fn hover(
20266        &self,
20267        buffer: &Entity<Buffer>,
20268        position: text::Anchor,
20269        cx: &mut App,
20270    ) -> Option<Task<Vec<project::Hover>>> {
20271        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20272    }
20273
20274    fn document_highlights(
20275        &self,
20276        buffer: &Entity<Buffer>,
20277        position: text::Anchor,
20278        cx: &mut App,
20279    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20280        Some(self.update(cx, |project, cx| {
20281            project.document_highlights(buffer, position, cx)
20282        }))
20283    }
20284
20285    fn definitions(
20286        &self,
20287        buffer: &Entity<Buffer>,
20288        position: text::Anchor,
20289        kind: GotoDefinitionKind,
20290        cx: &mut App,
20291    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20292        Some(self.update(cx, |project, cx| match kind {
20293            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20294            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20295            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20296            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20297        }))
20298    }
20299
20300    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20301        // TODO: make this work for remote projects
20302        self.update(cx, |project, cx| {
20303            if project
20304                .active_debug_session(cx)
20305                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20306            {
20307                return true;
20308            }
20309
20310            buffer.update(cx, |buffer, cx| {
20311                project.any_language_server_supports_inlay_hints(buffer, cx)
20312            })
20313        })
20314    }
20315
20316    fn inline_values(
20317        &self,
20318        buffer_handle: Entity<Buffer>,
20319
20320        range: Range<text::Anchor>,
20321        cx: &mut App,
20322    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20323        self.update(cx, |project, cx| {
20324            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20325
20326            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20327        })
20328    }
20329
20330    fn inlay_hints(
20331        &self,
20332        buffer_handle: Entity<Buffer>,
20333        range: Range<text::Anchor>,
20334        cx: &mut App,
20335    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20336        Some(self.update(cx, |project, cx| {
20337            project.inlay_hints(buffer_handle, range, cx)
20338        }))
20339    }
20340
20341    fn resolve_inlay_hint(
20342        &self,
20343        hint: InlayHint,
20344        buffer_handle: Entity<Buffer>,
20345        server_id: LanguageServerId,
20346        cx: &mut App,
20347    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20348        Some(self.update(cx, |project, cx| {
20349            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20350        }))
20351    }
20352
20353    fn range_for_rename(
20354        &self,
20355        buffer: &Entity<Buffer>,
20356        position: text::Anchor,
20357        cx: &mut App,
20358    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20359        Some(self.update(cx, |project, cx| {
20360            let buffer = buffer.clone();
20361            let task = project.prepare_rename(buffer.clone(), position, cx);
20362            cx.spawn(async move |_, cx| {
20363                Ok(match task.await? {
20364                    PrepareRenameResponse::Success(range) => Some(range),
20365                    PrepareRenameResponse::InvalidPosition => None,
20366                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20367                        // Fallback on using TreeSitter info to determine identifier range
20368                        buffer.update(cx, |buffer, _| {
20369                            let snapshot = buffer.snapshot();
20370                            let (range, kind) = snapshot.surrounding_word(position);
20371                            if kind != Some(CharKind::Word) {
20372                                return None;
20373                            }
20374                            Some(
20375                                snapshot.anchor_before(range.start)
20376                                    ..snapshot.anchor_after(range.end),
20377                            )
20378                        })?
20379                    }
20380                })
20381            })
20382        }))
20383    }
20384
20385    fn perform_rename(
20386        &self,
20387        buffer: &Entity<Buffer>,
20388        position: text::Anchor,
20389        new_name: String,
20390        cx: &mut App,
20391    ) -> Option<Task<Result<ProjectTransaction>>> {
20392        Some(self.update(cx, |project, cx| {
20393            project.perform_rename(buffer.clone(), position, new_name, cx)
20394        }))
20395    }
20396}
20397
20398fn inlay_hint_settings(
20399    location: Anchor,
20400    snapshot: &MultiBufferSnapshot,
20401    cx: &mut Context<Editor>,
20402) -> InlayHintSettings {
20403    let file = snapshot.file_at(location);
20404    let language = snapshot.language_at(location).map(|l| l.name());
20405    language_settings(language, file, cx).inlay_hints
20406}
20407
20408fn consume_contiguous_rows(
20409    contiguous_row_selections: &mut Vec<Selection<Point>>,
20410    selection: &Selection<Point>,
20411    display_map: &DisplaySnapshot,
20412    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20413) -> (MultiBufferRow, MultiBufferRow) {
20414    contiguous_row_selections.push(selection.clone());
20415    let start_row = MultiBufferRow(selection.start.row);
20416    let mut end_row = ending_row(selection, display_map);
20417
20418    while let Some(next_selection) = selections.peek() {
20419        if next_selection.start.row <= end_row.0 {
20420            end_row = ending_row(next_selection, display_map);
20421            contiguous_row_selections.push(selections.next().unwrap().clone());
20422        } else {
20423            break;
20424        }
20425    }
20426    (start_row, end_row)
20427}
20428
20429fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20430    if next_selection.end.column > 0 || next_selection.is_empty() {
20431        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20432    } else {
20433        MultiBufferRow(next_selection.end.row)
20434    }
20435}
20436
20437impl EditorSnapshot {
20438    pub fn remote_selections_in_range<'a>(
20439        &'a self,
20440        range: &'a Range<Anchor>,
20441        collaboration_hub: &dyn CollaborationHub,
20442        cx: &'a App,
20443    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20444        let participant_names = collaboration_hub.user_names(cx);
20445        let participant_indices = collaboration_hub.user_participant_indices(cx);
20446        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20447        let collaborators_by_replica_id = collaborators_by_peer_id
20448            .values()
20449            .map(|collaborator| (collaborator.replica_id, collaborator))
20450            .collect::<HashMap<_, _>>();
20451        self.buffer_snapshot
20452            .selections_in_range(range, false)
20453            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20454                if replica_id == AGENT_REPLICA_ID {
20455                    Some(RemoteSelection {
20456                        replica_id,
20457                        selection,
20458                        cursor_shape,
20459                        line_mode,
20460                        collaborator_id: CollaboratorId::Agent,
20461                        user_name: Some("Agent".into()),
20462                        color: cx.theme().players().agent(),
20463                    })
20464                } else {
20465                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20466                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20467                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20468                    Some(RemoteSelection {
20469                        replica_id,
20470                        selection,
20471                        cursor_shape,
20472                        line_mode,
20473                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20474                        user_name,
20475                        color: if let Some(index) = participant_index {
20476                            cx.theme().players().color_for_participant(index.0)
20477                        } else {
20478                            cx.theme().players().absent()
20479                        },
20480                    })
20481                }
20482            })
20483    }
20484
20485    pub fn hunks_for_ranges(
20486        &self,
20487        ranges: impl IntoIterator<Item = Range<Point>>,
20488    ) -> Vec<MultiBufferDiffHunk> {
20489        let mut hunks = Vec::new();
20490        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20491            HashMap::default();
20492        for query_range in ranges {
20493            let query_rows =
20494                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20495            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20496                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20497            ) {
20498                // Include deleted hunks that are adjacent to the query range, because
20499                // otherwise they would be missed.
20500                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20501                if hunk.status().is_deleted() {
20502                    intersects_range |= hunk.row_range.start == query_rows.end;
20503                    intersects_range |= hunk.row_range.end == query_rows.start;
20504                }
20505                if intersects_range {
20506                    if !processed_buffer_rows
20507                        .entry(hunk.buffer_id)
20508                        .or_default()
20509                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20510                    {
20511                        continue;
20512                    }
20513                    hunks.push(hunk);
20514                }
20515            }
20516        }
20517
20518        hunks
20519    }
20520
20521    fn display_diff_hunks_for_rows<'a>(
20522        &'a self,
20523        display_rows: Range<DisplayRow>,
20524        folded_buffers: &'a HashSet<BufferId>,
20525    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20526        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20527        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20528
20529        self.buffer_snapshot
20530            .diff_hunks_in_range(buffer_start..buffer_end)
20531            .filter_map(|hunk| {
20532                if folded_buffers.contains(&hunk.buffer_id) {
20533                    return None;
20534                }
20535
20536                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20537                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20538
20539                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20540                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20541
20542                let display_hunk = if hunk_display_start.column() != 0 {
20543                    DisplayDiffHunk::Folded {
20544                        display_row: hunk_display_start.row(),
20545                    }
20546                } else {
20547                    let mut end_row = hunk_display_end.row();
20548                    if hunk_display_end.column() > 0 {
20549                        end_row.0 += 1;
20550                    }
20551                    let is_created_file = hunk.is_created_file();
20552                    DisplayDiffHunk::Unfolded {
20553                        status: hunk.status(),
20554                        diff_base_byte_range: hunk.diff_base_byte_range,
20555                        display_row_range: hunk_display_start.row()..end_row,
20556                        multi_buffer_range: Anchor::range_in_buffer(
20557                            hunk.excerpt_id,
20558                            hunk.buffer_id,
20559                            hunk.buffer_range,
20560                        ),
20561                        is_created_file,
20562                    }
20563                };
20564
20565                Some(display_hunk)
20566            })
20567    }
20568
20569    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20570        self.display_snapshot.buffer_snapshot.language_at(position)
20571    }
20572
20573    pub fn is_focused(&self) -> bool {
20574        self.is_focused
20575    }
20576
20577    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20578        self.placeholder_text.as_ref()
20579    }
20580
20581    pub fn scroll_position(&self) -> gpui::Point<f32> {
20582        self.scroll_anchor.scroll_position(&self.display_snapshot)
20583    }
20584
20585    fn gutter_dimensions(
20586        &self,
20587        font_id: FontId,
20588        font_size: Pixels,
20589        max_line_number_width: Pixels,
20590        cx: &App,
20591    ) -> Option<GutterDimensions> {
20592        if !self.show_gutter {
20593            return None;
20594        }
20595
20596        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20597        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20598
20599        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20600            matches!(
20601                ProjectSettings::get_global(cx).git.git_gutter,
20602                Some(GitGutterSetting::TrackedFiles)
20603            )
20604        });
20605        let gutter_settings = EditorSettings::get_global(cx).gutter;
20606        let show_line_numbers = self
20607            .show_line_numbers
20608            .unwrap_or(gutter_settings.line_numbers);
20609        let line_gutter_width = if show_line_numbers {
20610            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20611            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20612            max_line_number_width.max(min_width_for_number_on_gutter)
20613        } else {
20614            0.0.into()
20615        };
20616
20617        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20618        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20619
20620        let git_blame_entries_width =
20621            self.git_blame_gutter_max_author_length
20622                .map(|max_author_length| {
20623                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20624                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20625
20626                    /// The number of characters to dedicate to gaps and margins.
20627                    const SPACING_WIDTH: usize = 4;
20628
20629                    let max_char_count = max_author_length.min(renderer.max_author_length())
20630                        + ::git::SHORT_SHA_LENGTH
20631                        + MAX_RELATIVE_TIMESTAMP.len()
20632                        + SPACING_WIDTH;
20633
20634                    em_advance * max_char_count
20635                });
20636
20637        let is_singleton = self.buffer_snapshot.is_singleton();
20638
20639        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20640        left_padding += if !is_singleton {
20641            em_width * 4.0
20642        } else if show_runnables || show_breakpoints {
20643            em_width * 3.0
20644        } else if show_git_gutter && show_line_numbers {
20645            em_width * 2.0
20646        } else if show_git_gutter || show_line_numbers {
20647            em_width
20648        } else {
20649            px(0.)
20650        };
20651
20652        let shows_folds = is_singleton && gutter_settings.folds;
20653
20654        let right_padding = if shows_folds && show_line_numbers {
20655            em_width * 4.0
20656        } else if shows_folds || (!is_singleton && show_line_numbers) {
20657            em_width * 3.0
20658        } else if show_line_numbers {
20659            em_width
20660        } else {
20661            px(0.)
20662        };
20663
20664        Some(GutterDimensions {
20665            left_padding,
20666            right_padding,
20667            width: line_gutter_width + left_padding + right_padding,
20668            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20669            git_blame_entries_width,
20670        })
20671    }
20672
20673    pub fn render_crease_toggle(
20674        &self,
20675        buffer_row: MultiBufferRow,
20676        row_contains_cursor: bool,
20677        editor: Entity<Editor>,
20678        window: &mut Window,
20679        cx: &mut App,
20680    ) -> Option<AnyElement> {
20681        let folded = self.is_line_folded(buffer_row);
20682        let mut is_foldable = false;
20683
20684        if let Some(crease) = self
20685            .crease_snapshot
20686            .query_row(buffer_row, &self.buffer_snapshot)
20687        {
20688            is_foldable = true;
20689            match crease {
20690                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20691                    if let Some(render_toggle) = render_toggle {
20692                        let toggle_callback =
20693                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20694                                if folded {
20695                                    editor.update(cx, |editor, cx| {
20696                                        editor.fold_at(buffer_row, window, cx)
20697                                    });
20698                                } else {
20699                                    editor.update(cx, |editor, cx| {
20700                                        editor.unfold_at(buffer_row, window, cx)
20701                                    });
20702                                }
20703                            });
20704                        return Some((render_toggle)(
20705                            buffer_row,
20706                            folded,
20707                            toggle_callback,
20708                            window,
20709                            cx,
20710                        ));
20711                    }
20712                }
20713            }
20714        }
20715
20716        is_foldable |= self.starts_indent(buffer_row);
20717
20718        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20719            Some(
20720                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20721                    .toggle_state(folded)
20722                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20723                        if folded {
20724                            this.unfold_at(buffer_row, window, cx);
20725                        } else {
20726                            this.fold_at(buffer_row, window, cx);
20727                        }
20728                    }))
20729                    .into_any_element(),
20730            )
20731        } else {
20732            None
20733        }
20734    }
20735
20736    pub fn render_crease_trailer(
20737        &self,
20738        buffer_row: MultiBufferRow,
20739        window: &mut Window,
20740        cx: &mut App,
20741    ) -> Option<AnyElement> {
20742        let folded = self.is_line_folded(buffer_row);
20743        if let Crease::Inline { render_trailer, .. } = self
20744            .crease_snapshot
20745            .query_row(buffer_row, &self.buffer_snapshot)?
20746        {
20747            let render_trailer = render_trailer.as_ref()?;
20748            Some(render_trailer(buffer_row, folded, window, cx))
20749        } else {
20750            None
20751        }
20752    }
20753}
20754
20755impl Deref for EditorSnapshot {
20756    type Target = DisplaySnapshot;
20757
20758    fn deref(&self) -> &Self::Target {
20759        &self.display_snapshot
20760    }
20761}
20762
20763#[derive(Clone, Debug, PartialEq, Eq)]
20764pub enum EditorEvent {
20765    InputIgnored {
20766        text: Arc<str>,
20767    },
20768    InputHandled {
20769        utf16_range_to_replace: Option<Range<isize>>,
20770        text: Arc<str>,
20771    },
20772    ExcerptsAdded {
20773        buffer: Entity<Buffer>,
20774        predecessor: ExcerptId,
20775        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20776    },
20777    ExcerptsRemoved {
20778        ids: Vec<ExcerptId>,
20779        removed_buffer_ids: Vec<BufferId>,
20780    },
20781    BufferFoldToggled {
20782        ids: Vec<ExcerptId>,
20783        folded: bool,
20784    },
20785    ExcerptsEdited {
20786        ids: Vec<ExcerptId>,
20787    },
20788    ExcerptsExpanded {
20789        ids: Vec<ExcerptId>,
20790    },
20791    BufferEdited,
20792    Edited {
20793        transaction_id: clock::Lamport,
20794    },
20795    Reparsed(BufferId),
20796    Focused,
20797    FocusedIn,
20798    Blurred,
20799    DirtyChanged,
20800    Saved,
20801    TitleChanged,
20802    DiffBaseChanged,
20803    SelectionsChanged {
20804        local: bool,
20805    },
20806    ScrollPositionChanged {
20807        local: bool,
20808        autoscroll: bool,
20809    },
20810    Closed,
20811    TransactionUndone {
20812        transaction_id: clock::Lamport,
20813    },
20814    TransactionBegun {
20815        transaction_id: clock::Lamport,
20816    },
20817    Reloaded,
20818    CursorShapeChanged,
20819    PushedToNavHistory {
20820        anchor: Anchor,
20821        is_deactivate: bool,
20822    },
20823}
20824
20825impl EventEmitter<EditorEvent> for Editor {}
20826
20827impl Focusable for Editor {
20828    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20829        self.focus_handle.clone()
20830    }
20831}
20832
20833impl Render for Editor {
20834    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20835        let settings = ThemeSettings::get_global(cx);
20836
20837        let mut text_style = match self.mode {
20838            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20839                color: cx.theme().colors().editor_foreground,
20840                font_family: settings.ui_font.family.clone(),
20841                font_features: settings.ui_font.features.clone(),
20842                font_fallbacks: settings.ui_font.fallbacks.clone(),
20843                font_size: rems(0.875).into(),
20844                font_weight: settings.ui_font.weight,
20845                line_height: relative(settings.buffer_line_height.value()),
20846                ..Default::default()
20847            },
20848            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20849                color: cx.theme().colors().editor_foreground,
20850                font_family: settings.buffer_font.family.clone(),
20851                font_features: settings.buffer_font.features.clone(),
20852                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20853                font_size: settings.buffer_font_size(cx).into(),
20854                font_weight: settings.buffer_font.weight,
20855                line_height: relative(settings.buffer_line_height.value()),
20856                ..Default::default()
20857            },
20858        };
20859        if let Some(text_style_refinement) = &self.text_style_refinement {
20860            text_style.refine(text_style_refinement)
20861        }
20862
20863        let background = match self.mode {
20864            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20865            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20866            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20867            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20868        };
20869
20870        EditorElement::new(
20871            &cx.entity(),
20872            EditorStyle {
20873                background,
20874                local_player: cx.theme().players().local(),
20875                text: text_style,
20876                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20877                syntax: cx.theme().syntax().clone(),
20878                status: cx.theme().status().clone(),
20879                inlay_hints_style: make_inlay_hints_style(cx),
20880                inline_completion_styles: make_suggestion_styles(cx),
20881                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20882                show_underlines: !self.mode.is_minimap(),
20883            },
20884        )
20885    }
20886}
20887
20888impl EntityInputHandler for Editor {
20889    fn text_for_range(
20890        &mut self,
20891        range_utf16: Range<usize>,
20892        adjusted_range: &mut Option<Range<usize>>,
20893        _: &mut Window,
20894        cx: &mut Context<Self>,
20895    ) -> Option<String> {
20896        let snapshot = self.buffer.read(cx).read(cx);
20897        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20898        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20899        if (start.0..end.0) != range_utf16 {
20900            adjusted_range.replace(start.0..end.0);
20901        }
20902        Some(snapshot.text_for_range(start..end).collect())
20903    }
20904
20905    fn selected_text_range(
20906        &mut self,
20907        ignore_disabled_input: bool,
20908        _: &mut Window,
20909        cx: &mut Context<Self>,
20910    ) -> Option<UTF16Selection> {
20911        // Prevent the IME menu from appearing when holding down an alphabetic key
20912        // while input is disabled.
20913        if !ignore_disabled_input && !self.input_enabled {
20914            return None;
20915        }
20916
20917        let selection = self.selections.newest::<OffsetUtf16>(cx);
20918        let range = selection.range();
20919
20920        Some(UTF16Selection {
20921            range: range.start.0..range.end.0,
20922            reversed: selection.reversed,
20923        })
20924    }
20925
20926    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20927        let snapshot = self.buffer.read(cx).read(cx);
20928        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20929        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20930    }
20931
20932    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20933        self.clear_highlights::<InputComposition>(cx);
20934        self.ime_transaction.take();
20935    }
20936
20937    fn replace_text_in_range(
20938        &mut self,
20939        range_utf16: Option<Range<usize>>,
20940        text: &str,
20941        window: &mut Window,
20942        cx: &mut Context<Self>,
20943    ) {
20944        if !self.input_enabled {
20945            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20946            return;
20947        }
20948
20949        self.transact(window, cx, |this, window, cx| {
20950            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20951                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20952                Some(this.selection_replacement_ranges(range_utf16, cx))
20953            } else {
20954                this.marked_text_ranges(cx)
20955            };
20956
20957            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20958                let newest_selection_id = this.selections.newest_anchor().id;
20959                this.selections
20960                    .all::<OffsetUtf16>(cx)
20961                    .iter()
20962                    .zip(ranges_to_replace.iter())
20963                    .find_map(|(selection, range)| {
20964                        if selection.id == newest_selection_id {
20965                            Some(
20966                                (range.start.0 as isize - selection.head().0 as isize)
20967                                    ..(range.end.0 as isize - selection.head().0 as isize),
20968                            )
20969                        } else {
20970                            None
20971                        }
20972                    })
20973            });
20974
20975            cx.emit(EditorEvent::InputHandled {
20976                utf16_range_to_replace: range_to_replace,
20977                text: text.into(),
20978            });
20979
20980            if let Some(new_selected_ranges) = new_selected_ranges {
20981                this.change_selections(None, window, cx, |selections| {
20982                    selections.select_ranges(new_selected_ranges)
20983                });
20984                this.backspace(&Default::default(), window, cx);
20985            }
20986
20987            this.handle_input(text, window, cx);
20988        });
20989
20990        if let Some(transaction) = self.ime_transaction {
20991            self.buffer.update(cx, |buffer, cx| {
20992                buffer.group_until_transaction(transaction, cx);
20993            });
20994        }
20995
20996        self.unmark_text(window, cx);
20997    }
20998
20999    fn replace_and_mark_text_in_range(
21000        &mut self,
21001        range_utf16: Option<Range<usize>>,
21002        text: &str,
21003        new_selected_range_utf16: Option<Range<usize>>,
21004        window: &mut Window,
21005        cx: &mut Context<Self>,
21006    ) {
21007        if !self.input_enabled {
21008            return;
21009        }
21010
21011        let transaction = self.transact(window, cx, |this, window, cx| {
21012            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21013                let snapshot = this.buffer.read(cx).read(cx);
21014                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21015                    for marked_range in &mut marked_ranges {
21016                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21017                        marked_range.start.0 += relative_range_utf16.start;
21018                        marked_range.start =
21019                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21020                        marked_range.end =
21021                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21022                    }
21023                }
21024                Some(marked_ranges)
21025            } else if let Some(range_utf16) = range_utf16 {
21026                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21027                Some(this.selection_replacement_ranges(range_utf16, cx))
21028            } else {
21029                None
21030            };
21031
21032            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21033                let newest_selection_id = this.selections.newest_anchor().id;
21034                this.selections
21035                    .all::<OffsetUtf16>(cx)
21036                    .iter()
21037                    .zip(ranges_to_replace.iter())
21038                    .find_map(|(selection, range)| {
21039                        if selection.id == newest_selection_id {
21040                            Some(
21041                                (range.start.0 as isize - selection.head().0 as isize)
21042                                    ..(range.end.0 as isize - selection.head().0 as isize),
21043                            )
21044                        } else {
21045                            None
21046                        }
21047                    })
21048            });
21049
21050            cx.emit(EditorEvent::InputHandled {
21051                utf16_range_to_replace: range_to_replace,
21052                text: text.into(),
21053            });
21054
21055            if let Some(ranges) = ranges_to_replace {
21056                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21057            }
21058
21059            let marked_ranges = {
21060                let snapshot = this.buffer.read(cx).read(cx);
21061                this.selections
21062                    .disjoint_anchors()
21063                    .iter()
21064                    .map(|selection| {
21065                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21066                    })
21067                    .collect::<Vec<_>>()
21068            };
21069
21070            if text.is_empty() {
21071                this.unmark_text(window, cx);
21072            } else {
21073                this.highlight_text::<InputComposition>(
21074                    marked_ranges.clone(),
21075                    HighlightStyle {
21076                        underline: Some(UnderlineStyle {
21077                            thickness: px(1.),
21078                            color: None,
21079                            wavy: false,
21080                        }),
21081                        ..Default::default()
21082                    },
21083                    cx,
21084                );
21085            }
21086
21087            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21088            let use_autoclose = this.use_autoclose;
21089            let use_auto_surround = this.use_auto_surround;
21090            this.set_use_autoclose(false);
21091            this.set_use_auto_surround(false);
21092            this.handle_input(text, window, cx);
21093            this.set_use_autoclose(use_autoclose);
21094            this.set_use_auto_surround(use_auto_surround);
21095
21096            if let Some(new_selected_range) = new_selected_range_utf16 {
21097                let snapshot = this.buffer.read(cx).read(cx);
21098                let new_selected_ranges = marked_ranges
21099                    .into_iter()
21100                    .map(|marked_range| {
21101                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21102                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21103                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21104                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21105                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21106                    })
21107                    .collect::<Vec<_>>();
21108
21109                drop(snapshot);
21110                this.change_selections(None, window, cx, |selections| {
21111                    selections.select_ranges(new_selected_ranges)
21112                });
21113            }
21114        });
21115
21116        self.ime_transaction = self.ime_transaction.or(transaction);
21117        if let Some(transaction) = self.ime_transaction {
21118            self.buffer.update(cx, |buffer, cx| {
21119                buffer.group_until_transaction(transaction, cx);
21120            });
21121        }
21122
21123        if self.text_highlights::<InputComposition>(cx).is_none() {
21124            self.ime_transaction.take();
21125        }
21126    }
21127
21128    fn bounds_for_range(
21129        &mut self,
21130        range_utf16: Range<usize>,
21131        element_bounds: gpui::Bounds<Pixels>,
21132        window: &mut Window,
21133        cx: &mut Context<Self>,
21134    ) -> Option<gpui::Bounds<Pixels>> {
21135        let text_layout_details = self.text_layout_details(window);
21136        let gpui::Size {
21137            width: em_width,
21138            height: line_height,
21139        } = self.character_size(window);
21140
21141        let snapshot = self.snapshot(window, cx);
21142        let scroll_position = snapshot.scroll_position();
21143        let scroll_left = scroll_position.x * em_width;
21144
21145        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21146        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21147            + self.gutter_dimensions.width
21148            + self.gutter_dimensions.margin;
21149        let y = line_height * (start.row().as_f32() - scroll_position.y);
21150
21151        Some(Bounds {
21152            origin: element_bounds.origin + point(x, y),
21153            size: size(em_width, line_height),
21154        })
21155    }
21156
21157    fn character_index_for_point(
21158        &mut self,
21159        point: gpui::Point<Pixels>,
21160        _window: &mut Window,
21161        _cx: &mut Context<Self>,
21162    ) -> Option<usize> {
21163        let position_map = self.last_position_map.as_ref()?;
21164        if !position_map.text_hitbox.contains(&point) {
21165            return None;
21166        }
21167        let display_point = position_map.point_for_position(point).previous_valid;
21168        let anchor = position_map
21169            .snapshot
21170            .display_point_to_anchor(display_point, Bias::Left);
21171        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21172        Some(utf16_offset.0)
21173    }
21174}
21175
21176trait SelectionExt {
21177    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21178    fn spanned_rows(
21179        &self,
21180        include_end_if_at_line_start: bool,
21181        map: &DisplaySnapshot,
21182    ) -> Range<MultiBufferRow>;
21183}
21184
21185impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21186    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21187        let start = self
21188            .start
21189            .to_point(&map.buffer_snapshot)
21190            .to_display_point(map);
21191        let end = self
21192            .end
21193            .to_point(&map.buffer_snapshot)
21194            .to_display_point(map);
21195        if self.reversed {
21196            end..start
21197        } else {
21198            start..end
21199        }
21200    }
21201
21202    fn spanned_rows(
21203        &self,
21204        include_end_if_at_line_start: bool,
21205        map: &DisplaySnapshot,
21206    ) -> Range<MultiBufferRow> {
21207        let start = self.start.to_point(&map.buffer_snapshot);
21208        let mut end = self.end.to_point(&map.buffer_snapshot);
21209        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21210            end.row -= 1;
21211        }
21212
21213        let buffer_start = map.prev_line_boundary(start).0;
21214        let buffer_end = map.next_line_boundary(end).0;
21215        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21216    }
21217}
21218
21219impl<T: InvalidationRegion> InvalidationStack<T> {
21220    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21221    where
21222        S: Clone + ToOffset,
21223    {
21224        while let Some(region) = self.last() {
21225            let all_selections_inside_invalidation_ranges =
21226                if selections.len() == region.ranges().len() {
21227                    selections
21228                        .iter()
21229                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21230                        .all(|(selection, invalidation_range)| {
21231                            let head = selection.head().to_offset(buffer);
21232                            invalidation_range.start <= head && invalidation_range.end >= head
21233                        })
21234                } else {
21235                    false
21236                };
21237
21238            if all_selections_inside_invalidation_ranges {
21239                break;
21240            } else {
21241                self.pop();
21242            }
21243        }
21244    }
21245}
21246
21247impl<T> Default for InvalidationStack<T> {
21248    fn default() -> Self {
21249        Self(Default::default())
21250    }
21251}
21252
21253impl<T> Deref for InvalidationStack<T> {
21254    type Target = Vec<T>;
21255
21256    fn deref(&self) -> &Self::Target {
21257        &self.0
21258    }
21259}
21260
21261impl<T> DerefMut for InvalidationStack<T> {
21262    fn deref_mut(&mut self) -> &mut Self::Target {
21263        &mut self.0
21264    }
21265}
21266
21267impl InvalidationRegion for SnippetState {
21268    fn ranges(&self) -> &[Range<Anchor>] {
21269        &self.ranges[self.active_index]
21270    }
21271}
21272
21273fn inline_completion_edit_text(
21274    current_snapshot: &BufferSnapshot,
21275    edits: &[(Range<Anchor>, String)],
21276    edit_preview: &EditPreview,
21277    include_deletions: bool,
21278    cx: &App,
21279) -> HighlightedText {
21280    let edits = edits
21281        .iter()
21282        .map(|(anchor, text)| {
21283            (
21284                anchor.start.text_anchor..anchor.end.text_anchor,
21285                text.clone(),
21286            )
21287        })
21288        .collect::<Vec<_>>();
21289
21290    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21291}
21292
21293pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21294    match severity {
21295        lsp::DiagnosticSeverity::ERROR => colors.error,
21296        lsp::DiagnosticSeverity::WARNING => colors.warning,
21297        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21298        lsp::DiagnosticSeverity::HINT => colors.info,
21299        _ => colors.ignored,
21300    }
21301}
21302
21303pub fn styled_runs_for_code_label<'a>(
21304    label: &'a CodeLabel,
21305    syntax_theme: &'a theme::SyntaxTheme,
21306) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21307    let fade_out = HighlightStyle {
21308        fade_out: Some(0.35),
21309        ..Default::default()
21310    };
21311
21312    let mut prev_end = label.filter_range.end;
21313    label
21314        .runs
21315        .iter()
21316        .enumerate()
21317        .flat_map(move |(ix, (range, highlight_id))| {
21318            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21319                style
21320            } else {
21321                return Default::default();
21322            };
21323            let mut muted_style = style;
21324            muted_style.highlight(fade_out);
21325
21326            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21327            if range.start >= label.filter_range.end {
21328                if range.start > prev_end {
21329                    runs.push((prev_end..range.start, fade_out));
21330                }
21331                runs.push((range.clone(), muted_style));
21332            } else if range.end <= label.filter_range.end {
21333                runs.push((range.clone(), style));
21334            } else {
21335                runs.push((range.start..label.filter_range.end, style));
21336                runs.push((label.filter_range.end..range.end, muted_style));
21337            }
21338            prev_end = cmp::max(prev_end, range.end);
21339
21340            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21341                runs.push((prev_end..label.text.len(), fade_out));
21342            }
21343
21344            runs
21345        })
21346}
21347
21348pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21349    let mut prev_index = 0;
21350    let mut prev_codepoint: Option<char> = None;
21351    text.char_indices()
21352        .chain([(text.len(), '\0')])
21353        .filter_map(move |(index, codepoint)| {
21354            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21355            let is_boundary = index == text.len()
21356                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21357                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21358            if is_boundary {
21359                let chunk = &text[prev_index..index];
21360                prev_index = index;
21361                Some(chunk)
21362            } else {
21363                None
21364            }
21365        })
21366}
21367
21368pub trait RangeToAnchorExt: Sized {
21369    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21370
21371    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21372        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21373        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21374    }
21375}
21376
21377impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21378    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21379        let start_offset = self.start.to_offset(snapshot);
21380        let end_offset = self.end.to_offset(snapshot);
21381        if start_offset == end_offset {
21382            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21383        } else {
21384            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21385        }
21386    }
21387}
21388
21389pub trait RowExt {
21390    fn as_f32(&self) -> f32;
21391
21392    fn next_row(&self) -> Self;
21393
21394    fn previous_row(&self) -> Self;
21395
21396    fn minus(&self, other: Self) -> u32;
21397}
21398
21399impl RowExt for DisplayRow {
21400    fn as_f32(&self) -> f32 {
21401        self.0 as f32
21402    }
21403
21404    fn next_row(&self) -> Self {
21405        Self(self.0 + 1)
21406    }
21407
21408    fn previous_row(&self) -> Self {
21409        Self(self.0.saturating_sub(1))
21410    }
21411
21412    fn minus(&self, other: Self) -> u32 {
21413        self.0 - other.0
21414    }
21415}
21416
21417impl RowExt for MultiBufferRow {
21418    fn as_f32(&self) -> f32 {
21419        self.0 as f32
21420    }
21421
21422    fn next_row(&self) -> Self {
21423        Self(self.0 + 1)
21424    }
21425
21426    fn previous_row(&self) -> Self {
21427        Self(self.0.saturating_sub(1))
21428    }
21429
21430    fn minus(&self, other: Self) -> u32 {
21431        self.0 - other.0
21432    }
21433}
21434
21435trait RowRangeExt {
21436    type Row;
21437
21438    fn len(&self) -> usize;
21439
21440    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21441}
21442
21443impl RowRangeExt for Range<MultiBufferRow> {
21444    type Row = MultiBufferRow;
21445
21446    fn len(&self) -> usize {
21447        (self.end.0 - self.start.0) as usize
21448    }
21449
21450    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21451        (self.start.0..self.end.0).map(MultiBufferRow)
21452    }
21453}
21454
21455impl RowRangeExt for Range<DisplayRow> {
21456    type Row = DisplayRow;
21457
21458    fn len(&self) -> usize {
21459        (self.end.0 - self.start.0) as usize
21460    }
21461
21462    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21463        (self.start.0..self.end.0).map(DisplayRow)
21464    }
21465}
21466
21467/// If select range has more than one line, we
21468/// just point the cursor to range.start.
21469fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21470    if range.start.row == range.end.row {
21471        range
21472    } else {
21473        range.start..range.start
21474    }
21475}
21476pub struct KillRing(ClipboardItem);
21477impl Global for KillRing {}
21478
21479const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21480
21481enum BreakpointPromptEditAction {
21482    Log,
21483    Condition,
21484    HitCondition,
21485}
21486
21487struct BreakpointPromptEditor {
21488    pub(crate) prompt: Entity<Editor>,
21489    editor: WeakEntity<Editor>,
21490    breakpoint_anchor: Anchor,
21491    breakpoint: Breakpoint,
21492    edit_action: BreakpointPromptEditAction,
21493    block_ids: HashSet<CustomBlockId>,
21494    editor_margins: Arc<Mutex<EditorMargins>>,
21495    _subscriptions: Vec<Subscription>,
21496}
21497
21498impl BreakpointPromptEditor {
21499    const MAX_LINES: u8 = 4;
21500
21501    fn new(
21502        editor: WeakEntity<Editor>,
21503        breakpoint_anchor: Anchor,
21504        breakpoint: Breakpoint,
21505        edit_action: BreakpointPromptEditAction,
21506        window: &mut Window,
21507        cx: &mut Context<Self>,
21508    ) -> Self {
21509        let base_text = match edit_action {
21510            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21511            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21512            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21513        }
21514        .map(|msg| msg.to_string())
21515        .unwrap_or_default();
21516
21517        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21518        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21519
21520        let prompt = cx.new(|cx| {
21521            let mut prompt = Editor::new(
21522                EditorMode::AutoHeight {
21523                    max_lines: Self::MAX_LINES as usize,
21524                },
21525                buffer,
21526                None,
21527                window,
21528                cx,
21529            );
21530            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21531            prompt.set_show_cursor_when_unfocused(false, cx);
21532            prompt.set_placeholder_text(
21533                match edit_action {
21534                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21535                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21536                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21537                },
21538                cx,
21539            );
21540
21541            prompt
21542        });
21543
21544        Self {
21545            prompt,
21546            editor,
21547            breakpoint_anchor,
21548            breakpoint,
21549            edit_action,
21550            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21551            block_ids: Default::default(),
21552            _subscriptions: vec![],
21553        }
21554    }
21555
21556    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21557        self.block_ids.extend(block_ids)
21558    }
21559
21560    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21561        if let Some(editor) = self.editor.upgrade() {
21562            let message = self
21563                .prompt
21564                .read(cx)
21565                .buffer
21566                .read(cx)
21567                .as_singleton()
21568                .expect("A multi buffer in breakpoint prompt isn't possible")
21569                .read(cx)
21570                .as_rope()
21571                .to_string();
21572
21573            editor.update(cx, |editor, cx| {
21574                editor.edit_breakpoint_at_anchor(
21575                    self.breakpoint_anchor,
21576                    self.breakpoint.clone(),
21577                    match self.edit_action {
21578                        BreakpointPromptEditAction::Log => {
21579                            BreakpointEditAction::EditLogMessage(message.into())
21580                        }
21581                        BreakpointPromptEditAction::Condition => {
21582                            BreakpointEditAction::EditCondition(message.into())
21583                        }
21584                        BreakpointPromptEditAction::HitCondition => {
21585                            BreakpointEditAction::EditHitCondition(message.into())
21586                        }
21587                    },
21588                    cx,
21589                );
21590
21591                editor.remove_blocks(self.block_ids.clone(), None, cx);
21592                cx.focus_self(window);
21593            });
21594        }
21595    }
21596
21597    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21598        self.editor
21599            .update(cx, |editor, cx| {
21600                editor.remove_blocks(self.block_ids.clone(), None, cx);
21601                window.focus(&editor.focus_handle);
21602            })
21603            .log_err();
21604    }
21605
21606    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21607        let settings = ThemeSettings::get_global(cx);
21608        let text_style = TextStyle {
21609            color: if self.prompt.read(cx).read_only(cx) {
21610                cx.theme().colors().text_disabled
21611            } else {
21612                cx.theme().colors().text
21613            },
21614            font_family: settings.buffer_font.family.clone(),
21615            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21616            font_size: settings.buffer_font_size(cx).into(),
21617            font_weight: settings.buffer_font.weight,
21618            line_height: relative(settings.buffer_line_height.value()),
21619            ..Default::default()
21620        };
21621        EditorElement::new(
21622            &self.prompt,
21623            EditorStyle {
21624                background: cx.theme().colors().editor_background,
21625                local_player: cx.theme().players().local(),
21626                text: text_style,
21627                ..Default::default()
21628            },
21629        )
21630    }
21631}
21632
21633impl Render for BreakpointPromptEditor {
21634    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21635        let editor_margins = *self.editor_margins.lock();
21636        let gutter_dimensions = editor_margins.gutter;
21637        h_flex()
21638            .key_context("Editor")
21639            .bg(cx.theme().colors().editor_background)
21640            .border_y_1()
21641            .border_color(cx.theme().status().info_border)
21642            .size_full()
21643            .py(window.line_height() / 2.5)
21644            .on_action(cx.listener(Self::confirm))
21645            .on_action(cx.listener(Self::cancel))
21646            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21647            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21648    }
21649}
21650
21651impl Focusable for BreakpointPromptEditor {
21652    fn focus_handle(&self, cx: &App) -> FocusHandle {
21653        self.prompt.focus_handle(cx)
21654    }
21655}
21656
21657fn all_edits_insertions_or_deletions(
21658    edits: &Vec<(Range<Anchor>, String)>,
21659    snapshot: &MultiBufferSnapshot,
21660) -> bool {
21661    let mut all_insertions = true;
21662    let mut all_deletions = true;
21663
21664    for (range, new_text) in edits.iter() {
21665        let range_is_empty = range.to_offset(&snapshot).is_empty();
21666        let text_is_empty = new_text.is_empty();
21667
21668        if range_is_empty != text_is_empty {
21669            if range_is_empty {
21670                all_deletions = false;
21671            } else {
21672                all_insertions = false;
21673            }
21674        } else {
21675            return false;
21676        }
21677
21678        if !all_insertions && !all_deletions {
21679            return false;
21680        }
21681    }
21682    all_insertions || all_deletions
21683}
21684
21685struct MissingEditPredictionKeybindingTooltip;
21686
21687impl Render for MissingEditPredictionKeybindingTooltip {
21688    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21689        ui::tooltip_container(window, cx, |container, _, cx| {
21690            container
21691                .flex_shrink_0()
21692                .max_w_80()
21693                .min_h(rems_from_px(124.))
21694                .justify_between()
21695                .child(
21696                    v_flex()
21697                        .flex_1()
21698                        .text_ui_sm(cx)
21699                        .child(Label::new("Conflict with Accept Keybinding"))
21700                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21701                )
21702                .child(
21703                    h_flex()
21704                        .pb_1()
21705                        .gap_1()
21706                        .items_end()
21707                        .w_full()
21708                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21709                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21710                        }))
21711                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21712                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21713                        })),
21714                )
21715        })
21716    }
21717}
21718
21719#[derive(Debug, Clone, Copy, PartialEq)]
21720pub struct LineHighlight {
21721    pub background: Background,
21722    pub border: Option<gpui::Hsla>,
21723    pub include_gutter: bool,
21724    pub type_id: Option<TypeId>,
21725}
21726
21727fn render_diff_hunk_controls(
21728    row: u32,
21729    status: &DiffHunkStatus,
21730    hunk_range: Range<Anchor>,
21731    is_created_file: bool,
21732    line_height: Pixels,
21733    editor: &Entity<Editor>,
21734    _window: &mut Window,
21735    cx: &mut App,
21736) -> AnyElement {
21737    h_flex()
21738        .h(line_height)
21739        .mr_1()
21740        .gap_1()
21741        .px_0p5()
21742        .pb_1()
21743        .border_x_1()
21744        .border_b_1()
21745        .border_color(cx.theme().colors().border_variant)
21746        .rounded_b_lg()
21747        .bg(cx.theme().colors().editor_background)
21748        .gap_1()
21749        .occlude()
21750        .shadow_md()
21751        .child(if status.has_secondary_hunk() {
21752            Button::new(("stage", row as u64), "Stage")
21753                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21754                .tooltip({
21755                    let focus_handle = editor.focus_handle(cx);
21756                    move |window, cx| {
21757                        Tooltip::for_action_in(
21758                            "Stage Hunk",
21759                            &::git::ToggleStaged,
21760                            &focus_handle,
21761                            window,
21762                            cx,
21763                        )
21764                    }
21765                })
21766                .on_click({
21767                    let editor = editor.clone();
21768                    move |_event, _window, cx| {
21769                        editor.update(cx, |editor, cx| {
21770                            editor.stage_or_unstage_diff_hunks(
21771                                true,
21772                                vec![hunk_range.start..hunk_range.start],
21773                                cx,
21774                            );
21775                        });
21776                    }
21777                })
21778        } else {
21779            Button::new(("unstage", row as u64), "Unstage")
21780                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21781                .tooltip({
21782                    let focus_handle = editor.focus_handle(cx);
21783                    move |window, cx| {
21784                        Tooltip::for_action_in(
21785                            "Unstage Hunk",
21786                            &::git::ToggleStaged,
21787                            &focus_handle,
21788                            window,
21789                            cx,
21790                        )
21791                    }
21792                })
21793                .on_click({
21794                    let editor = editor.clone();
21795                    move |_event, _window, cx| {
21796                        editor.update(cx, |editor, cx| {
21797                            editor.stage_or_unstage_diff_hunks(
21798                                false,
21799                                vec![hunk_range.start..hunk_range.start],
21800                                cx,
21801                            );
21802                        });
21803                    }
21804                })
21805        })
21806        .child(
21807            Button::new(("restore", row as u64), "Restore")
21808                .tooltip({
21809                    let focus_handle = editor.focus_handle(cx);
21810                    move |window, cx| {
21811                        Tooltip::for_action_in(
21812                            "Restore Hunk",
21813                            &::git::Restore,
21814                            &focus_handle,
21815                            window,
21816                            cx,
21817                        )
21818                    }
21819                })
21820                .on_click({
21821                    let editor = editor.clone();
21822                    move |_event, window, cx| {
21823                        editor.update(cx, |editor, cx| {
21824                            let snapshot = editor.snapshot(window, cx);
21825                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21826                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21827                        });
21828                    }
21829                })
21830                .disabled(is_created_file),
21831        )
21832        .when(
21833            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21834            |el| {
21835                el.child(
21836                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21837                        .shape(IconButtonShape::Square)
21838                        .icon_size(IconSize::Small)
21839                        // .disabled(!has_multiple_hunks)
21840                        .tooltip({
21841                            let focus_handle = editor.focus_handle(cx);
21842                            move |window, cx| {
21843                                Tooltip::for_action_in(
21844                                    "Next Hunk",
21845                                    &GoToHunk,
21846                                    &focus_handle,
21847                                    window,
21848                                    cx,
21849                                )
21850                            }
21851                        })
21852                        .on_click({
21853                            let editor = editor.clone();
21854                            move |_event, window, cx| {
21855                                editor.update(cx, |editor, cx| {
21856                                    let snapshot = editor.snapshot(window, cx);
21857                                    let position =
21858                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21859                                    editor.go_to_hunk_before_or_after_position(
21860                                        &snapshot,
21861                                        position,
21862                                        Direction::Next,
21863                                        window,
21864                                        cx,
21865                                    );
21866                                    editor.expand_selected_diff_hunks(cx);
21867                                });
21868                            }
21869                        }),
21870                )
21871                .child(
21872                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21873                        .shape(IconButtonShape::Square)
21874                        .icon_size(IconSize::Small)
21875                        // .disabled(!has_multiple_hunks)
21876                        .tooltip({
21877                            let focus_handle = editor.focus_handle(cx);
21878                            move |window, cx| {
21879                                Tooltip::for_action_in(
21880                                    "Previous Hunk",
21881                                    &GoToPreviousHunk,
21882                                    &focus_handle,
21883                                    window,
21884                                    cx,
21885                                )
21886                            }
21887                        })
21888                        .on_click({
21889                            let editor = editor.clone();
21890                            move |_event, window, cx| {
21891                                editor.update(cx, |editor, cx| {
21892                                    let snapshot = editor.snapshot(window, cx);
21893                                    let point =
21894                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21895                                    editor.go_to_hunk_before_or_after_position(
21896                                        &snapshot,
21897                                        point,
21898                                        Direction::Prev,
21899                                        window,
21900                                        cx,
21901                                    );
21902                                    editor.expand_selected_diff_hunks(cx);
21903                                });
21904                            }
21905                        }),
21906                )
21907            },
21908        )
21909        .into_any_element()
21910}