editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, SearchSettings,
   67    ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt,
   78    future::{self, Shared, join},
   79};
   80use fuzzy::StringMatchCandidate;
   81
   82use ::git::blame::BlameEntry;
   83use ::git::{Restore, blame::ParsedCommitMessage};
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use git::blame::{GitBlame, GlobalBlameRenderer};
   89use gpui::{
   90    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   91    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   92    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   93    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   94    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   95    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   96    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   97    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   98};
   99use highlight_matching_bracket::refresh_matching_bracket_highlights;
  100use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  101pub use hover_popover::hover_markdown_style;
  102use hover_popover::{HoverState, hide_hover};
  103use indent_guides::ActiveIndentGuidesState;
  104use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  105pub use inline_completion::Direction;
  106use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  107pub use items::MAX_TAB_TITLE_LEN;
  108use itertools::Itertools;
  109use language::{
  110    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  111    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  112    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  113    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  114    language_settings::{
  115        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  116        all_language_settings, language_settings,
  117    },
  118    point_from_lsp, text_diff_with_options,
  119};
  120use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  121use linked_editing_ranges::refresh_linked_ranges;
  122use markdown::Markdown;
  123use mouse_context_menu::MouseContextMenu;
  124use persistence::DB;
  125use project::{
  126    BreakpointWithPosition, ProjectPath,
  127    debugger::{
  128        breakpoint_store::{
  129            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  130            BreakpointStoreEvent,
  131        },
  132        session::{Session, SessionEvent},
  133    },
  134    project_settings::DiagnosticSeverity,
  135};
  136
  137pub use git::blame::BlameRenderer;
  138pub use proposed_changes_editor::{
  139    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  140};
  141use smallvec::smallvec;
  142use std::{cell::OnceCell, iter::Peekable, ops::Not};
  143use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  144
  145pub use lsp::CompletionContext;
  146use lsp::{
  147    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  148    LanguageServerId, LanguageServerName,
  149};
  150
  151use language::BufferSnapshot;
  152pub use lsp_ext::lsp_tasks;
  153use movement::TextLayoutDetails;
  154pub use multi_buffer::{
  155    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  156    RowInfo, ToOffset, ToPoint,
  157};
  158use multi_buffer::{
  159    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  160    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  161};
  162use parking_lot::Mutex;
  163use project::{
  164    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  165    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  166    TaskSourceKind,
  167    debugger::breakpoint_store::Breakpoint,
  168    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  169    project_settings::{GitGutterSetting, ProjectSettings},
  170};
  171use rand::prelude::*;
  172use rpc::{ErrorExt, proto::*};
  173use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  174use selections_collection::{
  175    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  176};
  177use serde::{Deserialize, Serialize};
  178use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  179use smallvec::SmallVec;
  180use snippet::Snippet;
  181use std::sync::Arc;
  182use std::{
  183    any::TypeId,
  184    borrow::Cow,
  185    cell::RefCell,
  186    cmp::{self, Ordering, Reverse},
  187    mem,
  188    num::NonZeroU32,
  189    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  190    path::{Path, PathBuf},
  191    rc::Rc,
  192    time::{Duration, Instant},
  193};
  194pub use sum_tree::Bias;
  195use sum_tree::TreeMap;
  196use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  197use theme::{
  198    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  199    observe_buffer_font_size_adjustment,
  200};
  201use ui::{
  202    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  203    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  204};
  205use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  206use workspace::{
  207    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  208    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  209    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  210    item::{ItemHandle, PreviewTabsSettings},
  211    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  212    searchable::SearchEvent,
  213};
  214
  215use crate::hover_links::{find_url, find_url_from_range};
  216use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  217
  218pub const FILE_HEADER_HEIGHT: u32 = 2;
  219pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  220pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  221const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  222const MAX_LINE_LEN: usize = 1024;
  223const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  224const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  225pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  226#[doc(hidden)]
  227pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  228const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  229
  230pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  233
  234pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  235pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  236pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  237pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  238
  239pub type RenderDiffHunkControlsFn = Arc<
  240    dyn Fn(
  241        u32,
  242        &DiffHunkStatus,
  243        Range<Anchor>,
  244        bool,
  245        Pixels,
  246        &Entity<Editor>,
  247        &mut Window,
  248        &mut App,
  249    ) -> AnyElement,
  250>;
  251
  252const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  253    alt: true,
  254    shift: true,
  255    control: false,
  256    platform: false,
  257    function: false,
  258};
  259
  260struct InlineValueCache {
  261    enabled: bool,
  262    inlays: Vec<InlayId>,
  263    refresh_task: Task<Option<()>>,
  264}
  265
  266impl InlineValueCache {
  267    fn new(enabled: bool) -> Self {
  268        Self {
  269            enabled,
  270            inlays: Vec::new(),
  271            refresh_task: Task::ready(None),
  272        }
  273    }
  274}
  275
  276#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  277pub enum InlayId {
  278    InlineCompletion(usize),
  279    Hint(usize),
  280    DebuggerValue(usize),
  281}
  282
  283impl InlayId {
  284    fn id(&self) -> usize {
  285        match self {
  286            Self::InlineCompletion(id) => *id,
  287            Self::Hint(id) => *id,
  288            Self::DebuggerValue(id) => *id,
  289        }
  290    }
  291}
  292
  293pub enum ActiveDebugLine {}
  294pub enum DebugStackFrameLine {}
  295enum DocumentHighlightRead {}
  296enum DocumentHighlightWrite {}
  297enum InputComposition {}
  298enum SelectedTextHighlight {}
  299
  300pub enum ConflictsOuter {}
  301pub enum ConflictsOurs {}
  302pub enum ConflictsTheirs {}
  303pub enum ConflictsOursMarker {}
  304pub enum ConflictsTheirsMarker {}
  305
  306#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  307pub enum Navigated {
  308    Yes,
  309    No,
  310}
  311
  312impl Navigated {
  313    pub fn from_bool(yes: bool) -> Navigated {
  314        if yes { Navigated::Yes } else { Navigated::No }
  315    }
  316}
  317
  318#[derive(Debug, Clone, PartialEq, Eq)]
  319enum DisplayDiffHunk {
  320    Folded {
  321        display_row: DisplayRow,
  322    },
  323    Unfolded {
  324        is_created_file: bool,
  325        diff_base_byte_range: Range<usize>,
  326        display_row_range: Range<DisplayRow>,
  327        multi_buffer_range: Range<Anchor>,
  328        status: DiffHunkStatus,
  329    },
  330}
  331
  332pub enum HideMouseCursorOrigin {
  333    TypingAction,
  334    MovementAction,
  335}
  336
  337pub fn init_settings(cx: &mut App) {
  338    EditorSettings::register(cx);
  339}
  340
  341pub fn init(cx: &mut App) {
  342    init_settings(cx);
  343
  344    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  345
  346    workspace::register_project_item::<Editor>(cx);
  347    workspace::FollowableViewRegistry::register::<Editor>(cx);
  348    workspace::register_serializable_item::<Editor>(cx);
  349
  350    cx.observe_new(
  351        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  352            workspace.register_action(Editor::new_file);
  353            workspace.register_action(Editor::new_file_vertical);
  354            workspace.register_action(Editor::new_file_horizontal);
  355            workspace.register_action(Editor::cancel_language_server_work);
  356        },
  357    )
  358    .detach();
  359
  360    cx.on_action(move |_: &workspace::NewFile, cx| {
  361        let app_state = workspace::AppState::global(cx);
  362        if let Some(app_state) = app_state.upgrade() {
  363            workspace::open_new(
  364                Default::default(),
  365                app_state,
  366                cx,
  367                |workspace, window, cx| {
  368                    Editor::new_file(workspace, &Default::default(), window, cx)
  369                },
  370            )
  371            .detach();
  372        }
  373    });
  374    cx.on_action(move |_: &workspace::NewWindow, cx| {
  375        let app_state = workspace::AppState::global(cx);
  376        if let Some(app_state) = app_state.upgrade() {
  377            workspace::open_new(
  378                Default::default(),
  379                app_state,
  380                cx,
  381                |workspace, window, cx| {
  382                    cx.activate(true);
  383                    Editor::new_file(workspace, &Default::default(), window, cx)
  384                },
  385            )
  386            .detach();
  387        }
  388    });
  389}
  390
  391pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  392    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  393}
  394
  395pub trait DiagnosticRenderer {
  396    fn render_group(
  397        &self,
  398        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  399        buffer_id: BufferId,
  400        snapshot: EditorSnapshot,
  401        editor: WeakEntity<Editor>,
  402        cx: &mut App,
  403    ) -> Vec<BlockProperties<Anchor>>;
  404
  405    fn render_hover(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  408        range: Range<Point>,
  409        buffer_id: BufferId,
  410        cx: &mut App,
  411    ) -> Option<Entity<markdown::Markdown>>;
  412
  413    fn open_link(
  414        &self,
  415        editor: &mut Editor,
  416        link: SharedString,
  417        window: &mut Window,
  418        cx: &mut Context<Editor>,
  419    );
  420}
  421
  422pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  423
  424impl GlobalDiagnosticRenderer {
  425    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  426        cx.try_global::<Self>().map(|g| g.0.clone())
  427    }
  428}
  429
  430impl gpui::Global for GlobalDiagnosticRenderer {}
  431pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  432    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  433}
  434
  435pub struct SearchWithinRange;
  436
  437trait InvalidationRegion {
  438    fn ranges(&self) -> &[Range<Anchor>];
  439}
  440
  441#[derive(Clone, Debug, PartialEq)]
  442pub enum SelectPhase {
  443    Begin {
  444        position: DisplayPoint,
  445        add: bool,
  446        click_count: usize,
  447    },
  448    BeginColumnar {
  449        position: DisplayPoint,
  450        reset: bool,
  451        goal_column: u32,
  452    },
  453    Extend {
  454        position: DisplayPoint,
  455        click_count: usize,
  456    },
  457    Update {
  458        position: DisplayPoint,
  459        goal_column: u32,
  460        scroll_delta: gpui::Point<f32>,
  461    },
  462    End,
  463}
  464
  465#[derive(Clone, Debug)]
  466pub enum SelectMode {
  467    Character,
  468    Word(Range<Anchor>),
  469    Line(Range<Anchor>),
  470    All,
  471}
  472
  473#[derive(Clone, PartialEq, Eq, Debug)]
  474pub enum EditorMode {
  475    SingleLine {
  476        auto_width: bool,
  477    },
  478    AutoHeight {
  479        max_lines: usize,
  480    },
  481    Full {
  482        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  483        scale_ui_elements_with_buffer_font_size: bool,
  484        /// When set to `true`, the editor will render a background for the active line.
  485        show_active_line_background: bool,
  486        /// When set to `true`, the editor's height will be determined by its content.
  487        sized_by_content: bool,
  488    },
  489    Minimap {
  490        parent: WeakEntity<Editor>,
  491    },
  492}
  493
  494impl EditorMode {
  495    pub fn full() -> Self {
  496        Self::Full {
  497            scale_ui_elements_with_buffer_font_size: true,
  498            show_active_line_background: true,
  499            sized_by_content: false,
  500        }
  501    }
  502
  503    pub fn is_full(&self) -> bool {
  504        matches!(self, Self::Full { .. })
  505    }
  506
  507    fn is_minimap(&self) -> bool {
  508        matches!(self, Self::Minimap { .. })
  509    }
  510}
  511
  512#[derive(Copy, Clone, Debug)]
  513pub enum SoftWrap {
  514    /// Prefer not to wrap at all.
  515    ///
  516    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  517    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  518    GitDiff,
  519    /// Prefer a single line generally, unless an overly long line is encountered.
  520    None,
  521    /// Soft wrap lines that exceed the editor width.
  522    EditorWidth,
  523    /// Soft wrap lines at the preferred line length.
  524    Column(u32),
  525    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  526    Bounded(u32),
  527}
  528
  529#[derive(Clone)]
  530pub struct EditorStyle {
  531    pub background: Hsla,
  532    pub local_player: PlayerColor,
  533    pub text: TextStyle,
  534    pub scrollbar_width: Pixels,
  535    pub syntax: Arc<SyntaxTheme>,
  536    pub status: StatusColors,
  537    pub inlay_hints_style: HighlightStyle,
  538    pub inline_completion_styles: InlineCompletionStyles,
  539    pub unnecessary_code_fade: f32,
  540    pub show_underlines: bool,
  541}
  542
  543impl Default for EditorStyle {
  544    fn default() -> Self {
  545        Self {
  546            background: Hsla::default(),
  547            local_player: PlayerColor::default(),
  548            text: TextStyle::default(),
  549            scrollbar_width: Pixels::default(),
  550            syntax: Default::default(),
  551            // HACK: Status colors don't have a real default.
  552            // We should look into removing the status colors from the editor
  553            // style and retrieve them directly from the theme.
  554            status: StatusColors::dark(),
  555            inlay_hints_style: HighlightStyle::default(),
  556            inline_completion_styles: InlineCompletionStyles {
  557                insertion: HighlightStyle::default(),
  558                whitespace: HighlightStyle::default(),
  559            },
  560            unnecessary_code_fade: Default::default(),
  561            show_underlines: true,
  562        }
  563    }
  564}
  565
  566pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  567    let show_background = language_settings::language_settings(None, None, cx)
  568        .inlay_hints
  569        .show_background;
  570
  571    HighlightStyle {
  572        color: Some(cx.theme().status().hint),
  573        background_color: show_background.then(|| cx.theme().status().hint_background),
  574        ..HighlightStyle::default()
  575    }
  576}
  577
  578pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  579    InlineCompletionStyles {
  580        insertion: HighlightStyle {
  581            color: Some(cx.theme().status().predictive),
  582            ..HighlightStyle::default()
  583        },
  584        whitespace: HighlightStyle {
  585            background_color: Some(cx.theme().status().created_background),
  586            ..HighlightStyle::default()
  587        },
  588    }
  589}
  590
  591type CompletionId = usize;
  592
  593pub(crate) enum EditDisplayMode {
  594    TabAccept,
  595    DiffPopover,
  596    Inline,
  597}
  598
  599enum InlineCompletion {
  600    Edit {
  601        edits: Vec<(Range<Anchor>, String)>,
  602        edit_preview: Option<EditPreview>,
  603        display_mode: EditDisplayMode,
  604        snapshot: BufferSnapshot,
  605    },
  606    Move {
  607        target: Anchor,
  608        snapshot: BufferSnapshot,
  609    },
  610}
  611
  612struct InlineCompletionState {
  613    inlay_ids: Vec<InlayId>,
  614    completion: InlineCompletion,
  615    completion_id: Option<SharedString>,
  616    invalidation_range: Range<Anchor>,
  617}
  618
  619enum EditPredictionSettings {
  620    Disabled,
  621    Enabled {
  622        show_in_menu: bool,
  623        preview_requires_modifier: bool,
  624    },
  625}
  626
  627enum InlineCompletionHighlight {}
  628
  629#[derive(Debug, Clone)]
  630struct InlineDiagnostic {
  631    message: SharedString,
  632    group_id: usize,
  633    is_primary: bool,
  634    start: Point,
  635    severity: lsp::DiagnosticSeverity,
  636}
  637
  638pub enum MenuInlineCompletionsPolicy {
  639    Never,
  640    ByProvider,
  641}
  642
  643pub enum EditPredictionPreview {
  644    /// Modifier is not pressed
  645    Inactive { released_too_fast: bool },
  646    /// Modifier pressed
  647    Active {
  648        since: Instant,
  649        previous_scroll_position: Option<ScrollAnchor>,
  650    },
  651}
  652
  653impl EditPredictionPreview {
  654    pub fn released_too_fast(&self) -> bool {
  655        match self {
  656            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  657            EditPredictionPreview::Active { .. } => false,
  658        }
  659    }
  660
  661    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  662        if let EditPredictionPreview::Active {
  663            previous_scroll_position,
  664            ..
  665        } = self
  666        {
  667            *previous_scroll_position = scroll_position;
  668        }
  669    }
  670}
  671
  672pub struct ContextMenuOptions {
  673    pub min_entries_visible: usize,
  674    pub max_entries_visible: usize,
  675    pub placement: Option<ContextMenuPlacement>,
  676}
  677
  678#[derive(Debug, Clone, PartialEq, Eq)]
  679pub enum ContextMenuPlacement {
  680    Above,
  681    Below,
  682}
  683
  684#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  685struct EditorActionId(usize);
  686
  687impl EditorActionId {
  688    pub fn post_inc(&mut self) -> Self {
  689        let answer = self.0;
  690
  691        *self = Self(answer + 1);
  692
  693        Self(answer)
  694    }
  695}
  696
  697// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  698// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  699
  700type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  701type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  702
  703#[derive(Default)]
  704struct ScrollbarMarkerState {
  705    scrollbar_size: Size<Pixels>,
  706    dirty: bool,
  707    markers: Arc<[PaintQuad]>,
  708    pending_refresh: Option<Task<Result<()>>>,
  709}
  710
  711impl ScrollbarMarkerState {
  712    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  713        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  714    }
  715}
  716
  717#[derive(Clone, Copy, PartialEq, Eq)]
  718pub enum MinimapVisibility {
  719    Disabled,
  720    Enabled(bool),
  721}
  722
  723impl MinimapVisibility {
  724    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  725        if mode.is_full() {
  726            Self::Enabled(EditorSettings::get_global(cx).minimap.minimap_enabled())
  727        } else {
  728            Self::Disabled
  729        }
  730    }
  731
  732    fn disabled(&self) -> bool {
  733        match *self {
  734            Self::Disabled => true,
  735            _ => false,
  736        }
  737    }
  738
  739    fn visible(&self) -> bool {
  740        match *self {
  741            Self::Enabled(visible) => visible,
  742            _ => false,
  743        }
  744    }
  745
  746    fn toggle_visibility(&self) -> Self {
  747        match *self {
  748            Self::Enabled(visible) => Self::Enabled(!visible),
  749            Self::Disabled => Self::Disabled,
  750        }
  751    }
  752}
  753
  754#[derive(Clone, Debug)]
  755struct RunnableTasks {
  756    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  757    offset: multi_buffer::Anchor,
  758    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  759    column: u32,
  760    // Values of all named captures, including those starting with '_'
  761    extra_variables: HashMap<String, String>,
  762    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  763    context_range: Range<BufferOffset>,
  764}
  765
  766impl RunnableTasks {
  767    fn resolve<'a>(
  768        &'a self,
  769        cx: &'a task::TaskContext,
  770    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  771        self.templates.iter().filter_map(|(kind, template)| {
  772            template
  773                .resolve_task(&kind.to_id_base(), cx)
  774                .map(|task| (kind.clone(), task))
  775        })
  776    }
  777}
  778
  779#[derive(Clone)]
  780struct ResolvedTasks {
  781    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  782    position: Anchor,
  783}
  784
  785#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  786struct BufferOffset(usize);
  787
  788// Addons allow storing per-editor state in other crates (e.g. Vim)
  789pub trait Addon: 'static {
  790    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  791
  792    fn render_buffer_header_controls(
  793        &self,
  794        _: &ExcerptInfo,
  795        _: &Window,
  796        _: &App,
  797    ) -> Option<AnyElement> {
  798        None
  799    }
  800
  801    fn to_any(&self) -> &dyn std::any::Any;
  802
  803    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  804        None
  805    }
  806}
  807
  808/// A set of caret positions, registered when the editor was edited.
  809pub struct ChangeList {
  810    changes: Vec<Vec<Anchor>>,
  811    /// Currently "selected" change.
  812    position: Option<usize>,
  813}
  814
  815impl ChangeList {
  816    pub fn new() -> Self {
  817        Self {
  818            changes: Vec::new(),
  819            position: None,
  820        }
  821    }
  822
  823    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  824    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  825    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  826        if self.changes.is_empty() {
  827            return None;
  828        }
  829
  830        let prev = self.position.unwrap_or(self.changes.len());
  831        let next = if direction == Direction::Prev {
  832            prev.saturating_sub(count)
  833        } else {
  834            (prev + count).min(self.changes.len() - 1)
  835        };
  836        self.position = Some(next);
  837        self.changes.get(next).map(|anchors| anchors.as_slice())
  838    }
  839
  840    /// Adds a new change to the list, resetting the change list position.
  841    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  842        self.position.take();
  843        if pop_state {
  844            self.changes.pop();
  845        }
  846        self.changes.push(new_positions.clone());
  847    }
  848
  849    pub fn last(&self) -> Option<&[Anchor]> {
  850        self.changes.last().map(|anchors| anchors.as_slice())
  851    }
  852}
  853
  854#[derive(Clone)]
  855struct InlineBlamePopoverState {
  856    scroll_handle: ScrollHandle,
  857    commit_message: Option<ParsedCommitMessage>,
  858    markdown: Entity<Markdown>,
  859}
  860
  861struct InlineBlamePopover {
  862    position: gpui::Point<Pixels>,
  863    show_task: Option<Task<()>>,
  864    hide_task: Option<Task<()>>,
  865    popover_bounds: Option<Bounds<Pixels>>,
  866    popover_state: InlineBlamePopoverState,
  867}
  868
  869/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  870/// a breakpoint on them.
  871#[derive(Clone, Copy, Debug)]
  872struct PhantomBreakpointIndicator {
  873    display_row: DisplayRow,
  874    /// There's a small debounce between hovering over the line and showing the indicator.
  875    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  876    is_active: bool,
  877    collides_with_existing_breakpoint: bool,
  878}
  879/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  880///
  881/// See the [module level documentation](self) for more information.
  882pub struct Editor {
  883    focus_handle: FocusHandle,
  884    last_focused_descendant: Option<WeakFocusHandle>,
  885    /// The text buffer being edited
  886    buffer: Entity<MultiBuffer>,
  887    /// Map of how text in the buffer should be displayed.
  888    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  889    pub display_map: Entity<DisplayMap>,
  890    pub selections: SelectionsCollection,
  891    pub scroll_manager: ScrollManager,
  892    /// When inline assist editors are linked, they all render cursors because
  893    /// typing enters text into each of them, even the ones that aren't focused.
  894    pub(crate) show_cursor_when_unfocused: bool,
  895    columnar_selection_tail: Option<Anchor>,
  896    add_selections_state: Option<AddSelectionsState>,
  897    select_next_state: Option<SelectNextState>,
  898    select_prev_state: Option<SelectNextState>,
  899    selection_history: SelectionHistory,
  900    autoclose_regions: Vec<AutocloseRegion>,
  901    snippet_stack: InvalidationStack<SnippetState>,
  902    select_syntax_node_history: SelectSyntaxNodeHistory,
  903    ime_transaction: Option<TransactionId>,
  904    pub diagnostics_max_severity: DiagnosticSeverity,
  905    active_diagnostics: ActiveDiagnostic,
  906    show_inline_diagnostics: bool,
  907    inline_diagnostics_update: Task<()>,
  908    inline_diagnostics_enabled: bool,
  909    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  910    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  911    hard_wrap: Option<usize>,
  912
  913    // TODO: make this a access method
  914    pub project: Option<Entity<Project>>,
  915    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  916    completion_provider: Option<Box<dyn CompletionProvider>>,
  917    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  918    blink_manager: Entity<BlinkManager>,
  919    show_cursor_names: bool,
  920    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  921    pub show_local_selections: bool,
  922    mode: EditorMode,
  923    show_breadcrumbs: bool,
  924    show_gutter: bool,
  925    show_scrollbars: bool,
  926    minimap_visibility: MinimapVisibility,
  927    disable_expand_excerpt_buttons: bool,
  928    show_line_numbers: Option<bool>,
  929    use_relative_line_numbers: Option<bool>,
  930    show_git_diff_gutter: Option<bool>,
  931    show_code_actions: Option<bool>,
  932    show_runnables: Option<bool>,
  933    show_breakpoints: Option<bool>,
  934    show_wrap_guides: Option<bool>,
  935    show_indent_guides: Option<bool>,
  936    placeholder_text: Option<Arc<str>>,
  937    highlight_order: usize,
  938    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  939    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  940    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  941    scrollbar_marker_state: ScrollbarMarkerState,
  942    active_indent_guides_state: ActiveIndentGuidesState,
  943    nav_history: Option<ItemNavHistory>,
  944    context_menu: RefCell<Option<CodeContextMenu>>,
  945    context_menu_options: Option<ContextMenuOptions>,
  946    mouse_context_menu: Option<MouseContextMenu>,
  947    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  948    inline_blame_popover: Option<InlineBlamePopover>,
  949    signature_help_state: SignatureHelpState,
  950    auto_signature_help: Option<bool>,
  951    find_all_references_task_sources: Vec<Anchor>,
  952    next_completion_id: CompletionId,
  953    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  954    code_actions_task: Option<Task<Result<()>>>,
  955    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  956    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  957    document_highlights_task: Option<Task<()>>,
  958    linked_editing_range_task: Option<Task<Option<()>>>,
  959    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  960    pending_rename: Option<RenameState>,
  961    searchable: bool,
  962    cursor_shape: CursorShape,
  963    current_line_highlight: Option<CurrentLineHighlight>,
  964    collapse_matches: bool,
  965    autoindent_mode: Option<AutoindentMode>,
  966    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  967    input_enabled: bool,
  968    use_modal_editing: bool,
  969    read_only: bool,
  970    leader_id: Option<CollaboratorId>,
  971    remote_id: Option<ViewId>,
  972    pub hover_state: HoverState,
  973    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  974    gutter_hovered: bool,
  975    hovered_link_state: Option<HoveredLinkState>,
  976    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  977    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  978    active_inline_completion: Option<InlineCompletionState>,
  979    /// Used to prevent flickering as the user types while the menu is open
  980    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  981    edit_prediction_settings: EditPredictionSettings,
  982    inline_completions_hidden_for_vim_mode: bool,
  983    show_inline_completions_override: Option<bool>,
  984    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  985    edit_prediction_preview: EditPredictionPreview,
  986    edit_prediction_indent_conflict: bool,
  987    edit_prediction_requires_modifier_in_indent_conflict: bool,
  988    inlay_hint_cache: InlayHintCache,
  989    next_inlay_id: usize,
  990    _subscriptions: Vec<Subscription>,
  991    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  992    gutter_dimensions: GutterDimensions,
  993    style: Option<EditorStyle>,
  994    text_style_refinement: Option<TextStyleRefinement>,
  995    next_editor_action_id: EditorActionId,
  996    editor_actions:
  997        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  998    use_autoclose: bool,
  999    use_auto_surround: bool,
 1000    auto_replace_emoji_shortcode: bool,
 1001    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1002    show_git_blame_gutter: bool,
 1003    show_git_blame_inline: bool,
 1004    show_git_blame_inline_delay_task: Option<Task<()>>,
 1005    git_blame_inline_enabled: bool,
 1006    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1007    serialize_dirty_buffers: bool,
 1008    show_selection_menu: Option<bool>,
 1009    blame: Option<Entity<GitBlame>>,
 1010    blame_subscription: Option<Subscription>,
 1011    custom_context_menu: Option<
 1012        Box<
 1013            dyn 'static
 1014                + Fn(
 1015                    &mut Self,
 1016                    DisplayPoint,
 1017                    &mut Window,
 1018                    &mut Context<Self>,
 1019                ) -> Option<Entity<ui::ContextMenu>>,
 1020        >,
 1021    >,
 1022    last_bounds: Option<Bounds<Pixels>>,
 1023    last_position_map: Option<Rc<PositionMap>>,
 1024    expect_bounds_change: Option<Bounds<Pixels>>,
 1025    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1026    tasks_update_task: Option<Task<()>>,
 1027    breakpoint_store: Option<Entity<BreakpointStore>>,
 1028    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1029    in_project_search: bool,
 1030    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1031    breadcrumb_header: Option<String>,
 1032    focused_block: Option<FocusedBlock>,
 1033    next_scroll_position: NextScrollCursorCenterTopBottom,
 1034    addons: HashMap<TypeId, Box<dyn Addon>>,
 1035    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1036    load_diff_task: Option<Shared<Task<()>>>,
 1037    /// Whether we are temporarily displaying a diff other than git's
 1038    temporary_diff_override: bool,
 1039    selection_mark_mode: bool,
 1040    toggle_fold_multiple_buffers: Task<()>,
 1041    _scroll_cursor_center_top_bottom_task: Task<()>,
 1042    serialize_selections: Task<()>,
 1043    serialize_folds: Task<()>,
 1044    mouse_cursor_hidden: bool,
 1045    minimap: Option<Entity<Self>>,
 1046    hide_mouse_mode: HideMouseMode,
 1047    pub change_list: ChangeList,
 1048    inline_value_cache: InlineValueCache,
 1049}
 1050
 1051#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1052enum NextScrollCursorCenterTopBottom {
 1053    #[default]
 1054    Center,
 1055    Top,
 1056    Bottom,
 1057}
 1058
 1059impl NextScrollCursorCenterTopBottom {
 1060    fn next(&self) -> Self {
 1061        match self {
 1062            Self::Center => Self::Top,
 1063            Self::Top => Self::Bottom,
 1064            Self::Bottom => Self::Center,
 1065        }
 1066    }
 1067}
 1068
 1069#[derive(Clone)]
 1070pub struct EditorSnapshot {
 1071    pub mode: EditorMode,
 1072    show_gutter: bool,
 1073    show_line_numbers: Option<bool>,
 1074    show_git_diff_gutter: Option<bool>,
 1075    show_runnables: Option<bool>,
 1076    show_breakpoints: Option<bool>,
 1077    git_blame_gutter_max_author_length: Option<usize>,
 1078    pub display_snapshot: DisplaySnapshot,
 1079    pub placeholder_text: Option<Arc<str>>,
 1080    is_focused: bool,
 1081    scroll_anchor: ScrollAnchor,
 1082    ongoing_scroll: OngoingScroll,
 1083    current_line_highlight: CurrentLineHighlight,
 1084    gutter_hovered: bool,
 1085}
 1086
 1087#[derive(Default, Debug, Clone, Copy)]
 1088pub struct GutterDimensions {
 1089    pub left_padding: Pixels,
 1090    pub right_padding: Pixels,
 1091    pub width: Pixels,
 1092    pub margin: Pixels,
 1093    pub git_blame_entries_width: Option<Pixels>,
 1094}
 1095
 1096impl GutterDimensions {
 1097    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1098        Self {
 1099            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1100            ..Default::default()
 1101        }
 1102    }
 1103
 1104    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1105        -cx.text_system().descent(font_id, font_size)
 1106    }
 1107    /// The full width of the space taken up by the gutter.
 1108    pub fn full_width(&self) -> Pixels {
 1109        self.margin + self.width
 1110    }
 1111
 1112    /// The width of the space reserved for the fold indicators,
 1113    /// use alongside 'justify_end' and `gutter_width` to
 1114    /// right align content with the line numbers
 1115    pub fn fold_area_width(&self) -> Pixels {
 1116        self.margin + self.right_padding
 1117    }
 1118}
 1119
 1120#[derive(Debug)]
 1121pub struct RemoteSelection {
 1122    pub replica_id: ReplicaId,
 1123    pub selection: Selection<Anchor>,
 1124    pub cursor_shape: CursorShape,
 1125    pub collaborator_id: CollaboratorId,
 1126    pub line_mode: bool,
 1127    pub user_name: Option<SharedString>,
 1128    pub color: PlayerColor,
 1129}
 1130
 1131#[derive(Clone, Debug)]
 1132struct SelectionHistoryEntry {
 1133    selections: Arc<[Selection<Anchor>]>,
 1134    select_next_state: Option<SelectNextState>,
 1135    select_prev_state: Option<SelectNextState>,
 1136    add_selections_state: Option<AddSelectionsState>,
 1137}
 1138
 1139enum SelectionHistoryMode {
 1140    Normal,
 1141    Undoing,
 1142    Redoing,
 1143}
 1144
 1145#[derive(Clone, PartialEq, Eq, Hash)]
 1146struct HoveredCursor {
 1147    replica_id: u16,
 1148    selection_id: usize,
 1149}
 1150
 1151impl Default for SelectionHistoryMode {
 1152    fn default() -> Self {
 1153        Self::Normal
 1154    }
 1155}
 1156
 1157#[derive(Default)]
 1158struct SelectionHistory {
 1159    #[allow(clippy::type_complexity)]
 1160    selections_by_transaction:
 1161        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1162    mode: SelectionHistoryMode,
 1163    undo_stack: VecDeque<SelectionHistoryEntry>,
 1164    redo_stack: VecDeque<SelectionHistoryEntry>,
 1165}
 1166
 1167impl SelectionHistory {
 1168    fn insert_transaction(
 1169        &mut self,
 1170        transaction_id: TransactionId,
 1171        selections: Arc<[Selection<Anchor>]>,
 1172    ) {
 1173        self.selections_by_transaction
 1174            .insert(transaction_id, (selections, None));
 1175    }
 1176
 1177    #[allow(clippy::type_complexity)]
 1178    fn transaction(
 1179        &self,
 1180        transaction_id: TransactionId,
 1181    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1182        self.selections_by_transaction.get(&transaction_id)
 1183    }
 1184
 1185    #[allow(clippy::type_complexity)]
 1186    fn transaction_mut(
 1187        &mut self,
 1188        transaction_id: TransactionId,
 1189    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1190        self.selections_by_transaction.get_mut(&transaction_id)
 1191    }
 1192
 1193    fn push(&mut self, entry: SelectionHistoryEntry) {
 1194        if !entry.selections.is_empty() {
 1195            match self.mode {
 1196                SelectionHistoryMode::Normal => {
 1197                    self.push_undo(entry);
 1198                    self.redo_stack.clear();
 1199                }
 1200                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1201                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1202            }
 1203        }
 1204    }
 1205
 1206    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1207        if self
 1208            .undo_stack
 1209            .back()
 1210            .map_or(true, |e| e.selections != entry.selections)
 1211        {
 1212            self.undo_stack.push_back(entry);
 1213            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1214                self.undo_stack.pop_front();
 1215            }
 1216        }
 1217    }
 1218
 1219    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1220        if self
 1221            .redo_stack
 1222            .back()
 1223            .map_or(true, |e| e.selections != entry.selections)
 1224        {
 1225            self.redo_stack.push_back(entry);
 1226            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1227                self.redo_stack.pop_front();
 1228            }
 1229        }
 1230    }
 1231}
 1232
 1233#[derive(Clone, Copy)]
 1234pub struct RowHighlightOptions {
 1235    pub autoscroll: bool,
 1236    pub include_gutter: bool,
 1237}
 1238
 1239impl Default for RowHighlightOptions {
 1240    fn default() -> Self {
 1241        Self {
 1242            autoscroll: Default::default(),
 1243            include_gutter: true,
 1244        }
 1245    }
 1246}
 1247
 1248struct RowHighlight {
 1249    index: usize,
 1250    range: Range<Anchor>,
 1251    color: Hsla,
 1252    options: RowHighlightOptions,
 1253    type_id: TypeId,
 1254}
 1255
 1256#[derive(Clone, Debug)]
 1257struct AddSelectionsState {
 1258    above: bool,
 1259    stack: Vec<usize>,
 1260}
 1261
 1262#[derive(Clone)]
 1263struct SelectNextState {
 1264    query: AhoCorasick,
 1265    wordwise: bool,
 1266    done: bool,
 1267}
 1268
 1269impl std::fmt::Debug for SelectNextState {
 1270    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1271        f.debug_struct(std::any::type_name::<Self>())
 1272            .field("wordwise", &self.wordwise)
 1273            .field("done", &self.done)
 1274            .finish()
 1275    }
 1276}
 1277
 1278#[derive(Debug)]
 1279struct AutocloseRegion {
 1280    selection_id: usize,
 1281    range: Range<Anchor>,
 1282    pair: BracketPair,
 1283}
 1284
 1285#[derive(Debug)]
 1286struct SnippetState {
 1287    ranges: Vec<Vec<Range<Anchor>>>,
 1288    active_index: usize,
 1289    choices: Vec<Option<Vec<String>>>,
 1290}
 1291
 1292#[doc(hidden)]
 1293pub struct RenameState {
 1294    pub range: Range<Anchor>,
 1295    pub old_name: Arc<str>,
 1296    pub editor: Entity<Editor>,
 1297    block_id: CustomBlockId,
 1298}
 1299
 1300struct InvalidationStack<T>(Vec<T>);
 1301
 1302struct RegisteredInlineCompletionProvider {
 1303    provider: Arc<dyn InlineCompletionProviderHandle>,
 1304    _subscription: Subscription,
 1305}
 1306
 1307#[derive(Debug, PartialEq, Eq)]
 1308pub struct ActiveDiagnosticGroup {
 1309    pub active_range: Range<Anchor>,
 1310    pub active_message: String,
 1311    pub group_id: usize,
 1312    pub blocks: HashSet<CustomBlockId>,
 1313}
 1314
 1315#[derive(Debug, PartialEq, Eq)]
 1316
 1317pub(crate) enum ActiveDiagnostic {
 1318    None,
 1319    All,
 1320    Group(ActiveDiagnosticGroup),
 1321}
 1322
 1323#[derive(Serialize, Deserialize, Clone, Debug)]
 1324pub struct ClipboardSelection {
 1325    /// The number of bytes in this selection.
 1326    pub len: usize,
 1327    /// Whether this was a full-line selection.
 1328    pub is_entire_line: bool,
 1329    /// The indentation of the first line when this content was originally copied.
 1330    pub first_line_indent: u32,
 1331}
 1332
 1333// selections, scroll behavior, was newest selection reversed
 1334type SelectSyntaxNodeHistoryState = (
 1335    Box<[Selection<usize>]>,
 1336    SelectSyntaxNodeScrollBehavior,
 1337    bool,
 1338);
 1339
 1340#[derive(Default)]
 1341struct SelectSyntaxNodeHistory {
 1342    stack: Vec<SelectSyntaxNodeHistoryState>,
 1343    // disable temporarily to allow changing selections without losing the stack
 1344    pub disable_clearing: bool,
 1345}
 1346
 1347impl SelectSyntaxNodeHistory {
 1348    pub fn try_clear(&mut self) {
 1349        if !self.disable_clearing {
 1350            self.stack.clear();
 1351        }
 1352    }
 1353
 1354    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1355        self.stack.push(selection);
 1356    }
 1357
 1358    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1359        self.stack.pop()
 1360    }
 1361}
 1362
 1363enum SelectSyntaxNodeScrollBehavior {
 1364    CursorTop,
 1365    FitSelection,
 1366    CursorBottom,
 1367}
 1368
 1369#[derive(Debug)]
 1370pub(crate) struct NavigationData {
 1371    cursor_anchor: Anchor,
 1372    cursor_position: Point,
 1373    scroll_anchor: ScrollAnchor,
 1374    scroll_top_row: u32,
 1375}
 1376
 1377#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1378pub enum GotoDefinitionKind {
 1379    Symbol,
 1380    Declaration,
 1381    Type,
 1382    Implementation,
 1383}
 1384
 1385#[derive(Debug, Clone)]
 1386enum InlayHintRefreshReason {
 1387    ModifiersChanged(bool),
 1388    Toggle(bool),
 1389    SettingsChange(InlayHintSettings),
 1390    NewLinesShown,
 1391    BufferEdited(HashSet<Arc<Language>>),
 1392    RefreshRequested,
 1393    ExcerptsRemoved(Vec<ExcerptId>),
 1394}
 1395
 1396impl InlayHintRefreshReason {
 1397    fn description(&self) -> &'static str {
 1398        match self {
 1399            Self::ModifiersChanged(_) => "modifiers changed",
 1400            Self::Toggle(_) => "toggle",
 1401            Self::SettingsChange(_) => "settings change",
 1402            Self::NewLinesShown => "new lines shown",
 1403            Self::BufferEdited(_) => "buffer edited",
 1404            Self::RefreshRequested => "refresh requested",
 1405            Self::ExcerptsRemoved(_) => "excerpts removed",
 1406        }
 1407    }
 1408}
 1409
 1410pub enum FormatTarget {
 1411    Buffers,
 1412    Ranges(Vec<Range<MultiBufferPoint>>),
 1413}
 1414
 1415pub(crate) struct FocusedBlock {
 1416    id: BlockId,
 1417    focus_handle: WeakFocusHandle,
 1418}
 1419
 1420#[derive(Clone)]
 1421enum JumpData {
 1422    MultiBufferRow {
 1423        row: MultiBufferRow,
 1424        line_offset_from_top: u32,
 1425    },
 1426    MultiBufferPoint {
 1427        excerpt_id: ExcerptId,
 1428        position: Point,
 1429        anchor: text::Anchor,
 1430        line_offset_from_top: u32,
 1431    },
 1432}
 1433
 1434pub enum MultibufferSelectionMode {
 1435    First,
 1436    All,
 1437}
 1438
 1439#[derive(Clone, Copy, Debug, Default)]
 1440pub struct RewrapOptions {
 1441    pub override_language_settings: bool,
 1442    pub preserve_existing_whitespace: bool,
 1443}
 1444
 1445impl Editor {
 1446    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1447        let buffer = cx.new(|cx| Buffer::local("", cx));
 1448        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1449        Self::new(
 1450            EditorMode::SingleLine { auto_width: false },
 1451            buffer,
 1452            None,
 1453            window,
 1454            cx,
 1455        )
 1456    }
 1457
 1458    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1459        let buffer = cx.new(|cx| Buffer::local("", cx));
 1460        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1461        Self::new(EditorMode::full(), buffer, None, window, cx)
 1462    }
 1463
 1464    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1465        let buffer = cx.new(|cx| Buffer::local("", cx));
 1466        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1467        Self::new(
 1468            EditorMode::SingleLine { auto_width: true },
 1469            buffer,
 1470            None,
 1471            window,
 1472            cx,
 1473        )
 1474    }
 1475
 1476    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1477        let buffer = cx.new(|cx| Buffer::local("", cx));
 1478        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1479        Self::new(
 1480            EditorMode::AutoHeight { max_lines },
 1481            buffer,
 1482            None,
 1483            window,
 1484            cx,
 1485        )
 1486    }
 1487
 1488    pub fn for_buffer(
 1489        buffer: Entity<Buffer>,
 1490        project: Option<Entity<Project>>,
 1491        window: &mut Window,
 1492        cx: &mut Context<Self>,
 1493    ) -> Self {
 1494        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1495        Self::new(EditorMode::full(), buffer, project, window, cx)
 1496    }
 1497
 1498    pub fn for_multibuffer(
 1499        buffer: Entity<MultiBuffer>,
 1500        project: Option<Entity<Project>>,
 1501        window: &mut Window,
 1502        cx: &mut Context<Self>,
 1503    ) -> Self {
 1504        Self::new(EditorMode::full(), buffer, project, window, cx)
 1505    }
 1506
 1507    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1508        let mut clone = Self::new(
 1509            self.mode.clone(),
 1510            self.buffer.clone(),
 1511            self.project.clone(),
 1512            window,
 1513            cx,
 1514        );
 1515        self.display_map.update(cx, |display_map, cx| {
 1516            let snapshot = display_map.snapshot(cx);
 1517            clone.display_map.update(cx, |display_map, cx| {
 1518                display_map.set_state(&snapshot, cx);
 1519            });
 1520        });
 1521        clone.folds_did_change(cx);
 1522        clone.selections.clone_state(&self.selections);
 1523        clone.scroll_manager.clone_state(&self.scroll_manager);
 1524        clone.searchable = self.searchable;
 1525        clone.read_only = self.read_only;
 1526        clone
 1527    }
 1528
 1529    pub fn new(
 1530        mode: EditorMode,
 1531        buffer: Entity<MultiBuffer>,
 1532        project: Option<Entity<Project>>,
 1533        window: &mut Window,
 1534        cx: &mut Context<Self>,
 1535    ) -> Self {
 1536        Editor::new_internal(mode, buffer, project, None, window, cx)
 1537    }
 1538
 1539    fn new_internal(
 1540        mode: EditorMode,
 1541        buffer: Entity<MultiBuffer>,
 1542        project: Option<Entity<Project>>,
 1543        display_map: Option<Entity<DisplayMap>>,
 1544        window: &mut Window,
 1545        cx: &mut Context<Self>,
 1546    ) -> Self {
 1547        debug_assert!(
 1548            display_map.is_none() || mode.is_minimap(),
 1549            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1550        );
 1551
 1552        let full_mode = mode.is_full();
 1553        let diagnostics_max_severity = if full_mode {
 1554            EditorSettings::get_global(cx)
 1555                .diagnostics_max_severity
 1556                .unwrap_or(DiagnosticSeverity::Hint)
 1557        } else {
 1558            DiagnosticSeverity::Off
 1559        };
 1560        let style = window.text_style();
 1561        let font_size = style.font_size.to_pixels(window.rem_size());
 1562        let editor = cx.entity().downgrade();
 1563        let fold_placeholder = FoldPlaceholder {
 1564            constrain_width: true,
 1565            render: Arc::new(move |fold_id, fold_range, cx| {
 1566                let editor = editor.clone();
 1567                div()
 1568                    .id(fold_id)
 1569                    .bg(cx.theme().colors().ghost_element_background)
 1570                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1571                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1572                    .rounded_xs()
 1573                    .size_full()
 1574                    .cursor_pointer()
 1575                    .child("")
 1576                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1577                    .on_click(move |_, _window, cx| {
 1578                        editor
 1579                            .update(cx, |editor, cx| {
 1580                                editor.unfold_ranges(
 1581                                    &[fold_range.start..fold_range.end],
 1582                                    true,
 1583                                    false,
 1584                                    cx,
 1585                                );
 1586                                cx.stop_propagation();
 1587                            })
 1588                            .ok();
 1589                    })
 1590                    .into_any()
 1591            }),
 1592            merge_adjacent: true,
 1593            ..FoldPlaceholder::default()
 1594        };
 1595        let display_map = display_map.unwrap_or_else(|| {
 1596            cx.new(|cx| {
 1597                DisplayMap::new(
 1598                    buffer.clone(),
 1599                    style.font(),
 1600                    font_size,
 1601                    None,
 1602                    FILE_HEADER_HEIGHT,
 1603                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1604                    fold_placeholder,
 1605                    diagnostics_max_severity,
 1606                    cx,
 1607                )
 1608            })
 1609        });
 1610
 1611        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1612
 1613        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1614
 1615        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1616            .then(|| language_settings::SoftWrap::None);
 1617
 1618        let mut project_subscriptions = Vec::new();
 1619        if mode.is_full() {
 1620            if let Some(project) = project.as_ref() {
 1621                project_subscriptions.push(cx.subscribe_in(
 1622                    project,
 1623                    window,
 1624                    |editor, _, event, window, cx| match event {
 1625                        project::Event::RefreshCodeLens => {
 1626                            // we always query lens with actions, without storing them, always refreshing them
 1627                        }
 1628                        project::Event::RefreshInlayHints => {
 1629                            editor
 1630                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1631                        }
 1632                        project::Event::SnippetEdit(id, snippet_edits) => {
 1633                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1634                                let focus_handle = editor.focus_handle(cx);
 1635                                if focus_handle.is_focused(window) {
 1636                                    let snapshot = buffer.read(cx).snapshot();
 1637                                    for (range, snippet) in snippet_edits {
 1638                                        let editor_range =
 1639                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1640                                        editor
 1641                                            .insert_snippet(
 1642                                                &[editor_range],
 1643                                                snippet.clone(),
 1644                                                window,
 1645                                                cx,
 1646                                            )
 1647                                            .ok();
 1648                                    }
 1649                                }
 1650                            }
 1651                        }
 1652                        _ => {}
 1653                    },
 1654                ));
 1655                if let Some(task_inventory) = project
 1656                    .read(cx)
 1657                    .task_store()
 1658                    .read(cx)
 1659                    .task_inventory()
 1660                    .cloned()
 1661                {
 1662                    project_subscriptions.push(cx.observe_in(
 1663                        &task_inventory,
 1664                        window,
 1665                        |editor, _, window, cx| {
 1666                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1667                        },
 1668                    ));
 1669                };
 1670
 1671                project_subscriptions.push(cx.subscribe_in(
 1672                    &project.read(cx).breakpoint_store(),
 1673                    window,
 1674                    |editor, _, event, window, cx| match event {
 1675                        BreakpointStoreEvent::ClearDebugLines => {
 1676                            editor.clear_row_highlights::<ActiveDebugLine>();
 1677                            editor.refresh_inline_values(cx);
 1678                        }
 1679                        BreakpointStoreEvent::SetDebugLine => {
 1680                            if editor.go_to_active_debug_line(window, cx) {
 1681                                cx.stop_propagation();
 1682                            }
 1683
 1684                            editor.refresh_inline_values(cx);
 1685                        }
 1686                        _ => {}
 1687                    },
 1688                ));
 1689            }
 1690        }
 1691
 1692        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1693
 1694        let inlay_hint_settings =
 1695            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1696        let focus_handle = cx.focus_handle();
 1697        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1698            .detach();
 1699        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1700            .detach();
 1701        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1702            .detach();
 1703        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1704            .detach();
 1705
 1706        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1707            Some(false)
 1708        } else {
 1709            None
 1710        };
 1711
 1712        let breakpoint_store = match (&mode, project.as_ref()) {
 1713            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1714            _ => None,
 1715        };
 1716
 1717        let mut code_action_providers = Vec::new();
 1718        let mut load_uncommitted_diff = None;
 1719        if let Some(project) = project.clone() {
 1720            load_uncommitted_diff = Some(
 1721                update_uncommitted_diff_for_buffer(
 1722                    cx.entity(),
 1723                    &project,
 1724                    buffer.read(cx).all_buffers(),
 1725                    buffer.clone(),
 1726                    cx,
 1727                )
 1728                .shared(),
 1729            );
 1730            code_action_providers.push(Rc::new(project) as Rc<_>);
 1731        }
 1732
 1733        let mut this = Self {
 1734            focus_handle,
 1735            show_cursor_when_unfocused: false,
 1736            last_focused_descendant: None,
 1737            buffer: buffer.clone(),
 1738            display_map: display_map.clone(),
 1739            selections,
 1740            scroll_manager: ScrollManager::new(cx),
 1741            columnar_selection_tail: None,
 1742            add_selections_state: None,
 1743            select_next_state: None,
 1744            select_prev_state: None,
 1745            selection_history: SelectionHistory::default(),
 1746            autoclose_regions: Vec::new(),
 1747            snippet_stack: InvalidationStack::default(),
 1748            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1749            ime_transaction: None,
 1750            active_diagnostics: ActiveDiagnostic::None,
 1751            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1752            inline_diagnostics_update: Task::ready(()),
 1753            inline_diagnostics: Vec::new(),
 1754            soft_wrap_mode_override,
 1755            diagnostics_max_severity,
 1756            hard_wrap: None,
 1757            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1758            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1759            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1760            project,
 1761            blink_manager: blink_manager.clone(),
 1762            show_local_selections: true,
 1763            show_scrollbars: full_mode,
 1764            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1765            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1766            show_gutter: mode.is_full(),
 1767            show_line_numbers: None,
 1768            use_relative_line_numbers: None,
 1769            disable_expand_excerpt_buttons: false,
 1770            show_git_diff_gutter: None,
 1771            show_code_actions: None,
 1772            show_runnables: None,
 1773            show_breakpoints: None,
 1774            show_wrap_guides: None,
 1775            show_indent_guides,
 1776            placeholder_text: None,
 1777            highlight_order: 0,
 1778            highlighted_rows: HashMap::default(),
 1779            background_highlights: TreeMap::default(),
 1780            gutter_highlights: TreeMap::default(),
 1781            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1782            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1783            nav_history: None,
 1784            context_menu: RefCell::new(None),
 1785            context_menu_options: None,
 1786            mouse_context_menu: None,
 1787            completion_tasks: Vec::new(),
 1788            inline_blame_popover: None,
 1789            signature_help_state: SignatureHelpState::default(),
 1790            auto_signature_help: None,
 1791            find_all_references_task_sources: Vec::new(),
 1792            next_completion_id: 0,
 1793            next_inlay_id: 0,
 1794            code_action_providers,
 1795            available_code_actions: None,
 1796            code_actions_task: None,
 1797            quick_selection_highlight_task: None,
 1798            debounced_selection_highlight_task: None,
 1799            document_highlights_task: None,
 1800            linked_editing_range_task: None,
 1801            pending_rename: None,
 1802            searchable: true,
 1803            cursor_shape: EditorSettings::get_global(cx)
 1804                .cursor_shape
 1805                .unwrap_or_default(),
 1806            current_line_highlight: None,
 1807            autoindent_mode: Some(AutoindentMode::EachLine),
 1808            collapse_matches: false,
 1809            workspace: None,
 1810            input_enabled: true,
 1811            use_modal_editing: mode.is_full(),
 1812            read_only: mode.is_minimap(),
 1813            use_autoclose: true,
 1814            use_auto_surround: true,
 1815            auto_replace_emoji_shortcode: false,
 1816            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1817            leader_id: None,
 1818            remote_id: None,
 1819            hover_state: HoverState::default(),
 1820            pending_mouse_down: None,
 1821            hovered_link_state: None,
 1822            edit_prediction_provider: None,
 1823            active_inline_completion: None,
 1824            stale_inline_completion_in_menu: None,
 1825            edit_prediction_preview: EditPredictionPreview::Inactive {
 1826                released_too_fast: false,
 1827            },
 1828            inline_diagnostics_enabled: mode.is_full(),
 1829            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1830            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1831
 1832            gutter_hovered: false,
 1833            pixel_position_of_newest_cursor: None,
 1834            last_bounds: None,
 1835            last_position_map: None,
 1836            expect_bounds_change: None,
 1837            gutter_dimensions: GutterDimensions::default(),
 1838            style: None,
 1839            show_cursor_names: false,
 1840            hovered_cursors: HashMap::default(),
 1841            next_editor_action_id: EditorActionId::default(),
 1842            editor_actions: Rc::default(),
 1843            inline_completions_hidden_for_vim_mode: false,
 1844            show_inline_completions_override: None,
 1845            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1846            edit_prediction_settings: EditPredictionSettings::Disabled,
 1847            edit_prediction_indent_conflict: false,
 1848            edit_prediction_requires_modifier_in_indent_conflict: true,
 1849            custom_context_menu: None,
 1850            show_git_blame_gutter: false,
 1851            show_git_blame_inline: false,
 1852            show_selection_menu: None,
 1853            show_git_blame_inline_delay_task: None,
 1854            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1855            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1856            serialize_dirty_buffers: !mode.is_minimap()
 1857                && ProjectSettings::get_global(cx)
 1858                    .session
 1859                    .restore_unsaved_buffers,
 1860            blame: None,
 1861            blame_subscription: None,
 1862            tasks: BTreeMap::default(),
 1863
 1864            breakpoint_store,
 1865            gutter_breakpoint_indicator: (None, None),
 1866            _subscriptions: vec![
 1867                cx.observe(&buffer, Self::on_buffer_changed),
 1868                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1869                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1870                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1871                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1872                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1873                cx.observe_window_activation(window, |editor, window, cx| {
 1874                    let active = window.is_window_active();
 1875                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1876                        if active {
 1877                            blink_manager.enable(cx);
 1878                        } else {
 1879                            blink_manager.disable(cx);
 1880                        }
 1881                    });
 1882                }),
 1883            ],
 1884            tasks_update_task: None,
 1885            linked_edit_ranges: Default::default(),
 1886            in_project_search: false,
 1887            previous_search_ranges: None,
 1888            breadcrumb_header: None,
 1889            focused_block: None,
 1890            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1891            addons: HashMap::default(),
 1892            registered_buffers: HashMap::default(),
 1893            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1894            selection_mark_mode: false,
 1895            toggle_fold_multiple_buffers: Task::ready(()),
 1896            serialize_selections: Task::ready(()),
 1897            serialize_folds: Task::ready(()),
 1898            text_style_refinement: None,
 1899            load_diff_task: load_uncommitted_diff,
 1900            temporary_diff_override: false,
 1901            mouse_cursor_hidden: false,
 1902            minimap: None,
 1903            hide_mouse_mode: EditorSettings::get_global(cx)
 1904                .hide_mouse
 1905                .unwrap_or_default(),
 1906            change_list: ChangeList::new(),
 1907            mode,
 1908        };
 1909        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1910            this._subscriptions
 1911                .push(cx.observe(breakpoints, |_, _, cx| {
 1912                    cx.notify();
 1913                }));
 1914        }
 1915        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1916        this._subscriptions.extend(project_subscriptions);
 1917
 1918        this._subscriptions.push(cx.subscribe_in(
 1919            &cx.entity(),
 1920            window,
 1921            |editor, _, e: &EditorEvent, window, cx| match e {
 1922                EditorEvent::ScrollPositionChanged { local, .. } => {
 1923                    if *local {
 1924                        let new_anchor = editor.scroll_manager.anchor();
 1925                        let snapshot = editor.snapshot(window, cx);
 1926                        editor.update_restoration_data(cx, move |data| {
 1927                            data.scroll_position = (
 1928                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1929                                new_anchor.offset,
 1930                            );
 1931                        });
 1932                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1933                        editor.inline_blame_popover.take();
 1934                    }
 1935                }
 1936                EditorEvent::Edited { .. } => {
 1937                    if !vim_enabled(cx) {
 1938                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1939                        let pop_state = editor
 1940                            .change_list
 1941                            .last()
 1942                            .map(|previous| {
 1943                                previous.len() == selections.len()
 1944                                    && previous.iter().enumerate().all(|(ix, p)| {
 1945                                        p.to_display_point(&map).row()
 1946                                            == selections[ix].head().row()
 1947                                    })
 1948                            })
 1949                            .unwrap_or(false);
 1950                        let new_positions = selections
 1951                            .into_iter()
 1952                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1953                            .collect();
 1954                        editor
 1955                            .change_list
 1956                            .push_to_change_list(pop_state, new_positions);
 1957                    }
 1958                }
 1959                _ => (),
 1960            },
 1961        ));
 1962
 1963        if let Some(dap_store) = this
 1964            .project
 1965            .as_ref()
 1966            .map(|project| project.read(cx).dap_store())
 1967        {
 1968            let weak_editor = cx.weak_entity();
 1969
 1970            this._subscriptions
 1971                .push(
 1972                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1973                        let session_entity = cx.entity();
 1974                        weak_editor
 1975                            .update(cx, |editor, cx| {
 1976                                editor._subscriptions.push(
 1977                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1978                                );
 1979                            })
 1980                            .ok();
 1981                    }),
 1982                );
 1983
 1984            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1985                this._subscriptions
 1986                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1987            }
 1988        }
 1989
 1990        this.end_selection(window, cx);
 1991        this.scroll_manager.show_scrollbars(window, cx);
 1992        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1993
 1994        if full_mode {
 1995            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1996            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1997
 1998            if this.git_blame_inline_enabled {
 1999                this.start_git_blame_inline(false, window, cx);
 2000            }
 2001
 2002            this.go_to_active_debug_line(window, cx);
 2003
 2004            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2005                if let Some(project) = this.project.as_ref() {
 2006                    let handle = project.update(cx, |project, cx| {
 2007                        project.register_buffer_with_language_servers(&buffer, cx)
 2008                    });
 2009                    this.registered_buffers
 2010                        .insert(buffer.read(cx).remote_id(), handle);
 2011                }
 2012            }
 2013
 2014            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2015        }
 2016
 2017        this.report_editor_event("Editor Opened", None, cx);
 2018        this
 2019    }
 2020
 2021    pub fn deploy_mouse_context_menu(
 2022        &mut self,
 2023        position: gpui::Point<Pixels>,
 2024        context_menu: Entity<ContextMenu>,
 2025        window: &mut Window,
 2026        cx: &mut Context<Self>,
 2027    ) {
 2028        self.mouse_context_menu = Some(MouseContextMenu::new(
 2029            self,
 2030            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2031            context_menu,
 2032            window,
 2033            cx,
 2034        ));
 2035    }
 2036
 2037    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2038        self.mouse_context_menu
 2039            .as_ref()
 2040            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2041    }
 2042
 2043    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2044        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2045    }
 2046
 2047    fn key_context_internal(
 2048        &self,
 2049        has_active_edit_prediction: bool,
 2050        window: &Window,
 2051        cx: &App,
 2052    ) -> KeyContext {
 2053        let mut key_context = KeyContext::new_with_defaults();
 2054        key_context.add("Editor");
 2055        let mode = match self.mode {
 2056            EditorMode::SingleLine { .. } => "single_line",
 2057            EditorMode::AutoHeight { .. } => "auto_height",
 2058            EditorMode::Minimap { .. } => "minimap",
 2059            EditorMode::Full { .. } => "full",
 2060        };
 2061
 2062        if EditorSettings::jupyter_enabled(cx) {
 2063            key_context.add("jupyter");
 2064        }
 2065
 2066        key_context.set("mode", mode);
 2067        if self.pending_rename.is_some() {
 2068            key_context.add("renaming");
 2069        }
 2070
 2071        match self.context_menu.borrow().as_ref() {
 2072            Some(CodeContextMenu::Completions(_)) => {
 2073                key_context.add("menu");
 2074                key_context.add("showing_completions");
 2075            }
 2076            Some(CodeContextMenu::CodeActions(_)) => {
 2077                key_context.add("menu");
 2078                key_context.add("showing_code_actions")
 2079            }
 2080            None => {}
 2081        }
 2082
 2083        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2084        if !self.focus_handle(cx).contains_focused(window, cx)
 2085            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2086        {
 2087            for addon in self.addons.values() {
 2088                addon.extend_key_context(&mut key_context, cx)
 2089            }
 2090        }
 2091
 2092        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2093            if let Some(extension) = singleton_buffer
 2094                .read(cx)
 2095                .file()
 2096                .and_then(|file| file.path().extension()?.to_str())
 2097            {
 2098                key_context.set("extension", extension.to_string());
 2099            }
 2100        } else {
 2101            key_context.add("multibuffer");
 2102        }
 2103
 2104        if has_active_edit_prediction {
 2105            if self.edit_prediction_in_conflict() {
 2106                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2107            } else {
 2108                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2109                key_context.add("copilot_suggestion");
 2110            }
 2111        }
 2112
 2113        if self.selection_mark_mode {
 2114            key_context.add("selection_mode");
 2115        }
 2116
 2117        key_context
 2118    }
 2119
 2120    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2121        self.mouse_cursor_hidden = match origin {
 2122            HideMouseCursorOrigin::TypingAction => {
 2123                matches!(
 2124                    self.hide_mouse_mode,
 2125                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2126                )
 2127            }
 2128            HideMouseCursorOrigin::MovementAction => {
 2129                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2130            }
 2131        };
 2132    }
 2133
 2134    pub fn edit_prediction_in_conflict(&self) -> bool {
 2135        if !self.show_edit_predictions_in_menu() {
 2136            return false;
 2137        }
 2138
 2139        let showing_completions = self
 2140            .context_menu
 2141            .borrow()
 2142            .as_ref()
 2143            .map_or(false, |context| {
 2144                matches!(context, CodeContextMenu::Completions(_))
 2145            });
 2146
 2147        showing_completions
 2148            || self.edit_prediction_requires_modifier()
 2149            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2150            // bindings to insert tab characters.
 2151            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2152    }
 2153
 2154    pub fn accept_edit_prediction_keybind(
 2155        &self,
 2156        window: &Window,
 2157        cx: &App,
 2158    ) -> AcceptEditPredictionBinding {
 2159        let key_context = self.key_context_internal(true, window, cx);
 2160        let in_conflict = self.edit_prediction_in_conflict();
 2161
 2162        AcceptEditPredictionBinding(
 2163            window
 2164                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2165                .into_iter()
 2166                .filter(|binding| {
 2167                    !in_conflict
 2168                        || binding
 2169                            .keystrokes()
 2170                            .first()
 2171                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2172                })
 2173                .rev()
 2174                .min_by_key(|binding| {
 2175                    binding
 2176                        .keystrokes()
 2177                        .first()
 2178                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2179                }),
 2180        )
 2181    }
 2182
 2183    pub fn new_file(
 2184        workspace: &mut Workspace,
 2185        _: &workspace::NewFile,
 2186        window: &mut Window,
 2187        cx: &mut Context<Workspace>,
 2188    ) {
 2189        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2190            "Failed to create buffer",
 2191            window,
 2192            cx,
 2193            |e, _, _| match e.error_code() {
 2194                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2195                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2196                e.error_tag("required").unwrap_or("the latest version")
 2197            )),
 2198                _ => None,
 2199            },
 2200        );
 2201    }
 2202
 2203    pub fn new_in_workspace(
 2204        workspace: &mut Workspace,
 2205        window: &mut Window,
 2206        cx: &mut Context<Workspace>,
 2207    ) -> Task<Result<Entity<Editor>>> {
 2208        let project = workspace.project().clone();
 2209        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2210
 2211        cx.spawn_in(window, async move |workspace, cx| {
 2212            let buffer = create.await?;
 2213            workspace.update_in(cx, |workspace, window, cx| {
 2214                let editor =
 2215                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2216                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2217                editor
 2218            })
 2219        })
 2220    }
 2221
 2222    fn new_file_vertical(
 2223        workspace: &mut Workspace,
 2224        _: &workspace::NewFileSplitVertical,
 2225        window: &mut Window,
 2226        cx: &mut Context<Workspace>,
 2227    ) {
 2228        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2229    }
 2230
 2231    fn new_file_horizontal(
 2232        workspace: &mut Workspace,
 2233        _: &workspace::NewFileSplitHorizontal,
 2234        window: &mut Window,
 2235        cx: &mut Context<Workspace>,
 2236    ) {
 2237        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2238    }
 2239
 2240    fn new_file_in_direction(
 2241        workspace: &mut Workspace,
 2242        direction: SplitDirection,
 2243        window: &mut Window,
 2244        cx: &mut Context<Workspace>,
 2245    ) {
 2246        let project = workspace.project().clone();
 2247        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2248
 2249        cx.spawn_in(window, async move |workspace, cx| {
 2250            let buffer = create.await?;
 2251            workspace.update_in(cx, move |workspace, window, cx| {
 2252                workspace.split_item(
 2253                    direction,
 2254                    Box::new(
 2255                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2256                    ),
 2257                    window,
 2258                    cx,
 2259                )
 2260            })?;
 2261            anyhow::Ok(())
 2262        })
 2263        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2264            match e.error_code() {
 2265                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2266                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2267                e.error_tag("required").unwrap_or("the latest version")
 2268            )),
 2269                _ => None,
 2270            }
 2271        });
 2272    }
 2273
 2274    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2275        self.leader_id
 2276    }
 2277
 2278    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2279        &self.buffer
 2280    }
 2281
 2282    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2283        self.workspace.as_ref()?.0.upgrade()
 2284    }
 2285
 2286    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2287        self.buffer().read(cx).title(cx)
 2288    }
 2289
 2290    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2291        let git_blame_gutter_max_author_length = self
 2292            .render_git_blame_gutter(cx)
 2293            .then(|| {
 2294                if let Some(blame) = self.blame.as_ref() {
 2295                    let max_author_length =
 2296                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2297                    Some(max_author_length)
 2298                } else {
 2299                    None
 2300                }
 2301            })
 2302            .flatten();
 2303
 2304        EditorSnapshot {
 2305            mode: self.mode.clone(),
 2306            show_gutter: self.show_gutter,
 2307            show_line_numbers: self.show_line_numbers,
 2308            show_git_diff_gutter: self.show_git_diff_gutter,
 2309            show_runnables: self.show_runnables,
 2310            show_breakpoints: self.show_breakpoints,
 2311            git_blame_gutter_max_author_length,
 2312            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2313            scroll_anchor: self.scroll_manager.anchor(),
 2314            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2315            placeholder_text: self.placeholder_text.clone(),
 2316            is_focused: self.focus_handle.is_focused(window),
 2317            current_line_highlight: self
 2318                .current_line_highlight
 2319                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2320            gutter_hovered: self.gutter_hovered,
 2321        }
 2322    }
 2323
 2324    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2325        self.buffer.read(cx).language_at(point, cx)
 2326    }
 2327
 2328    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2329        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2330    }
 2331
 2332    pub fn active_excerpt(
 2333        &self,
 2334        cx: &App,
 2335    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2336        self.buffer
 2337            .read(cx)
 2338            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2339    }
 2340
 2341    pub fn mode(&self) -> &EditorMode {
 2342        &self.mode
 2343    }
 2344
 2345    pub fn set_mode(&mut self, mode: EditorMode) {
 2346        self.mode = mode;
 2347    }
 2348
 2349    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2350        self.collaboration_hub.as_deref()
 2351    }
 2352
 2353    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2354        self.collaboration_hub = Some(hub);
 2355    }
 2356
 2357    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2358        self.in_project_search = in_project_search;
 2359    }
 2360
 2361    pub fn set_custom_context_menu(
 2362        &mut self,
 2363        f: impl 'static
 2364        + Fn(
 2365            &mut Self,
 2366            DisplayPoint,
 2367            &mut Window,
 2368            &mut Context<Self>,
 2369        ) -> Option<Entity<ui::ContextMenu>>,
 2370    ) {
 2371        self.custom_context_menu = Some(Box::new(f))
 2372    }
 2373
 2374    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2375        self.completion_provider = provider;
 2376    }
 2377
 2378    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2379        self.semantics_provider.clone()
 2380    }
 2381
 2382    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2383        self.semantics_provider = provider;
 2384    }
 2385
 2386    pub fn set_edit_prediction_provider<T>(
 2387        &mut self,
 2388        provider: Option<Entity<T>>,
 2389        window: &mut Window,
 2390        cx: &mut Context<Self>,
 2391    ) where
 2392        T: EditPredictionProvider,
 2393    {
 2394        self.edit_prediction_provider =
 2395            provider.map(|provider| RegisteredInlineCompletionProvider {
 2396                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2397                    if this.focus_handle.is_focused(window) {
 2398                        this.update_visible_inline_completion(window, cx);
 2399                    }
 2400                }),
 2401                provider: Arc::new(provider),
 2402            });
 2403        self.update_edit_prediction_settings(cx);
 2404        self.refresh_inline_completion(false, false, window, cx);
 2405    }
 2406
 2407    pub fn placeholder_text(&self) -> Option<&str> {
 2408        self.placeholder_text.as_deref()
 2409    }
 2410
 2411    pub fn set_placeholder_text(
 2412        &mut self,
 2413        placeholder_text: impl Into<Arc<str>>,
 2414        cx: &mut Context<Self>,
 2415    ) {
 2416        let placeholder_text = Some(placeholder_text.into());
 2417        if self.placeholder_text != placeholder_text {
 2418            self.placeholder_text = placeholder_text;
 2419            cx.notify();
 2420        }
 2421    }
 2422
 2423    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2424        self.cursor_shape = cursor_shape;
 2425
 2426        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2427        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2428
 2429        cx.notify();
 2430    }
 2431
 2432    pub fn set_current_line_highlight(
 2433        &mut self,
 2434        current_line_highlight: Option<CurrentLineHighlight>,
 2435    ) {
 2436        self.current_line_highlight = current_line_highlight;
 2437    }
 2438
 2439    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2440        self.collapse_matches = collapse_matches;
 2441    }
 2442
 2443    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2444        let buffers = self.buffer.read(cx).all_buffers();
 2445        let Some(project) = self.project.as_ref() else {
 2446            return;
 2447        };
 2448        project.update(cx, |project, cx| {
 2449            for buffer in buffers {
 2450                self.registered_buffers
 2451                    .entry(buffer.read(cx).remote_id())
 2452                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2453            }
 2454        })
 2455    }
 2456
 2457    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2458        if self.collapse_matches {
 2459            return range.start..range.start;
 2460        }
 2461        range.clone()
 2462    }
 2463
 2464    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2465        if self.display_map.read(cx).clip_at_line_ends != clip {
 2466            self.display_map
 2467                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2468        }
 2469    }
 2470
 2471    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2472        self.input_enabled = input_enabled;
 2473    }
 2474
 2475    pub fn set_inline_completions_hidden_for_vim_mode(
 2476        &mut self,
 2477        hidden: bool,
 2478        window: &mut Window,
 2479        cx: &mut Context<Self>,
 2480    ) {
 2481        if hidden != self.inline_completions_hidden_for_vim_mode {
 2482            self.inline_completions_hidden_for_vim_mode = hidden;
 2483            if hidden {
 2484                self.update_visible_inline_completion(window, cx);
 2485            } else {
 2486                self.refresh_inline_completion(true, false, window, cx);
 2487            }
 2488        }
 2489    }
 2490
 2491    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2492        self.menu_inline_completions_policy = value;
 2493    }
 2494
 2495    pub fn set_autoindent(&mut self, autoindent: bool) {
 2496        if autoindent {
 2497            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2498        } else {
 2499            self.autoindent_mode = None;
 2500        }
 2501    }
 2502
 2503    pub fn read_only(&self, cx: &App) -> bool {
 2504        self.read_only || self.buffer.read(cx).read_only()
 2505    }
 2506
 2507    pub fn set_read_only(&mut self, read_only: bool) {
 2508        self.read_only = read_only;
 2509    }
 2510
 2511    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2512        self.use_autoclose = autoclose;
 2513    }
 2514
 2515    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2516        self.use_auto_surround = auto_surround;
 2517    }
 2518
 2519    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2520        self.auto_replace_emoji_shortcode = auto_replace;
 2521    }
 2522
 2523    pub fn toggle_edit_predictions(
 2524        &mut self,
 2525        _: &ToggleEditPrediction,
 2526        window: &mut Window,
 2527        cx: &mut Context<Self>,
 2528    ) {
 2529        if self.show_inline_completions_override.is_some() {
 2530            self.set_show_edit_predictions(None, window, cx);
 2531        } else {
 2532            let show_edit_predictions = !self.edit_predictions_enabled();
 2533            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2534        }
 2535    }
 2536
 2537    pub fn set_show_edit_predictions(
 2538        &mut self,
 2539        show_edit_predictions: Option<bool>,
 2540        window: &mut Window,
 2541        cx: &mut Context<Self>,
 2542    ) {
 2543        self.show_inline_completions_override = show_edit_predictions;
 2544        self.update_edit_prediction_settings(cx);
 2545
 2546        if let Some(false) = show_edit_predictions {
 2547            self.discard_inline_completion(false, cx);
 2548        } else {
 2549            self.refresh_inline_completion(false, true, window, cx);
 2550        }
 2551    }
 2552
 2553    fn inline_completions_disabled_in_scope(
 2554        &self,
 2555        buffer: &Entity<Buffer>,
 2556        buffer_position: language::Anchor,
 2557        cx: &App,
 2558    ) -> bool {
 2559        let snapshot = buffer.read(cx).snapshot();
 2560        let settings = snapshot.settings_at(buffer_position, cx);
 2561
 2562        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2563            return false;
 2564        };
 2565
 2566        scope.override_name().map_or(false, |scope_name| {
 2567            settings
 2568                .edit_predictions_disabled_in
 2569                .iter()
 2570                .any(|s| s == scope_name)
 2571        })
 2572    }
 2573
 2574    pub fn set_use_modal_editing(&mut self, to: bool) {
 2575        self.use_modal_editing = to;
 2576    }
 2577
 2578    pub fn use_modal_editing(&self) -> bool {
 2579        self.use_modal_editing
 2580    }
 2581
 2582    fn selections_did_change(
 2583        &mut self,
 2584        local: bool,
 2585        old_cursor_position: &Anchor,
 2586        show_completions: bool,
 2587        window: &mut Window,
 2588        cx: &mut Context<Self>,
 2589    ) {
 2590        window.invalidate_character_coordinates();
 2591
 2592        // Copy selections to primary selection buffer
 2593        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2594        if local {
 2595            let selections = self.selections.all::<usize>(cx);
 2596            let buffer_handle = self.buffer.read(cx).read(cx);
 2597
 2598            let mut text = String::new();
 2599            for (index, selection) in selections.iter().enumerate() {
 2600                let text_for_selection = buffer_handle
 2601                    .text_for_range(selection.start..selection.end)
 2602                    .collect::<String>();
 2603
 2604                text.push_str(&text_for_selection);
 2605                if index != selections.len() - 1 {
 2606                    text.push('\n');
 2607                }
 2608            }
 2609
 2610            if !text.is_empty() {
 2611                cx.write_to_primary(ClipboardItem::new_string(text));
 2612            }
 2613        }
 2614
 2615        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2616            self.buffer.update(cx, |buffer, cx| {
 2617                buffer.set_active_selections(
 2618                    &self.selections.disjoint_anchors(),
 2619                    self.selections.line_mode,
 2620                    self.cursor_shape,
 2621                    cx,
 2622                )
 2623            });
 2624        }
 2625        let display_map = self
 2626            .display_map
 2627            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2628        let buffer = &display_map.buffer_snapshot;
 2629        self.add_selections_state = None;
 2630        self.select_next_state = None;
 2631        self.select_prev_state = None;
 2632        self.select_syntax_node_history.try_clear();
 2633        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2634        self.snippet_stack
 2635            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2636        self.take_rename(false, window, cx);
 2637
 2638        let new_cursor_position = self.selections.newest_anchor().head();
 2639
 2640        self.push_to_nav_history(
 2641            *old_cursor_position,
 2642            Some(new_cursor_position.to_point(buffer)),
 2643            false,
 2644            cx,
 2645        );
 2646
 2647        if local {
 2648            let new_cursor_position = self.selections.newest_anchor().head();
 2649            let mut context_menu = self.context_menu.borrow_mut();
 2650            let completion_menu = match context_menu.as_ref() {
 2651                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2652                _ => {
 2653                    *context_menu = None;
 2654                    None
 2655                }
 2656            };
 2657            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2658                if !self.registered_buffers.contains_key(&buffer_id) {
 2659                    if let Some(project) = self.project.as_ref() {
 2660                        project.update(cx, |project, cx| {
 2661                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2662                                return;
 2663                            };
 2664                            self.registered_buffers.insert(
 2665                                buffer_id,
 2666                                project.register_buffer_with_language_servers(&buffer, cx),
 2667                            );
 2668                        })
 2669                    }
 2670                }
 2671            }
 2672
 2673            if let Some(completion_menu) = completion_menu {
 2674                let cursor_position = new_cursor_position.to_offset(buffer);
 2675                let (word_range, kind) =
 2676                    buffer.surrounding_word(completion_menu.initial_position, true);
 2677                if kind == Some(CharKind::Word)
 2678                    && word_range.to_inclusive().contains(&cursor_position)
 2679                {
 2680                    let mut completion_menu = completion_menu.clone();
 2681                    drop(context_menu);
 2682
 2683                    let query = Self::completion_query(buffer, cursor_position);
 2684                    cx.spawn(async move |this, cx| {
 2685                        completion_menu
 2686                            .filter(query.as_deref(), cx.background_executor().clone())
 2687                            .await;
 2688
 2689                        this.update(cx, |this, cx| {
 2690                            let mut context_menu = this.context_menu.borrow_mut();
 2691                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2692                            else {
 2693                                return;
 2694                            };
 2695
 2696                            if menu.id > completion_menu.id {
 2697                                return;
 2698                            }
 2699
 2700                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2701                            drop(context_menu);
 2702                            cx.notify();
 2703                        })
 2704                    })
 2705                    .detach();
 2706
 2707                    if show_completions {
 2708                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2709                    }
 2710                } else {
 2711                    drop(context_menu);
 2712                    self.hide_context_menu(window, cx);
 2713                }
 2714            } else {
 2715                drop(context_menu);
 2716            }
 2717
 2718            hide_hover(self, cx);
 2719
 2720            if old_cursor_position.to_display_point(&display_map).row()
 2721                != new_cursor_position.to_display_point(&display_map).row()
 2722            {
 2723                self.available_code_actions.take();
 2724            }
 2725            self.refresh_code_actions(window, cx);
 2726            self.refresh_document_highlights(cx);
 2727            self.refresh_selected_text_highlights(false, window, cx);
 2728            refresh_matching_bracket_highlights(self, window, cx);
 2729            self.update_visible_inline_completion(window, cx);
 2730            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2731            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2732            self.inline_blame_popover.take();
 2733            if self.git_blame_inline_enabled {
 2734                self.start_inline_blame_timer(window, cx);
 2735            }
 2736        }
 2737
 2738        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2739        cx.emit(EditorEvent::SelectionsChanged { local });
 2740
 2741        let selections = &self.selections.disjoint;
 2742        if selections.len() == 1 {
 2743            cx.emit(SearchEvent::ActiveMatchChanged)
 2744        }
 2745        if local {
 2746            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2747                let inmemory_selections = selections
 2748                    .iter()
 2749                    .map(|s| {
 2750                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2751                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2752                    })
 2753                    .collect();
 2754                self.update_restoration_data(cx, |data| {
 2755                    data.selections = inmemory_selections;
 2756                });
 2757
 2758                if WorkspaceSettings::get(None, cx).restore_on_startup
 2759                    != RestoreOnStartupBehavior::None
 2760                {
 2761                    if let Some(workspace_id) =
 2762                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2763                    {
 2764                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2765                        let selections = selections.clone();
 2766                        let background_executor = cx.background_executor().clone();
 2767                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2768                        self.serialize_selections = cx.background_spawn(async move {
 2769                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2770                    let db_selections = selections
 2771                        .iter()
 2772                        .map(|selection| {
 2773                            (
 2774                                selection.start.to_offset(&snapshot),
 2775                                selection.end.to_offset(&snapshot),
 2776                            )
 2777                        })
 2778                        .collect();
 2779
 2780                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2781                        .await
 2782                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2783                        .log_err();
 2784                });
 2785                    }
 2786                }
 2787            }
 2788        }
 2789
 2790        cx.notify();
 2791    }
 2792
 2793    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2794        use text::ToOffset as _;
 2795        use text::ToPoint as _;
 2796
 2797        if self.mode.is_minimap()
 2798            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2799        {
 2800            return;
 2801        }
 2802
 2803        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2804            return;
 2805        };
 2806
 2807        let snapshot = singleton.read(cx).snapshot();
 2808        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2809            let display_snapshot = display_map.snapshot(cx);
 2810
 2811            display_snapshot
 2812                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2813                .map(|fold| {
 2814                    fold.range.start.text_anchor.to_point(&snapshot)
 2815                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2816                })
 2817                .collect()
 2818        });
 2819        self.update_restoration_data(cx, |data| {
 2820            data.folds = inmemory_folds;
 2821        });
 2822
 2823        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2824            return;
 2825        };
 2826        let background_executor = cx.background_executor().clone();
 2827        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2828        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2829            display_map
 2830                .snapshot(cx)
 2831                .folds_in_range(0..snapshot.len())
 2832                .map(|fold| {
 2833                    (
 2834                        fold.range.start.text_anchor.to_offset(&snapshot),
 2835                        fold.range.end.text_anchor.to_offset(&snapshot),
 2836                    )
 2837                })
 2838                .collect()
 2839        });
 2840        self.serialize_folds = cx.background_spawn(async move {
 2841            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2842            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2843                .await
 2844                .with_context(|| {
 2845                    format!(
 2846                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2847                    )
 2848                })
 2849                .log_err();
 2850        });
 2851    }
 2852
 2853    pub fn sync_selections(
 2854        &mut self,
 2855        other: Entity<Editor>,
 2856        cx: &mut Context<Self>,
 2857    ) -> gpui::Subscription {
 2858        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2859        self.selections.change_with(cx, |selections| {
 2860            selections.select_anchors(other_selections);
 2861        });
 2862
 2863        let other_subscription =
 2864            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2865                EditorEvent::SelectionsChanged { local: true } => {
 2866                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2867                    if other_selections.is_empty() {
 2868                        return;
 2869                    }
 2870                    this.selections.change_with(cx, |selections| {
 2871                        selections.select_anchors(other_selections);
 2872                    });
 2873                }
 2874                _ => {}
 2875            });
 2876
 2877        let this_subscription =
 2878            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2879                EditorEvent::SelectionsChanged { local: true } => {
 2880                    let these_selections = this.selections.disjoint.to_vec();
 2881                    if these_selections.is_empty() {
 2882                        return;
 2883                    }
 2884                    other.update(cx, |other_editor, cx| {
 2885                        other_editor.selections.change_with(cx, |selections| {
 2886                            selections.select_anchors(these_selections);
 2887                        })
 2888                    });
 2889                }
 2890                _ => {}
 2891            });
 2892
 2893        Subscription::join(other_subscription, this_subscription)
 2894    }
 2895
 2896    pub fn change_selections<R>(
 2897        &mut self,
 2898        autoscroll: Option<Autoscroll>,
 2899        window: &mut Window,
 2900        cx: &mut Context<Self>,
 2901        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2902    ) -> R {
 2903        self.change_selections_inner(autoscroll, true, window, cx, change)
 2904    }
 2905
 2906    fn change_selections_inner<R>(
 2907        &mut self,
 2908        autoscroll: Option<Autoscroll>,
 2909        request_completions: bool,
 2910        window: &mut Window,
 2911        cx: &mut Context<Self>,
 2912        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2913    ) -> R {
 2914        let old_cursor_position = self.selections.newest_anchor().head();
 2915        self.push_to_selection_history();
 2916
 2917        let (changed, result) = self.selections.change_with(cx, change);
 2918
 2919        if changed {
 2920            if let Some(autoscroll) = autoscroll {
 2921                self.request_autoscroll(autoscroll, cx);
 2922            }
 2923            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2924
 2925            if self.should_open_signature_help_automatically(
 2926                &old_cursor_position,
 2927                self.signature_help_state.backspace_pressed(),
 2928                cx,
 2929            ) {
 2930                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2931            }
 2932            self.signature_help_state.set_backspace_pressed(false);
 2933        }
 2934
 2935        result
 2936    }
 2937
 2938    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2939    where
 2940        I: IntoIterator<Item = (Range<S>, T)>,
 2941        S: ToOffset,
 2942        T: Into<Arc<str>>,
 2943    {
 2944        if self.read_only(cx) {
 2945            return;
 2946        }
 2947
 2948        self.buffer
 2949            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2950    }
 2951
 2952    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2953    where
 2954        I: IntoIterator<Item = (Range<S>, T)>,
 2955        S: ToOffset,
 2956        T: Into<Arc<str>>,
 2957    {
 2958        if self.read_only(cx) {
 2959            return;
 2960        }
 2961
 2962        self.buffer.update(cx, |buffer, cx| {
 2963            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2964        });
 2965    }
 2966
 2967    pub fn edit_with_block_indent<I, S, T>(
 2968        &mut self,
 2969        edits: I,
 2970        original_indent_columns: Vec<Option<u32>>,
 2971        cx: &mut Context<Self>,
 2972    ) where
 2973        I: IntoIterator<Item = (Range<S>, T)>,
 2974        S: ToOffset,
 2975        T: Into<Arc<str>>,
 2976    {
 2977        if self.read_only(cx) {
 2978            return;
 2979        }
 2980
 2981        self.buffer.update(cx, |buffer, cx| {
 2982            buffer.edit(
 2983                edits,
 2984                Some(AutoindentMode::Block {
 2985                    original_indent_columns,
 2986                }),
 2987                cx,
 2988            )
 2989        });
 2990    }
 2991
 2992    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2993        self.hide_context_menu(window, cx);
 2994
 2995        match phase {
 2996            SelectPhase::Begin {
 2997                position,
 2998                add,
 2999                click_count,
 3000            } => self.begin_selection(position, add, click_count, window, cx),
 3001            SelectPhase::BeginColumnar {
 3002                position,
 3003                goal_column,
 3004                reset,
 3005            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3006            SelectPhase::Extend {
 3007                position,
 3008                click_count,
 3009            } => self.extend_selection(position, click_count, window, cx),
 3010            SelectPhase::Update {
 3011                position,
 3012                goal_column,
 3013                scroll_delta,
 3014            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3015            SelectPhase::End => self.end_selection(window, cx),
 3016        }
 3017    }
 3018
 3019    fn extend_selection(
 3020        &mut self,
 3021        position: DisplayPoint,
 3022        click_count: usize,
 3023        window: &mut Window,
 3024        cx: &mut Context<Self>,
 3025    ) {
 3026        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3027        let tail = self.selections.newest::<usize>(cx).tail();
 3028        self.begin_selection(position, false, click_count, window, cx);
 3029
 3030        let position = position.to_offset(&display_map, Bias::Left);
 3031        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3032
 3033        let mut pending_selection = self
 3034            .selections
 3035            .pending_anchor()
 3036            .expect("extend_selection not called with pending selection");
 3037        if position >= tail {
 3038            pending_selection.start = tail_anchor;
 3039        } else {
 3040            pending_selection.end = tail_anchor;
 3041            pending_selection.reversed = true;
 3042        }
 3043
 3044        let mut pending_mode = self.selections.pending_mode().unwrap();
 3045        match &mut pending_mode {
 3046            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3047            _ => {}
 3048        }
 3049
 3050        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3051
 3052        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3053            s.set_pending(pending_selection, pending_mode)
 3054        });
 3055    }
 3056
 3057    fn begin_selection(
 3058        &mut self,
 3059        position: DisplayPoint,
 3060        add: bool,
 3061        click_count: usize,
 3062        window: &mut Window,
 3063        cx: &mut Context<Self>,
 3064    ) {
 3065        if !self.focus_handle.is_focused(window) {
 3066            self.last_focused_descendant = None;
 3067            window.focus(&self.focus_handle);
 3068        }
 3069
 3070        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3071        let buffer = &display_map.buffer_snapshot;
 3072        let position = display_map.clip_point(position, Bias::Left);
 3073
 3074        let start;
 3075        let end;
 3076        let mode;
 3077        let mut auto_scroll;
 3078        match click_count {
 3079            1 => {
 3080                start = buffer.anchor_before(position.to_point(&display_map));
 3081                end = start;
 3082                mode = SelectMode::Character;
 3083                auto_scroll = true;
 3084            }
 3085            2 => {
 3086                let range = movement::surrounding_word(&display_map, position);
 3087                start = buffer.anchor_before(range.start.to_point(&display_map));
 3088                end = buffer.anchor_before(range.end.to_point(&display_map));
 3089                mode = SelectMode::Word(start..end);
 3090                auto_scroll = true;
 3091            }
 3092            3 => {
 3093                let position = display_map
 3094                    .clip_point(position, Bias::Left)
 3095                    .to_point(&display_map);
 3096                let line_start = display_map.prev_line_boundary(position).0;
 3097                let next_line_start = buffer.clip_point(
 3098                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3099                    Bias::Left,
 3100                );
 3101                start = buffer.anchor_before(line_start);
 3102                end = buffer.anchor_before(next_line_start);
 3103                mode = SelectMode::Line(start..end);
 3104                auto_scroll = true;
 3105            }
 3106            _ => {
 3107                start = buffer.anchor_before(0);
 3108                end = buffer.anchor_before(buffer.len());
 3109                mode = SelectMode::All;
 3110                auto_scroll = false;
 3111            }
 3112        }
 3113        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3114
 3115        let point_to_delete: Option<usize> = {
 3116            let selected_points: Vec<Selection<Point>> =
 3117                self.selections.disjoint_in_range(start..end, cx);
 3118
 3119            if !add || click_count > 1 {
 3120                None
 3121            } else if !selected_points.is_empty() {
 3122                Some(selected_points[0].id)
 3123            } else {
 3124                let clicked_point_already_selected =
 3125                    self.selections.disjoint.iter().find(|selection| {
 3126                        selection.start.to_point(buffer) == start.to_point(buffer)
 3127                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3128                    });
 3129
 3130                clicked_point_already_selected.map(|selection| selection.id)
 3131            }
 3132        };
 3133
 3134        let selections_count = self.selections.count();
 3135
 3136        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3137            if let Some(point_to_delete) = point_to_delete {
 3138                s.delete(point_to_delete);
 3139
 3140                if selections_count == 1 {
 3141                    s.set_pending_anchor_range(start..end, mode);
 3142                }
 3143            } else {
 3144                if !add {
 3145                    s.clear_disjoint();
 3146                }
 3147
 3148                s.set_pending_anchor_range(start..end, mode);
 3149            }
 3150        });
 3151    }
 3152
 3153    fn begin_columnar_selection(
 3154        &mut self,
 3155        position: DisplayPoint,
 3156        goal_column: u32,
 3157        reset: bool,
 3158        window: &mut Window,
 3159        cx: &mut Context<Self>,
 3160    ) {
 3161        if !self.focus_handle.is_focused(window) {
 3162            self.last_focused_descendant = None;
 3163            window.focus(&self.focus_handle);
 3164        }
 3165
 3166        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3167
 3168        if reset {
 3169            let pointer_position = display_map
 3170                .buffer_snapshot
 3171                .anchor_before(position.to_point(&display_map));
 3172
 3173            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3174                s.clear_disjoint();
 3175                s.set_pending_anchor_range(
 3176                    pointer_position..pointer_position,
 3177                    SelectMode::Character,
 3178                );
 3179            });
 3180        }
 3181
 3182        let tail = self.selections.newest::<Point>(cx).tail();
 3183        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3184
 3185        if !reset {
 3186            self.select_columns(
 3187                tail.to_display_point(&display_map),
 3188                position,
 3189                goal_column,
 3190                &display_map,
 3191                window,
 3192                cx,
 3193            );
 3194        }
 3195    }
 3196
 3197    fn update_selection(
 3198        &mut self,
 3199        position: DisplayPoint,
 3200        goal_column: u32,
 3201        scroll_delta: gpui::Point<f32>,
 3202        window: &mut Window,
 3203        cx: &mut Context<Self>,
 3204    ) {
 3205        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3206
 3207        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3208            let tail = tail.to_display_point(&display_map);
 3209            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3210        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3211            let buffer = self.buffer.read(cx).snapshot(cx);
 3212            let head;
 3213            let tail;
 3214            let mode = self.selections.pending_mode().unwrap();
 3215            match &mode {
 3216                SelectMode::Character => {
 3217                    head = position.to_point(&display_map);
 3218                    tail = pending.tail().to_point(&buffer);
 3219                }
 3220                SelectMode::Word(original_range) => {
 3221                    let original_display_range = original_range.start.to_display_point(&display_map)
 3222                        ..original_range.end.to_display_point(&display_map);
 3223                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3224                        ..original_display_range.end.to_point(&display_map);
 3225                    if movement::is_inside_word(&display_map, position)
 3226                        || original_display_range.contains(&position)
 3227                    {
 3228                        let word_range = movement::surrounding_word(&display_map, position);
 3229                        if word_range.start < original_display_range.start {
 3230                            head = word_range.start.to_point(&display_map);
 3231                        } else {
 3232                            head = word_range.end.to_point(&display_map);
 3233                        }
 3234                    } else {
 3235                        head = position.to_point(&display_map);
 3236                    }
 3237
 3238                    if head <= original_buffer_range.start {
 3239                        tail = original_buffer_range.end;
 3240                    } else {
 3241                        tail = original_buffer_range.start;
 3242                    }
 3243                }
 3244                SelectMode::Line(original_range) => {
 3245                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3246
 3247                    let position = display_map
 3248                        .clip_point(position, Bias::Left)
 3249                        .to_point(&display_map);
 3250                    let line_start = display_map.prev_line_boundary(position).0;
 3251                    let next_line_start = buffer.clip_point(
 3252                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3253                        Bias::Left,
 3254                    );
 3255
 3256                    if line_start < original_range.start {
 3257                        head = line_start
 3258                    } else {
 3259                        head = next_line_start
 3260                    }
 3261
 3262                    if head <= original_range.start {
 3263                        tail = original_range.end;
 3264                    } else {
 3265                        tail = original_range.start;
 3266                    }
 3267                }
 3268                SelectMode::All => {
 3269                    return;
 3270                }
 3271            };
 3272
 3273            if head < tail {
 3274                pending.start = buffer.anchor_before(head);
 3275                pending.end = buffer.anchor_before(tail);
 3276                pending.reversed = true;
 3277            } else {
 3278                pending.start = buffer.anchor_before(tail);
 3279                pending.end = buffer.anchor_before(head);
 3280                pending.reversed = false;
 3281            }
 3282
 3283            self.change_selections(None, window, cx, |s| {
 3284                s.set_pending(pending, mode);
 3285            });
 3286        } else {
 3287            log::error!("update_selection dispatched with no pending selection");
 3288            return;
 3289        }
 3290
 3291        self.apply_scroll_delta(scroll_delta, window, cx);
 3292        cx.notify();
 3293    }
 3294
 3295    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3296        self.columnar_selection_tail.take();
 3297        if self.selections.pending_anchor().is_some() {
 3298            let selections = self.selections.all::<usize>(cx);
 3299            self.change_selections(None, window, cx, |s| {
 3300                s.select(selections);
 3301                s.clear_pending();
 3302            });
 3303        }
 3304    }
 3305
 3306    fn select_columns(
 3307        &mut self,
 3308        tail: DisplayPoint,
 3309        head: DisplayPoint,
 3310        goal_column: u32,
 3311        display_map: &DisplaySnapshot,
 3312        window: &mut Window,
 3313        cx: &mut Context<Self>,
 3314    ) {
 3315        let start_row = cmp::min(tail.row(), head.row());
 3316        let end_row = cmp::max(tail.row(), head.row());
 3317        let start_column = cmp::min(tail.column(), goal_column);
 3318        let end_column = cmp::max(tail.column(), goal_column);
 3319        let reversed = start_column < tail.column();
 3320
 3321        let selection_ranges = (start_row.0..=end_row.0)
 3322            .map(DisplayRow)
 3323            .filter_map(|row| {
 3324                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3325                    let start = display_map
 3326                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3327                        .to_point(display_map);
 3328                    let end = display_map
 3329                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3330                        .to_point(display_map);
 3331                    if reversed {
 3332                        Some(end..start)
 3333                    } else {
 3334                        Some(start..end)
 3335                    }
 3336                } else {
 3337                    None
 3338                }
 3339            })
 3340            .collect::<Vec<_>>();
 3341
 3342        self.change_selections(None, window, cx, |s| {
 3343            s.select_ranges(selection_ranges);
 3344        });
 3345        cx.notify();
 3346    }
 3347
 3348    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3349        self.selections
 3350            .all_adjusted(cx)
 3351            .iter()
 3352            .any(|selection| !selection.is_empty())
 3353    }
 3354
 3355    pub fn has_pending_nonempty_selection(&self) -> bool {
 3356        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3357            Some(Selection { start, end, .. }) => start != end,
 3358            None => false,
 3359        };
 3360
 3361        pending_nonempty_selection
 3362            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3363    }
 3364
 3365    pub fn has_pending_selection(&self) -> bool {
 3366        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3367    }
 3368
 3369    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3370        self.selection_mark_mode = false;
 3371
 3372        if self.clear_expanded_diff_hunks(cx) {
 3373            cx.notify();
 3374            return;
 3375        }
 3376        if self.dismiss_menus_and_popups(true, window, cx) {
 3377            return;
 3378        }
 3379
 3380        if self.mode.is_full()
 3381            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3382        {
 3383            return;
 3384        }
 3385
 3386        cx.propagate();
 3387    }
 3388
 3389    pub fn dismiss_menus_and_popups(
 3390        &mut self,
 3391        is_user_requested: bool,
 3392        window: &mut Window,
 3393        cx: &mut Context<Self>,
 3394    ) -> bool {
 3395        if self.take_rename(false, window, cx).is_some() {
 3396            return true;
 3397        }
 3398
 3399        if hide_hover(self, cx) {
 3400            return true;
 3401        }
 3402
 3403        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3404            return true;
 3405        }
 3406
 3407        if self.hide_context_menu(window, cx).is_some() {
 3408            return true;
 3409        }
 3410
 3411        if self.mouse_context_menu.take().is_some() {
 3412            return true;
 3413        }
 3414
 3415        if is_user_requested && self.discard_inline_completion(true, cx) {
 3416            return true;
 3417        }
 3418
 3419        if self.snippet_stack.pop().is_some() {
 3420            return true;
 3421        }
 3422
 3423        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3424            self.dismiss_diagnostics(cx);
 3425            return true;
 3426        }
 3427
 3428        false
 3429    }
 3430
 3431    fn linked_editing_ranges_for(
 3432        &self,
 3433        selection: Range<text::Anchor>,
 3434        cx: &App,
 3435    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3436        if self.linked_edit_ranges.is_empty() {
 3437            return None;
 3438        }
 3439        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3440            selection.end.buffer_id.and_then(|end_buffer_id| {
 3441                if selection.start.buffer_id != Some(end_buffer_id) {
 3442                    return None;
 3443                }
 3444                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3445                let snapshot = buffer.read(cx).snapshot();
 3446                self.linked_edit_ranges
 3447                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3448                    .map(|ranges| (ranges, snapshot, buffer))
 3449            })?;
 3450        use text::ToOffset as TO;
 3451        // find offset from the start of current range to current cursor position
 3452        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3453
 3454        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3455        let start_difference = start_offset - start_byte_offset;
 3456        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3457        let end_difference = end_offset - start_byte_offset;
 3458        // Current range has associated linked ranges.
 3459        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3460        for range in linked_ranges.iter() {
 3461            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3462            let end_offset = start_offset + end_difference;
 3463            let start_offset = start_offset + start_difference;
 3464            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3465                continue;
 3466            }
 3467            if self.selections.disjoint_anchor_ranges().any(|s| {
 3468                if s.start.buffer_id != selection.start.buffer_id
 3469                    || s.end.buffer_id != selection.end.buffer_id
 3470                {
 3471                    return false;
 3472                }
 3473                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3474                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3475            }) {
 3476                continue;
 3477            }
 3478            let start = buffer_snapshot.anchor_after(start_offset);
 3479            let end = buffer_snapshot.anchor_after(end_offset);
 3480            linked_edits
 3481                .entry(buffer.clone())
 3482                .or_default()
 3483                .push(start..end);
 3484        }
 3485        Some(linked_edits)
 3486    }
 3487
 3488    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3489        let text: Arc<str> = text.into();
 3490
 3491        if self.read_only(cx) {
 3492            return;
 3493        }
 3494
 3495        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3496
 3497        let selections = self.selections.all_adjusted(cx);
 3498        let mut bracket_inserted = false;
 3499        let mut edits = Vec::new();
 3500        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3501        let mut new_selections = Vec::with_capacity(selections.len());
 3502        let mut new_autoclose_regions = Vec::new();
 3503        let snapshot = self.buffer.read(cx).read(cx);
 3504        let mut clear_linked_edit_ranges = false;
 3505
 3506        for (selection, autoclose_region) in
 3507            self.selections_with_autoclose_regions(selections, &snapshot)
 3508        {
 3509            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3510                // Determine if the inserted text matches the opening or closing
 3511                // bracket of any of this language's bracket pairs.
 3512                let mut bracket_pair = None;
 3513                let mut is_bracket_pair_start = false;
 3514                let mut is_bracket_pair_end = false;
 3515                if !text.is_empty() {
 3516                    let mut bracket_pair_matching_end = None;
 3517                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3518                    //  and they are removing the character that triggered IME popup.
 3519                    for (pair, enabled) in scope.brackets() {
 3520                        if !pair.close && !pair.surround {
 3521                            continue;
 3522                        }
 3523
 3524                        if enabled && pair.start.ends_with(text.as_ref()) {
 3525                            let prefix_len = pair.start.len() - text.len();
 3526                            let preceding_text_matches_prefix = prefix_len == 0
 3527                                || (selection.start.column >= (prefix_len as u32)
 3528                                    && snapshot.contains_str_at(
 3529                                        Point::new(
 3530                                            selection.start.row,
 3531                                            selection.start.column - (prefix_len as u32),
 3532                                        ),
 3533                                        &pair.start[..prefix_len],
 3534                                    ));
 3535                            if preceding_text_matches_prefix {
 3536                                bracket_pair = Some(pair.clone());
 3537                                is_bracket_pair_start = true;
 3538                                break;
 3539                            }
 3540                        }
 3541                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3542                        {
 3543                            // take first bracket pair matching end, but don't break in case a later bracket
 3544                            // pair matches start
 3545                            bracket_pair_matching_end = Some(pair.clone());
 3546                        }
 3547                    }
 3548                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3549                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3550                        is_bracket_pair_end = true;
 3551                    }
 3552                }
 3553
 3554                if let Some(bracket_pair) = bracket_pair {
 3555                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3556                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3557                    let auto_surround =
 3558                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3559                    if selection.is_empty() {
 3560                        if is_bracket_pair_start {
 3561                            // If the inserted text is a suffix of an opening bracket and the
 3562                            // selection is preceded by the rest of the opening bracket, then
 3563                            // insert the closing bracket.
 3564                            let following_text_allows_autoclose = snapshot
 3565                                .chars_at(selection.start)
 3566                                .next()
 3567                                .map_or(true, |c| scope.should_autoclose_before(c));
 3568
 3569                            let preceding_text_allows_autoclose = selection.start.column == 0
 3570                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3571                                    true,
 3572                                    |c| {
 3573                                        bracket_pair.start != bracket_pair.end
 3574                                            || !snapshot
 3575                                                .char_classifier_at(selection.start)
 3576                                                .is_word(c)
 3577                                    },
 3578                                );
 3579
 3580                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3581                                && bracket_pair.start.len() == 1
 3582                            {
 3583                                let target = bracket_pair.start.chars().next().unwrap();
 3584                                let current_line_count = snapshot
 3585                                    .reversed_chars_at(selection.start)
 3586                                    .take_while(|&c| c != '\n')
 3587                                    .filter(|&c| c == target)
 3588                                    .count();
 3589                                current_line_count % 2 == 1
 3590                            } else {
 3591                                false
 3592                            };
 3593
 3594                            if autoclose
 3595                                && bracket_pair.close
 3596                                && following_text_allows_autoclose
 3597                                && preceding_text_allows_autoclose
 3598                                && !is_closing_quote
 3599                            {
 3600                                let anchor = snapshot.anchor_before(selection.end);
 3601                                new_selections.push((selection.map(|_| anchor), text.len()));
 3602                                new_autoclose_regions.push((
 3603                                    anchor,
 3604                                    text.len(),
 3605                                    selection.id,
 3606                                    bracket_pair.clone(),
 3607                                ));
 3608                                edits.push((
 3609                                    selection.range(),
 3610                                    format!("{}{}", text, bracket_pair.end).into(),
 3611                                ));
 3612                                bracket_inserted = true;
 3613                                continue;
 3614                            }
 3615                        }
 3616
 3617                        if let Some(region) = autoclose_region {
 3618                            // If the selection is followed by an auto-inserted closing bracket,
 3619                            // then don't insert that closing bracket again; just move the selection
 3620                            // past the closing bracket.
 3621                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3622                                && text.as_ref() == region.pair.end.as_str();
 3623                            if should_skip {
 3624                                let anchor = snapshot.anchor_after(selection.end);
 3625                                new_selections
 3626                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3627                                continue;
 3628                            }
 3629                        }
 3630
 3631                        let always_treat_brackets_as_autoclosed = snapshot
 3632                            .language_settings_at(selection.start, cx)
 3633                            .always_treat_brackets_as_autoclosed;
 3634                        if always_treat_brackets_as_autoclosed
 3635                            && is_bracket_pair_end
 3636                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3637                        {
 3638                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3639                            // and the inserted text is a closing bracket and the selection is followed
 3640                            // by the closing bracket then move the selection past the closing bracket.
 3641                            let anchor = snapshot.anchor_after(selection.end);
 3642                            new_selections.push((selection.map(|_| anchor), text.len()));
 3643                            continue;
 3644                        }
 3645                    }
 3646                    // If an opening bracket is 1 character long and is typed while
 3647                    // text is selected, then surround that text with the bracket pair.
 3648                    else if auto_surround
 3649                        && bracket_pair.surround
 3650                        && is_bracket_pair_start
 3651                        && bracket_pair.start.chars().count() == 1
 3652                    {
 3653                        edits.push((selection.start..selection.start, text.clone()));
 3654                        edits.push((
 3655                            selection.end..selection.end,
 3656                            bracket_pair.end.as_str().into(),
 3657                        ));
 3658                        bracket_inserted = true;
 3659                        new_selections.push((
 3660                            Selection {
 3661                                id: selection.id,
 3662                                start: snapshot.anchor_after(selection.start),
 3663                                end: snapshot.anchor_before(selection.end),
 3664                                reversed: selection.reversed,
 3665                                goal: selection.goal,
 3666                            },
 3667                            0,
 3668                        ));
 3669                        continue;
 3670                    }
 3671                }
 3672            }
 3673
 3674            if self.auto_replace_emoji_shortcode
 3675                && selection.is_empty()
 3676                && text.as_ref().ends_with(':')
 3677            {
 3678                if let Some(possible_emoji_short_code) =
 3679                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3680                {
 3681                    if !possible_emoji_short_code.is_empty() {
 3682                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3683                            let emoji_shortcode_start = Point::new(
 3684                                selection.start.row,
 3685                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3686                            );
 3687
 3688                            // Remove shortcode from buffer
 3689                            edits.push((
 3690                                emoji_shortcode_start..selection.start,
 3691                                "".to_string().into(),
 3692                            ));
 3693                            new_selections.push((
 3694                                Selection {
 3695                                    id: selection.id,
 3696                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3697                                    end: snapshot.anchor_before(selection.start),
 3698                                    reversed: selection.reversed,
 3699                                    goal: selection.goal,
 3700                                },
 3701                                0,
 3702                            ));
 3703
 3704                            // Insert emoji
 3705                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3706                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3707                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3708
 3709                            continue;
 3710                        }
 3711                    }
 3712                }
 3713            }
 3714
 3715            // If not handling any auto-close operation, then just replace the selected
 3716            // text with the given input and move the selection to the end of the
 3717            // newly inserted text.
 3718            let anchor = snapshot.anchor_after(selection.end);
 3719            if !self.linked_edit_ranges.is_empty() {
 3720                let start_anchor = snapshot.anchor_before(selection.start);
 3721
 3722                let is_word_char = text.chars().next().map_or(true, |char| {
 3723                    let classifier = snapshot
 3724                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3725                        .ignore_punctuation(true);
 3726                    classifier.is_word(char)
 3727                });
 3728
 3729                if is_word_char {
 3730                    if let Some(ranges) = self
 3731                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3732                    {
 3733                        for (buffer, edits) in ranges {
 3734                            linked_edits
 3735                                .entry(buffer.clone())
 3736                                .or_default()
 3737                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3738                        }
 3739                    }
 3740                } else {
 3741                    clear_linked_edit_ranges = true;
 3742                }
 3743            }
 3744
 3745            new_selections.push((selection.map(|_| anchor), 0));
 3746            edits.push((selection.start..selection.end, text.clone()));
 3747        }
 3748
 3749        drop(snapshot);
 3750
 3751        self.transact(window, cx, |this, window, cx| {
 3752            if clear_linked_edit_ranges {
 3753                this.linked_edit_ranges.clear();
 3754            }
 3755            let initial_buffer_versions =
 3756                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3757
 3758            this.buffer.update(cx, |buffer, cx| {
 3759                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3760            });
 3761            for (buffer, edits) in linked_edits {
 3762                buffer.update(cx, |buffer, cx| {
 3763                    let snapshot = buffer.snapshot();
 3764                    let edits = edits
 3765                        .into_iter()
 3766                        .map(|(range, text)| {
 3767                            use text::ToPoint as TP;
 3768                            let end_point = TP::to_point(&range.end, &snapshot);
 3769                            let start_point = TP::to_point(&range.start, &snapshot);
 3770                            (start_point..end_point, text)
 3771                        })
 3772                        .sorted_by_key(|(range, _)| range.start);
 3773                    buffer.edit(edits, None, cx);
 3774                })
 3775            }
 3776            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3777            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3778            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3779            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3780                .zip(new_selection_deltas)
 3781                .map(|(selection, delta)| Selection {
 3782                    id: selection.id,
 3783                    start: selection.start + delta,
 3784                    end: selection.end + delta,
 3785                    reversed: selection.reversed,
 3786                    goal: SelectionGoal::None,
 3787                })
 3788                .collect::<Vec<_>>();
 3789
 3790            let mut i = 0;
 3791            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3792                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3793                let start = map.buffer_snapshot.anchor_before(position);
 3794                let end = map.buffer_snapshot.anchor_after(position);
 3795                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3796                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3797                        Ordering::Less => i += 1,
 3798                        Ordering::Greater => break,
 3799                        Ordering::Equal => {
 3800                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3801                                Ordering::Less => i += 1,
 3802                                Ordering::Equal => break,
 3803                                Ordering::Greater => break,
 3804                            }
 3805                        }
 3806                    }
 3807                }
 3808                this.autoclose_regions.insert(
 3809                    i,
 3810                    AutocloseRegion {
 3811                        selection_id,
 3812                        range: start..end,
 3813                        pair,
 3814                    },
 3815                );
 3816            }
 3817
 3818            let had_active_inline_completion = this.has_active_inline_completion();
 3819            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3820                s.select(new_selections)
 3821            });
 3822
 3823            if !bracket_inserted {
 3824                if let Some(on_type_format_task) =
 3825                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3826                {
 3827                    on_type_format_task.detach_and_log_err(cx);
 3828                }
 3829            }
 3830
 3831            let editor_settings = EditorSettings::get_global(cx);
 3832            if bracket_inserted
 3833                && (editor_settings.auto_signature_help
 3834                    || editor_settings.show_signature_help_after_edits)
 3835            {
 3836                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3837            }
 3838
 3839            let trigger_in_words =
 3840                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3841            if this.hard_wrap.is_some() {
 3842                let latest: Range<Point> = this.selections.newest(cx).range();
 3843                if latest.is_empty()
 3844                    && this
 3845                        .buffer()
 3846                        .read(cx)
 3847                        .snapshot(cx)
 3848                        .line_len(MultiBufferRow(latest.start.row))
 3849                        == latest.start.column
 3850                {
 3851                    this.rewrap_impl(
 3852                        RewrapOptions {
 3853                            override_language_settings: true,
 3854                            preserve_existing_whitespace: true,
 3855                        },
 3856                        cx,
 3857                    )
 3858                }
 3859            }
 3860            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3861            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3862            this.refresh_inline_completion(true, false, window, cx);
 3863            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3864        });
 3865    }
 3866
 3867    fn find_possible_emoji_shortcode_at_position(
 3868        snapshot: &MultiBufferSnapshot,
 3869        position: Point,
 3870    ) -> Option<String> {
 3871        let mut chars = Vec::new();
 3872        let mut found_colon = false;
 3873        for char in snapshot.reversed_chars_at(position).take(100) {
 3874            // Found a possible emoji shortcode in the middle of the buffer
 3875            if found_colon {
 3876                if char.is_whitespace() {
 3877                    chars.reverse();
 3878                    return Some(chars.iter().collect());
 3879                }
 3880                // If the previous character is not a whitespace, we are in the middle of a word
 3881                // and we only want to complete the shortcode if the word is made up of other emojis
 3882                let mut containing_word = String::new();
 3883                for ch in snapshot
 3884                    .reversed_chars_at(position)
 3885                    .skip(chars.len() + 1)
 3886                    .take(100)
 3887                {
 3888                    if ch.is_whitespace() {
 3889                        break;
 3890                    }
 3891                    containing_word.push(ch);
 3892                }
 3893                let containing_word = containing_word.chars().rev().collect::<String>();
 3894                if util::word_consists_of_emojis(containing_word.as_str()) {
 3895                    chars.reverse();
 3896                    return Some(chars.iter().collect());
 3897                }
 3898            }
 3899
 3900            if char.is_whitespace() || !char.is_ascii() {
 3901                return None;
 3902            }
 3903            if char == ':' {
 3904                found_colon = true;
 3905            } else {
 3906                chars.push(char);
 3907            }
 3908        }
 3909        // Found a possible emoji shortcode at the beginning of the buffer
 3910        chars.reverse();
 3911        Some(chars.iter().collect())
 3912    }
 3913
 3914    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3915        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3916        self.transact(window, cx, |this, window, cx| {
 3917            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3918                let selections = this.selections.all::<usize>(cx);
 3919                let multi_buffer = this.buffer.read(cx);
 3920                let buffer = multi_buffer.snapshot(cx);
 3921                selections
 3922                    .iter()
 3923                    .map(|selection| {
 3924                        let start_point = selection.start.to_point(&buffer);
 3925                        let mut existing_indent =
 3926                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3927                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3928                        let start = selection.start;
 3929                        let end = selection.end;
 3930                        let selection_is_empty = start == end;
 3931                        let language_scope = buffer.language_scope_at(start);
 3932                        let (
 3933                            comment_delimiter,
 3934                            doc_delimiter,
 3935                            insert_extra_newline,
 3936                            indent_on_newline,
 3937                            indent_on_extra_newline,
 3938                        ) = if let Some(language) = &language_scope {
 3939                            let mut insert_extra_newline =
 3940                                insert_extra_newline_brackets(&buffer, start..end, language)
 3941                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3942
 3943                            // Comment extension on newline is allowed only for cursor selections
 3944                            let comment_delimiter = maybe!({
 3945                                if !selection_is_empty {
 3946                                    return None;
 3947                                }
 3948
 3949                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3950                                    return None;
 3951                                }
 3952
 3953                                let delimiters = language.line_comment_prefixes();
 3954                                let max_len_of_delimiter =
 3955                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3956                                let (snapshot, range) =
 3957                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3958
 3959                                let num_of_whitespaces = snapshot
 3960                                    .chars_for_range(range.clone())
 3961                                    .take_while(|c| c.is_whitespace())
 3962                                    .count();
 3963                                let comment_candidate = snapshot
 3964                                    .chars_for_range(range)
 3965                                    .skip(num_of_whitespaces)
 3966                                    .take(max_len_of_delimiter)
 3967                                    .collect::<String>();
 3968                                let (delimiter, trimmed_len) = delimiters
 3969                                    .iter()
 3970                                    .filter_map(|delimiter| {
 3971                                        let prefix = delimiter.trim_end();
 3972                                        if comment_candidate.starts_with(prefix) {
 3973                                            Some((delimiter, prefix.len()))
 3974                                        } else {
 3975                                            None
 3976                                        }
 3977                                    })
 3978                                    .max_by_key(|(_, len)| *len)?;
 3979
 3980                                let cursor_is_placed_after_comment_marker =
 3981                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 3982                                if cursor_is_placed_after_comment_marker {
 3983                                    Some(delimiter.clone())
 3984                                } else {
 3985                                    None
 3986                                }
 3987                            });
 3988
 3989                            let mut indent_on_newline = IndentSize::spaces(0);
 3990                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 3991
 3992                            let doc_delimiter = maybe!({
 3993                                if !selection_is_empty {
 3994                                    return None;
 3995                                }
 3996
 3997                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3998                                    return None;
 3999                                }
 4000
 4001                                let DocumentationConfig {
 4002                                    start: start_tag,
 4003                                    end: end_tag,
 4004                                    prefix: delimiter,
 4005                                    tab_size: len,
 4006                                } = language.documentation()?;
 4007
 4008                                let (snapshot, range) =
 4009                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4010
 4011                                let num_of_whitespaces = snapshot
 4012                                    .chars_for_range(range.clone())
 4013                                    .take_while(|c| c.is_whitespace())
 4014                                    .count();
 4015
 4016                                let cursor_is_after_start_tag = {
 4017                                    let start_tag_len = start_tag.len();
 4018                                    let start_tag_line = snapshot
 4019                                        .chars_for_range(range.clone())
 4020                                        .skip(num_of_whitespaces)
 4021                                        .take(start_tag_len)
 4022                                        .collect::<String>();
 4023                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4024                                        num_of_whitespaces + start_tag_len
 4025                                            <= start_point.column as usize
 4026                                    } else {
 4027                                        false
 4028                                    }
 4029                                };
 4030
 4031                                let cursor_is_after_delimiter = {
 4032                                    let delimiter_trim = delimiter.trim_end();
 4033                                    let delimiter_line = snapshot
 4034                                        .chars_for_range(range.clone())
 4035                                        .skip(num_of_whitespaces)
 4036                                        .take(delimiter_trim.len())
 4037                                        .collect::<String>();
 4038                                    if delimiter_line.starts_with(delimiter_trim) {
 4039                                        num_of_whitespaces + delimiter_trim.len()
 4040                                            <= start_point.column as usize
 4041                                    } else {
 4042                                        false
 4043                                    }
 4044                                };
 4045
 4046                                let cursor_is_before_end_tag_if_exists = {
 4047                                    let num_of_whitespaces_rev = snapshot
 4048                                        .reversed_chars_for_range(range.clone())
 4049                                        .take_while(|c| c.is_whitespace())
 4050                                        .count();
 4051                                    let mut line_iter = snapshot
 4052                                        .reversed_chars_for_range(range)
 4053                                        .skip(num_of_whitespaces_rev);
 4054                                    let end_tag_exists = end_tag
 4055                                        .chars()
 4056                                        .rev()
 4057                                        .all(|char| line_iter.next() == Some(char));
 4058                                    if end_tag_exists {
 4059                                        let max_point = snapshot.line_len(start_point.row) as usize;
 4060                                        let ordering = (num_of_whitespaces_rev
 4061                                            + end_tag.len()
 4062                                            + start_point.column as usize)
 4063                                            .cmp(&max_point);
 4064                                        let cursor_is_before_end_tag =
 4065                                            ordering != Ordering::Greater;
 4066                                        if cursor_is_after_start_tag {
 4067                                            if cursor_is_before_end_tag {
 4068                                                insert_extra_newline = true;
 4069                                            }
 4070                                            let cursor_is_at_start_of_end_tag =
 4071                                                ordering == Ordering::Equal;
 4072                                            if cursor_is_at_start_of_end_tag {
 4073                                                indent_on_extra_newline.len = (*len).into();
 4074                                            }
 4075                                        }
 4076                                        cursor_is_before_end_tag
 4077                                    } else {
 4078                                        true
 4079                                    }
 4080                                };
 4081
 4082                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4083                                    && cursor_is_before_end_tag_if_exists
 4084                                {
 4085                                    if cursor_is_after_start_tag {
 4086                                        indent_on_newline.len = (*len).into();
 4087                                    }
 4088                                    Some(delimiter.clone())
 4089                                } else {
 4090                                    None
 4091                                }
 4092                            });
 4093
 4094                            (
 4095                                comment_delimiter,
 4096                                doc_delimiter,
 4097                                insert_extra_newline,
 4098                                indent_on_newline,
 4099                                indent_on_extra_newline,
 4100                            )
 4101                        } else {
 4102                            (
 4103                                None,
 4104                                None,
 4105                                false,
 4106                                IndentSize::default(),
 4107                                IndentSize::default(),
 4108                            )
 4109                        };
 4110
 4111                        let prevent_auto_indent = doc_delimiter.is_some();
 4112                        let delimiter = comment_delimiter.or(doc_delimiter);
 4113
 4114                        let capacity_for_delimiter =
 4115                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4116                        let mut new_text = String::with_capacity(
 4117                            1 + capacity_for_delimiter
 4118                                + existing_indent.len as usize
 4119                                + indent_on_newline.len as usize
 4120                                + indent_on_extra_newline.len as usize,
 4121                        );
 4122                        new_text.push('\n');
 4123                        new_text.extend(existing_indent.chars());
 4124                        new_text.extend(indent_on_newline.chars());
 4125
 4126                        if let Some(delimiter) = &delimiter {
 4127                            new_text.push_str(delimiter);
 4128                        }
 4129
 4130                        if insert_extra_newline {
 4131                            new_text.push('\n');
 4132                            new_text.extend(existing_indent.chars());
 4133                            new_text.extend(indent_on_extra_newline.chars());
 4134                        }
 4135
 4136                        let anchor = buffer.anchor_after(end);
 4137                        let new_selection = selection.map(|_| anchor);
 4138                        (
 4139                            ((start..end, new_text), prevent_auto_indent),
 4140                            (insert_extra_newline, new_selection),
 4141                        )
 4142                    })
 4143                    .unzip()
 4144            };
 4145
 4146            let mut auto_indent_edits = Vec::new();
 4147            let mut edits = Vec::new();
 4148            for (edit, prevent_auto_indent) in edits_with_flags {
 4149                if prevent_auto_indent {
 4150                    edits.push(edit);
 4151                } else {
 4152                    auto_indent_edits.push(edit);
 4153                }
 4154            }
 4155            if !edits.is_empty() {
 4156                this.edit(edits, cx);
 4157            }
 4158            if !auto_indent_edits.is_empty() {
 4159                this.edit_with_autoindent(auto_indent_edits, cx);
 4160            }
 4161
 4162            let buffer = this.buffer.read(cx).snapshot(cx);
 4163            let new_selections = selection_info
 4164                .into_iter()
 4165                .map(|(extra_newline_inserted, new_selection)| {
 4166                    let mut cursor = new_selection.end.to_point(&buffer);
 4167                    if extra_newline_inserted {
 4168                        cursor.row -= 1;
 4169                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4170                    }
 4171                    new_selection.map(|_| cursor)
 4172                })
 4173                .collect();
 4174
 4175            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4176                s.select(new_selections)
 4177            });
 4178            this.refresh_inline_completion(true, false, window, cx);
 4179        });
 4180    }
 4181
 4182    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4183        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4184
 4185        let buffer = self.buffer.read(cx);
 4186        let snapshot = buffer.snapshot(cx);
 4187
 4188        let mut edits = Vec::new();
 4189        let mut rows = Vec::new();
 4190
 4191        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4192            let cursor = selection.head();
 4193            let row = cursor.row;
 4194
 4195            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4196
 4197            let newline = "\n".to_string();
 4198            edits.push((start_of_line..start_of_line, newline));
 4199
 4200            rows.push(row + rows_inserted as u32);
 4201        }
 4202
 4203        self.transact(window, cx, |editor, window, cx| {
 4204            editor.edit(edits, cx);
 4205
 4206            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4207                let mut index = 0;
 4208                s.move_cursors_with(|map, _, _| {
 4209                    let row = rows[index];
 4210                    index += 1;
 4211
 4212                    let point = Point::new(row, 0);
 4213                    let boundary = map.next_line_boundary(point).1;
 4214                    let clipped = map.clip_point(boundary, Bias::Left);
 4215
 4216                    (clipped, SelectionGoal::None)
 4217                });
 4218            });
 4219
 4220            let mut indent_edits = Vec::new();
 4221            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4222            for row in rows {
 4223                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4224                for (row, indent) in indents {
 4225                    if indent.len == 0 {
 4226                        continue;
 4227                    }
 4228
 4229                    let text = match indent.kind {
 4230                        IndentKind::Space => " ".repeat(indent.len as usize),
 4231                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4232                    };
 4233                    let point = Point::new(row.0, 0);
 4234                    indent_edits.push((point..point, text));
 4235                }
 4236            }
 4237            editor.edit(indent_edits, cx);
 4238        });
 4239    }
 4240
 4241    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4242        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4243
 4244        let buffer = self.buffer.read(cx);
 4245        let snapshot = buffer.snapshot(cx);
 4246
 4247        let mut edits = Vec::new();
 4248        let mut rows = Vec::new();
 4249        let mut rows_inserted = 0;
 4250
 4251        for selection in self.selections.all_adjusted(cx) {
 4252            let cursor = selection.head();
 4253            let row = cursor.row;
 4254
 4255            let point = Point::new(row + 1, 0);
 4256            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4257
 4258            let newline = "\n".to_string();
 4259            edits.push((start_of_line..start_of_line, newline));
 4260
 4261            rows_inserted += 1;
 4262            rows.push(row + rows_inserted);
 4263        }
 4264
 4265        self.transact(window, cx, |editor, window, cx| {
 4266            editor.edit(edits, cx);
 4267
 4268            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4269                let mut index = 0;
 4270                s.move_cursors_with(|map, _, _| {
 4271                    let row = rows[index];
 4272                    index += 1;
 4273
 4274                    let point = Point::new(row, 0);
 4275                    let boundary = map.next_line_boundary(point).1;
 4276                    let clipped = map.clip_point(boundary, Bias::Left);
 4277
 4278                    (clipped, SelectionGoal::None)
 4279                });
 4280            });
 4281
 4282            let mut indent_edits = Vec::new();
 4283            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4284            for row in rows {
 4285                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4286                for (row, indent) in indents {
 4287                    if indent.len == 0 {
 4288                        continue;
 4289                    }
 4290
 4291                    let text = match indent.kind {
 4292                        IndentKind::Space => " ".repeat(indent.len as usize),
 4293                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4294                    };
 4295                    let point = Point::new(row.0, 0);
 4296                    indent_edits.push((point..point, text));
 4297                }
 4298            }
 4299            editor.edit(indent_edits, cx);
 4300        });
 4301    }
 4302
 4303    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4304        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4305            original_indent_columns: Vec::new(),
 4306        });
 4307        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4308    }
 4309
 4310    fn insert_with_autoindent_mode(
 4311        &mut self,
 4312        text: &str,
 4313        autoindent_mode: Option<AutoindentMode>,
 4314        window: &mut Window,
 4315        cx: &mut Context<Self>,
 4316    ) {
 4317        if self.read_only(cx) {
 4318            return;
 4319        }
 4320
 4321        let text: Arc<str> = text.into();
 4322        self.transact(window, cx, |this, window, cx| {
 4323            let old_selections = this.selections.all_adjusted(cx);
 4324            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4325                let anchors = {
 4326                    let snapshot = buffer.read(cx);
 4327                    old_selections
 4328                        .iter()
 4329                        .map(|s| {
 4330                            let anchor = snapshot.anchor_after(s.head());
 4331                            s.map(|_| anchor)
 4332                        })
 4333                        .collect::<Vec<_>>()
 4334                };
 4335                buffer.edit(
 4336                    old_selections
 4337                        .iter()
 4338                        .map(|s| (s.start..s.end, text.clone())),
 4339                    autoindent_mode,
 4340                    cx,
 4341                );
 4342                anchors
 4343            });
 4344
 4345            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4346                s.select_anchors(selection_anchors);
 4347            });
 4348
 4349            cx.notify();
 4350        });
 4351    }
 4352
 4353    fn trigger_completion_on_input(
 4354        &mut self,
 4355        text: &str,
 4356        trigger_in_words: bool,
 4357        window: &mut Window,
 4358        cx: &mut Context<Self>,
 4359    ) {
 4360        let ignore_completion_provider = self
 4361            .context_menu
 4362            .borrow()
 4363            .as_ref()
 4364            .map(|menu| match menu {
 4365                CodeContextMenu::Completions(completions_menu) => {
 4366                    completions_menu.ignore_completion_provider
 4367                }
 4368                CodeContextMenu::CodeActions(_) => false,
 4369            })
 4370            .unwrap_or(false);
 4371
 4372        if ignore_completion_provider {
 4373            self.show_word_completions(&ShowWordCompletions, window, cx);
 4374        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4375            self.show_completions(
 4376                &ShowCompletions {
 4377                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4378                },
 4379                window,
 4380                cx,
 4381            );
 4382        } else {
 4383            self.hide_context_menu(window, cx);
 4384        }
 4385    }
 4386
 4387    fn is_completion_trigger(
 4388        &self,
 4389        text: &str,
 4390        trigger_in_words: bool,
 4391        cx: &mut Context<Self>,
 4392    ) -> bool {
 4393        let position = self.selections.newest_anchor().head();
 4394        let multibuffer = self.buffer.read(cx);
 4395        let Some(buffer) = position
 4396            .buffer_id
 4397            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4398        else {
 4399            return false;
 4400        };
 4401
 4402        if let Some(completion_provider) = &self.completion_provider {
 4403            completion_provider.is_completion_trigger(
 4404                &buffer,
 4405                position.text_anchor,
 4406                text,
 4407                trigger_in_words,
 4408                cx,
 4409            )
 4410        } else {
 4411            false
 4412        }
 4413    }
 4414
 4415    /// If any empty selections is touching the start of its innermost containing autoclose
 4416    /// region, expand it to select the brackets.
 4417    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4418        let selections = self.selections.all::<usize>(cx);
 4419        let buffer = self.buffer.read(cx).read(cx);
 4420        let new_selections = self
 4421            .selections_with_autoclose_regions(selections, &buffer)
 4422            .map(|(mut selection, region)| {
 4423                if !selection.is_empty() {
 4424                    return selection;
 4425                }
 4426
 4427                if let Some(region) = region {
 4428                    let mut range = region.range.to_offset(&buffer);
 4429                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4430                        range.start -= region.pair.start.len();
 4431                        if buffer.contains_str_at(range.start, &region.pair.start)
 4432                            && buffer.contains_str_at(range.end, &region.pair.end)
 4433                        {
 4434                            range.end += region.pair.end.len();
 4435                            selection.start = range.start;
 4436                            selection.end = range.end;
 4437
 4438                            return selection;
 4439                        }
 4440                    }
 4441                }
 4442
 4443                let always_treat_brackets_as_autoclosed = buffer
 4444                    .language_settings_at(selection.start, cx)
 4445                    .always_treat_brackets_as_autoclosed;
 4446
 4447                if !always_treat_brackets_as_autoclosed {
 4448                    return selection;
 4449                }
 4450
 4451                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4452                    for (pair, enabled) in scope.brackets() {
 4453                        if !enabled || !pair.close {
 4454                            continue;
 4455                        }
 4456
 4457                        if buffer.contains_str_at(selection.start, &pair.end) {
 4458                            let pair_start_len = pair.start.len();
 4459                            if buffer.contains_str_at(
 4460                                selection.start.saturating_sub(pair_start_len),
 4461                                &pair.start,
 4462                            ) {
 4463                                selection.start -= pair_start_len;
 4464                                selection.end += pair.end.len();
 4465
 4466                                return selection;
 4467                            }
 4468                        }
 4469                    }
 4470                }
 4471
 4472                selection
 4473            })
 4474            .collect();
 4475
 4476        drop(buffer);
 4477        self.change_selections(None, window, cx, |selections| {
 4478            selections.select(new_selections)
 4479        });
 4480    }
 4481
 4482    /// Iterate the given selections, and for each one, find the smallest surrounding
 4483    /// autoclose region. This uses the ordering of the selections and the autoclose
 4484    /// regions to avoid repeated comparisons.
 4485    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4486        &'a self,
 4487        selections: impl IntoIterator<Item = Selection<D>>,
 4488        buffer: &'a MultiBufferSnapshot,
 4489    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4490        let mut i = 0;
 4491        let mut regions = self.autoclose_regions.as_slice();
 4492        selections.into_iter().map(move |selection| {
 4493            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4494
 4495            let mut enclosing = None;
 4496            while let Some(pair_state) = regions.get(i) {
 4497                if pair_state.range.end.to_offset(buffer) < range.start {
 4498                    regions = &regions[i + 1..];
 4499                    i = 0;
 4500                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4501                    break;
 4502                } else {
 4503                    if pair_state.selection_id == selection.id {
 4504                        enclosing = Some(pair_state);
 4505                    }
 4506                    i += 1;
 4507                }
 4508            }
 4509
 4510            (selection, enclosing)
 4511        })
 4512    }
 4513
 4514    /// Remove any autoclose regions that no longer contain their selection.
 4515    fn invalidate_autoclose_regions(
 4516        &mut self,
 4517        mut selections: &[Selection<Anchor>],
 4518        buffer: &MultiBufferSnapshot,
 4519    ) {
 4520        self.autoclose_regions.retain(|state| {
 4521            let mut i = 0;
 4522            while let Some(selection) = selections.get(i) {
 4523                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4524                    selections = &selections[1..];
 4525                    continue;
 4526                }
 4527                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4528                    break;
 4529                }
 4530                if selection.id == state.selection_id {
 4531                    return true;
 4532                } else {
 4533                    i += 1;
 4534                }
 4535            }
 4536            false
 4537        });
 4538    }
 4539
 4540    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4541        let offset = position.to_offset(buffer);
 4542        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4543        if offset > word_range.start && kind == Some(CharKind::Word) {
 4544            Some(
 4545                buffer
 4546                    .text_for_range(word_range.start..offset)
 4547                    .collect::<String>(),
 4548            )
 4549        } else {
 4550            None
 4551        }
 4552    }
 4553
 4554    pub fn toggle_inline_values(
 4555        &mut self,
 4556        _: &ToggleInlineValues,
 4557        _: &mut Window,
 4558        cx: &mut Context<Self>,
 4559    ) {
 4560        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4561
 4562        self.refresh_inline_values(cx);
 4563    }
 4564
 4565    pub fn toggle_inlay_hints(
 4566        &mut self,
 4567        _: &ToggleInlayHints,
 4568        _: &mut Window,
 4569        cx: &mut Context<Self>,
 4570    ) {
 4571        self.refresh_inlay_hints(
 4572            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4573            cx,
 4574        );
 4575    }
 4576
 4577    pub fn inlay_hints_enabled(&self) -> bool {
 4578        self.inlay_hint_cache.enabled
 4579    }
 4580
 4581    pub fn inline_values_enabled(&self) -> bool {
 4582        self.inline_value_cache.enabled
 4583    }
 4584
 4585    #[cfg(any(test, feature = "test-support"))]
 4586    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4587        self.display_map
 4588            .read(cx)
 4589            .current_inlays()
 4590            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4591            .cloned()
 4592            .collect()
 4593    }
 4594
 4595    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4596        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4597            return;
 4598        }
 4599
 4600        let reason_description = reason.description();
 4601        let ignore_debounce = matches!(
 4602            reason,
 4603            InlayHintRefreshReason::SettingsChange(_)
 4604                | InlayHintRefreshReason::Toggle(_)
 4605                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4606                | InlayHintRefreshReason::ModifiersChanged(_)
 4607        );
 4608        let (invalidate_cache, required_languages) = match reason {
 4609            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4610                match self.inlay_hint_cache.modifiers_override(enabled) {
 4611                    Some(enabled) => {
 4612                        if enabled {
 4613                            (InvalidationStrategy::RefreshRequested, None)
 4614                        } else {
 4615                            self.splice_inlays(
 4616                                &self
 4617                                    .visible_inlay_hints(cx)
 4618                                    .iter()
 4619                                    .map(|inlay| inlay.id)
 4620                                    .collect::<Vec<InlayId>>(),
 4621                                Vec::new(),
 4622                                cx,
 4623                            );
 4624                            return;
 4625                        }
 4626                    }
 4627                    None => return,
 4628                }
 4629            }
 4630            InlayHintRefreshReason::Toggle(enabled) => {
 4631                if self.inlay_hint_cache.toggle(enabled) {
 4632                    if enabled {
 4633                        (InvalidationStrategy::RefreshRequested, None)
 4634                    } else {
 4635                        self.splice_inlays(
 4636                            &self
 4637                                .visible_inlay_hints(cx)
 4638                                .iter()
 4639                                .map(|inlay| inlay.id)
 4640                                .collect::<Vec<InlayId>>(),
 4641                            Vec::new(),
 4642                            cx,
 4643                        );
 4644                        return;
 4645                    }
 4646                } else {
 4647                    return;
 4648                }
 4649            }
 4650            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4651                match self.inlay_hint_cache.update_settings(
 4652                    &self.buffer,
 4653                    new_settings,
 4654                    self.visible_inlay_hints(cx),
 4655                    cx,
 4656                ) {
 4657                    ControlFlow::Break(Some(InlaySplice {
 4658                        to_remove,
 4659                        to_insert,
 4660                    })) => {
 4661                        self.splice_inlays(&to_remove, to_insert, cx);
 4662                        return;
 4663                    }
 4664                    ControlFlow::Break(None) => return,
 4665                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4666                }
 4667            }
 4668            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4669                if let Some(InlaySplice {
 4670                    to_remove,
 4671                    to_insert,
 4672                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4673                {
 4674                    self.splice_inlays(&to_remove, to_insert, cx);
 4675                }
 4676                self.display_map.update(cx, |display_map, _| {
 4677                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4678                });
 4679                return;
 4680            }
 4681            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4682            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4683                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4684            }
 4685            InlayHintRefreshReason::RefreshRequested => {
 4686                (InvalidationStrategy::RefreshRequested, None)
 4687            }
 4688        };
 4689
 4690        if let Some(InlaySplice {
 4691            to_remove,
 4692            to_insert,
 4693        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4694            reason_description,
 4695            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4696            invalidate_cache,
 4697            ignore_debounce,
 4698            cx,
 4699        ) {
 4700            self.splice_inlays(&to_remove, to_insert, cx);
 4701        }
 4702    }
 4703
 4704    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4705        self.display_map
 4706            .read(cx)
 4707            .current_inlays()
 4708            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4709            .cloned()
 4710            .collect()
 4711    }
 4712
 4713    pub fn excerpts_for_inlay_hints_query(
 4714        &self,
 4715        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4716        cx: &mut Context<Editor>,
 4717    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4718        let Some(project) = self.project.as_ref() else {
 4719            return HashMap::default();
 4720        };
 4721        let project = project.read(cx);
 4722        let multi_buffer = self.buffer().read(cx);
 4723        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4724        let multi_buffer_visible_start = self
 4725            .scroll_manager
 4726            .anchor()
 4727            .anchor
 4728            .to_point(&multi_buffer_snapshot);
 4729        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4730            multi_buffer_visible_start
 4731                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4732            Bias::Left,
 4733        );
 4734        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4735        multi_buffer_snapshot
 4736            .range_to_buffer_ranges(multi_buffer_visible_range)
 4737            .into_iter()
 4738            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4739            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4740                let buffer_file = project::File::from_dyn(buffer.file())?;
 4741                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4742                let worktree_entry = buffer_worktree
 4743                    .read(cx)
 4744                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4745                if worktree_entry.is_ignored {
 4746                    return None;
 4747                }
 4748
 4749                let language = buffer.language()?;
 4750                if let Some(restrict_to_languages) = restrict_to_languages {
 4751                    if !restrict_to_languages.contains(language) {
 4752                        return None;
 4753                    }
 4754                }
 4755                Some((
 4756                    excerpt_id,
 4757                    (
 4758                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4759                        buffer.version().clone(),
 4760                        excerpt_visible_range,
 4761                    ),
 4762                ))
 4763            })
 4764            .collect()
 4765    }
 4766
 4767    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4768        TextLayoutDetails {
 4769            text_system: window.text_system().clone(),
 4770            editor_style: self.style.clone().unwrap(),
 4771            rem_size: window.rem_size(),
 4772            scroll_anchor: self.scroll_manager.anchor(),
 4773            visible_rows: self.visible_line_count(),
 4774            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4775        }
 4776    }
 4777
 4778    pub fn splice_inlays(
 4779        &self,
 4780        to_remove: &[InlayId],
 4781        to_insert: Vec<Inlay>,
 4782        cx: &mut Context<Self>,
 4783    ) {
 4784        self.display_map.update(cx, |display_map, cx| {
 4785            display_map.splice_inlays(to_remove, to_insert, cx)
 4786        });
 4787        cx.notify();
 4788    }
 4789
 4790    fn trigger_on_type_formatting(
 4791        &self,
 4792        input: String,
 4793        window: &mut Window,
 4794        cx: &mut Context<Self>,
 4795    ) -> Option<Task<Result<()>>> {
 4796        if input.len() != 1 {
 4797            return None;
 4798        }
 4799
 4800        let project = self.project.as_ref()?;
 4801        let position = self.selections.newest_anchor().head();
 4802        let (buffer, buffer_position) = self
 4803            .buffer
 4804            .read(cx)
 4805            .text_anchor_for_position(position, cx)?;
 4806
 4807        let settings = language_settings::language_settings(
 4808            buffer
 4809                .read(cx)
 4810                .language_at(buffer_position)
 4811                .map(|l| l.name()),
 4812            buffer.read(cx).file(),
 4813            cx,
 4814        );
 4815        if !settings.use_on_type_format {
 4816            return None;
 4817        }
 4818
 4819        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4820        // hence we do LSP request & edit on host side only — add formats to host's history.
 4821        let push_to_lsp_host_history = true;
 4822        // If this is not the host, append its history with new edits.
 4823        let push_to_client_history = project.read(cx).is_via_collab();
 4824
 4825        let on_type_formatting = project.update(cx, |project, cx| {
 4826            project.on_type_format(
 4827                buffer.clone(),
 4828                buffer_position,
 4829                input,
 4830                push_to_lsp_host_history,
 4831                cx,
 4832            )
 4833        });
 4834        Some(cx.spawn_in(window, async move |editor, cx| {
 4835            if let Some(transaction) = on_type_formatting.await? {
 4836                if push_to_client_history {
 4837                    buffer
 4838                        .update(cx, |buffer, _| {
 4839                            buffer.push_transaction(transaction, Instant::now());
 4840                            buffer.finalize_last_transaction();
 4841                        })
 4842                        .ok();
 4843                }
 4844                editor.update(cx, |editor, cx| {
 4845                    editor.refresh_document_highlights(cx);
 4846                })?;
 4847            }
 4848            Ok(())
 4849        }))
 4850    }
 4851
 4852    pub fn show_word_completions(
 4853        &mut self,
 4854        _: &ShowWordCompletions,
 4855        window: &mut Window,
 4856        cx: &mut Context<Self>,
 4857    ) {
 4858        self.open_completions_menu(true, None, window, cx);
 4859    }
 4860
 4861    pub fn show_completions(
 4862        &mut self,
 4863        options: &ShowCompletions,
 4864        window: &mut Window,
 4865        cx: &mut Context<Self>,
 4866    ) {
 4867        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4868    }
 4869
 4870    fn open_completions_menu(
 4871        &mut self,
 4872        ignore_completion_provider: bool,
 4873        trigger: Option<&str>,
 4874        window: &mut Window,
 4875        cx: &mut Context<Self>,
 4876    ) {
 4877        if self.pending_rename.is_some() {
 4878            return;
 4879        }
 4880        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4881            return;
 4882        }
 4883
 4884        let position = self.selections.newest_anchor().head();
 4885        if position.diff_base_anchor.is_some() {
 4886            return;
 4887        }
 4888        let (buffer, buffer_position) =
 4889            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4890                output
 4891            } else {
 4892                return;
 4893            };
 4894        let buffer_snapshot = buffer.read(cx).snapshot();
 4895        let show_completion_documentation = buffer_snapshot
 4896            .settings_at(buffer_position, cx)
 4897            .show_completion_documentation;
 4898
 4899        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4900
 4901        let trigger_kind = match trigger {
 4902            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4903                CompletionTriggerKind::TRIGGER_CHARACTER
 4904            }
 4905            _ => CompletionTriggerKind::INVOKED,
 4906        };
 4907        let completion_context = CompletionContext {
 4908            trigger_character: trigger.and_then(|trigger| {
 4909                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4910                    Some(String::from(trigger))
 4911                } else {
 4912                    None
 4913                }
 4914            }),
 4915            trigger_kind,
 4916        };
 4917
 4918        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4919        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4920            let word_to_exclude = buffer_snapshot
 4921                .text_for_range(old_range.clone())
 4922                .collect::<String>();
 4923            (
 4924                buffer_snapshot.anchor_before(old_range.start)
 4925                    ..buffer_snapshot.anchor_after(old_range.end),
 4926                Some(word_to_exclude),
 4927            )
 4928        } else {
 4929            (buffer_position..buffer_position, None)
 4930        };
 4931
 4932        let completion_settings = language_settings(
 4933            buffer_snapshot
 4934                .language_at(buffer_position)
 4935                .map(|language| language.name()),
 4936            buffer_snapshot.file(),
 4937            cx,
 4938        )
 4939        .completions;
 4940
 4941        // The document can be large, so stay in reasonable bounds when searching for words,
 4942        // otherwise completion pop-up might be slow to appear.
 4943        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4944        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4945        let min_word_search = buffer_snapshot.clip_point(
 4946            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4947            Bias::Left,
 4948        );
 4949        let max_word_search = buffer_snapshot.clip_point(
 4950            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4951            Bias::Right,
 4952        );
 4953        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4954            ..buffer_snapshot.point_to_offset(max_word_search);
 4955
 4956        let provider = self
 4957            .completion_provider
 4958            .as_ref()
 4959            .filter(|_| !ignore_completion_provider);
 4960        let skip_digits = query
 4961            .as_ref()
 4962            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4963
 4964        let (mut words, provided_completions) = match provider {
 4965            Some(provider) => {
 4966                let completions = provider.completions(
 4967                    position.excerpt_id,
 4968                    &buffer,
 4969                    buffer_position,
 4970                    completion_context,
 4971                    window,
 4972                    cx,
 4973                );
 4974
 4975                let words = match completion_settings.words {
 4976                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4977                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4978                        .background_spawn(async move {
 4979                            buffer_snapshot.words_in_range(WordsQuery {
 4980                                fuzzy_contents: None,
 4981                                range: word_search_range,
 4982                                skip_digits,
 4983                            })
 4984                        }),
 4985                };
 4986
 4987                (words, completions)
 4988            }
 4989            None => (
 4990                cx.background_spawn(async move {
 4991                    buffer_snapshot.words_in_range(WordsQuery {
 4992                        fuzzy_contents: None,
 4993                        range: word_search_range,
 4994                        skip_digits,
 4995                    })
 4996                }),
 4997                Task::ready(Ok(None)),
 4998            ),
 4999        };
 5000
 5001        let sort_completions = provider
 5002            .as_ref()
 5003            .map_or(false, |provider| provider.sort_completions());
 5004
 5005        let filter_completions = provider
 5006            .as_ref()
 5007            .map_or(true, |provider| provider.filter_completions());
 5008
 5009        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5010
 5011        let id = post_inc(&mut self.next_completion_id);
 5012        let task = cx.spawn_in(window, async move |editor, cx| {
 5013            async move {
 5014                editor.update(cx, |this, _| {
 5015                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5016                })?;
 5017
 5018                let mut completions = Vec::new();
 5019                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5020                    completions.extend(provided_completions);
 5021                    if completion_settings.words == WordsCompletionMode::Fallback {
 5022                        words = Task::ready(BTreeMap::default());
 5023                    }
 5024                }
 5025
 5026                let mut words = words.await;
 5027                if let Some(word_to_exclude) = &word_to_exclude {
 5028                    words.remove(word_to_exclude);
 5029                }
 5030                for lsp_completion in &completions {
 5031                    words.remove(&lsp_completion.new_text);
 5032                }
 5033                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5034                    replace_range: old_range.clone(),
 5035                    new_text: word.clone(),
 5036                    label: CodeLabel::plain(word, None),
 5037                    icon_path: None,
 5038                    documentation: None,
 5039                    source: CompletionSource::BufferWord {
 5040                        word_range,
 5041                        resolved: false,
 5042                    },
 5043                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5044                    confirm: None,
 5045                }));
 5046
 5047                let menu = if completions.is_empty() {
 5048                    None
 5049                } else {
 5050                    let mut menu = CompletionsMenu::new(
 5051                        id,
 5052                        sort_completions,
 5053                        show_completion_documentation,
 5054                        ignore_completion_provider,
 5055                        position,
 5056                        buffer.clone(),
 5057                        completions.into(),
 5058                        snippet_sort_order,
 5059                    );
 5060
 5061                    menu.filter(
 5062                        if filter_completions {
 5063                            query.as_deref()
 5064                        } else {
 5065                            None
 5066                        },
 5067                        cx.background_executor().clone(),
 5068                    )
 5069                    .await;
 5070
 5071                    menu.visible().then_some(menu)
 5072                };
 5073
 5074                editor.update_in(cx, |editor, window, cx| {
 5075                    match editor.context_menu.borrow().as_ref() {
 5076                        None => {}
 5077                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5078                            if prev_menu.id > id {
 5079                                return;
 5080                            }
 5081                        }
 5082                        _ => return,
 5083                    }
 5084
 5085                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5086                        let mut menu = menu.unwrap();
 5087                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5088                        crate::hover_popover::hide_hover(editor, cx);
 5089                        *editor.context_menu.borrow_mut() =
 5090                            Some(CodeContextMenu::Completions(menu));
 5091
 5092                        if editor.show_edit_predictions_in_menu() {
 5093                            editor.update_visible_inline_completion(window, cx);
 5094                        } else {
 5095                            editor.discard_inline_completion(false, cx);
 5096                        }
 5097
 5098                        cx.notify();
 5099                    } else if editor.completion_tasks.len() <= 1 {
 5100                        // If there are no more completion tasks and the last menu was
 5101                        // empty, we should hide it.
 5102                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5103                        // If it was already hidden and we don't show inline
 5104                        // completions in the menu, we should also show the
 5105                        // inline-completion when available.
 5106                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5107                            editor.update_visible_inline_completion(window, cx);
 5108                        }
 5109                    }
 5110                })?;
 5111
 5112                anyhow::Ok(())
 5113            }
 5114            .log_err()
 5115            .await
 5116        });
 5117
 5118        self.completion_tasks.push((id, task));
 5119    }
 5120
 5121    #[cfg(feature = "test-support")]
 5122    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5123        let menu = self.context_menu.borrow();
 5124        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5125            let completions = menu.completions.borrow();
 5126            Some(completions.to_vec())
 5127        } else {
 5128            None
 5129        }
 5130    }
 5131
 5132    pub fn confirm_completion(
 5133        &mut self,
 5134        action: &ConfirmCompletion,
 5135        window: &mut Window,
 5136        cx: &mut Context<Self>,
 5137    ) -> Option<Task<Result<()>>> {
 5138        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5139        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5140    }
 5141
 5142    pub fn confirm_completion_insert(
 5143        &mut self,
 5144        _: &ConfirmCompletionInsert,
 5145        window: &mut Window,
 5146        cx: &mut Context<Self>,
 5147    ) -> Option<Task<Result<()>>> {
 5148        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5149        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5150    }
 5151
 5152    pub fn confirm_completion_replace(
 5153        &mut self,
 5154        _: &ConfirmCompletionReplace,
 5155        window: &mut Window,
 5156        cx: &mut Context<Self>,
 5157    ) -> Option<Task<Result<()>>> {
 5158        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5159        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5160    }
 5161
 5162    pub fn compose_completion(
 5163        &mut self,
 5164        action: &ComposeCompletion,
 5165        window: &mut Window,
 5166        cx: &mut Context<Self>,
 5167    ) -> Option<Task<Result<()>>> {
 5168        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5169        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5170    }
 5171
 5172    fn do_completion(
 5173        &mut self,
 5174        item_ix: Option<usize>,
 5175        intent: CompletionIntent,
 5176        window: &mut Window,
 5177        cx: &mut Context<Editor>,
 5178    ) -> Option<Task<Result<()>>> {
 5179        use language::ToOffset as _;
 5180
 5181        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5182        else {
 5183            return None;
 5184        };
 5185
 5186        let candidate_id = {
 5187            let entries = completions_menu.entries.borrow();
 5188            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5189            if self.show_edit_predictions_in_menu() {
 5190                self.discard_inline_completion(true, cx);
 5191            }
 5192            mat.candidate_id
 5193        };
 5194
 5195        let buffer_handle = completions_menu.buffer;
 5196        let completion = completions_menu
 5197            .completions
 5198            .borrow()
 5199            .get(candidate_id)?
 5200            .clone();
 5201        cx.stop_propagation();
 5202
 5203        let snapshot = self.buffer.read(cx).snapshot(cx);
 5204        let newest_anchor = self.selections.newest_anchor();
 5205
 5206        let snippet;
 5207        let new_text;
 5208        if completion.is_snippet() {
 5209            let mut snippet_source = completion.new_text.clone();
 5210            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5211                if scope.prefers_label_for_snippet_in_completion() {
 5212                    if let Some(label) = completion.label() {
 5213                        if matches!(
 5214                            completion.kind(),
 5215                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5216                        ) {
 5217                            snippet_source = label;
 5218                        }
 5219                    }
 5220                }
 5221            }
 5222            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5223            new_text = snippet.as_ref().unwrap().text.clone();
 5224        } else {
 5225            snippet = None;
 5226            new_text = completion.new_text.clone();
 5227        };
 5228
 5229        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5230        let buffer = buffer_handle.read(cx);
 5231        let replace_range_multibuffer = {
 5232            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5233            let multibuffer_anchor = snapshot
 5234                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5235                .unwrap()
 5236                ..snapshot
 5237                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5238                    .unwrap();
 5239            multibuffer_anchor.start.to_offset(&snapshot)
 5240                ..multibuffer_anchor.end.to_offset(&snapshot)
 5241        };
 5242        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5243            return None;
 5244        }
 5245
 5246        let old_text = buffer
 5247            .text_for_range(replace_range.clone())
 5248            .collect::<String>();
 5249        let lookbehind = newest_anchor
 5250            .start
 5251            .text_anchor
 5252            .to_offset(buffer)
 5253            .saturating_sub(replace_range.start);
 5254        let lookahead = replace_range
 5255            .end
 5256            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5257        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5258        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5259
 5260        let selections = self.selections.all::<usize>(cx);
 5261        let mut ranges = Vec::new();
 5262        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5263
 5264        for selection in &selections {
 5265            let range = if selection.id == newest_anchor.id {
 5266                replace_range_multibuffer.clone()
 5267            } else {
 5268                let mut range = selection.range();
 5269
 5270                // if prefix is present, don't duplicate it
 5271                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5272                    range.start = range.start.saturating_sub(lookbehind);
 5273
 5274                    // if suffix is also present, mimic the newest cursor and replace it
 5275                    if selection.id != newest_anchor.id
 5276                        && snapshot.contains_str_at(range.end, suffix)
 5277                    {
 5278                        range.end += lookahead;
 5279                    }
 5280                }
 5281                range
 5282            };
 5283
 5284            ranges.push(range.clone());
 5285
 5286            if !self.linked_edit_ranges.is_empty() {
 5287                let start_anchor = snapshot.anchor_before(range.start);
 5288                let end_anchor = snapshot.anchor_after(range.end);
 5289                if let Some(ranges) = self
 5290                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5291                {
 5292                    for (buffer, edits) in ranges {
 5293                        linked_edits
 5294                            .entry(buffer.clone())
 5295                            .or_default()
 5296                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5297                    }
 5298                }
 5299            }
 5300        }
 5301
 5302        cx.emit(EditorEvent::InputHandled {
 5303            utf16_range_to_replace: None,
 5304            text: new_text.clone().into(),
 5305        });
 5306
 5307        self.transact(window, cx, |this, window, cx| {
 5308            if let Some(mut snippet) = snippet {
 5309                snippet.text = new_text.to_string();
 5310                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5311            } else {
 5312                this.buffer.update(cx, |buffer, cx| {
 5313                    let auto_indent = match completion.insert_text_mode {
 5314                        Some(InsertTextMode::AS_IS) => None,
 5315                        _ => this.autoindent_mode.clone(),
 5316                    };
 5317                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5318                    buffer.edit(edits, auto_indent, cx);
 5319                });
 5320            }
 5321            for (buffer, edits) in linked_edits {
 5322                buffer.update(cx, |buffer, cx| {
 5323                    let snapshot = buffer.snapshot();
 5324                    let edits = edits
 5325                        .into_iter()
 5326                        .map(|(range, text)| {
 5327                            use text::ToPoint as TP;
 5328                            let end_point = TP::to_point(&range.end, &snapshot);
 5329                            let start_point = TP::to_point(&range.start, &snapshot);
 5330                            (start_point..end_point, text)
 5331                        })
 5332                        .sorted_by_key(|(range, _)| range.start);
 5333                    buffer.edit(edits, None, cx);
 5334                })
 5335            }
 5336
 5337            this.refresh_inline_completion(true, false, window, cx);
 5338        });
 5339
 5340        let show_new_completions_on_confirm = completion
 5341            .confirm
 5342            .as_ref()
 5343            .map_or(false, |confirm| confirm(intent, window, cx));
 5344        if show_new_completions_on_confirm {
 5345            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5346        }
 5347
 5348        let provider = self.completion_provider.as_ref()?;
 5349        drop(completion);
 5350        let apply_edits = provider.apply_additional_edits_for_completion(
 5351            buffer_handle,
 5352            completions_menu.completions.clone(),
 5353            candidate_id,
 5354            true,
 5355            cx,
 5356        );
 5357
 5358        let editor_settings = EditorSettings::get_global(cx);
 5359        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5360            // After the code completion is finished, users often want to know what signatures are needed.
 5361            // so we should automatically call signature_help
 5362            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5363        }
 5364
 5365        Some(cx.foreground_executor().spawn(async move {
 5366            apply_edits.await?;
 5367            Ok(())
 5368        }))
 5369    }
 5370
 5371    pub fn toggle_code_actions(
 5372        &mut self,
 5373        action: &ToggleCodeActions,
 5374        window: &mut Window,
 5375        cx: &mut Context<Self>,
 5376    ) {
 5377        let quick_launch = action.quick_launch;
 5378        let mut context_menu = self.context_menu.borrow_mut();
 5379        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5380            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 5381                // Toggle if we're selecting the same one
 5382                *context_menu = None;
 5383                cx.notify();
 5384                return;
 5385            } else {
 5386                // Otherwise, clear it and start a new one
 5387                *context_menu = None;
 5388                cx.notify();
 5389            }
 5390        }
 5391        drop(context_menu);
 5392        let snapshot = self.snapshot(window, cx);
 5393        let deployed_from_indicator = action.deployed_from_indicator;
 5394        let mut task = self.code_actions_task.take();
 5395        let action = action.clone();
 5396        cx.spawn_in(window, async move |editor, cx| {
 5397            while let Some(prev_task) = task {
 5398                prev_task.await.log_err();
 5399                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5400            }
 5401
 5402            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5403                if editor.focus_handle.is_focused(window) {
 5404                    let multibuffer_point = action
 5405                        .deployed_from_indicator
 5406                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 5407                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 5408                    let (buffer, buffer_row) = snapshot
 5409                        .buffer_snapshot
 5410                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5411                        .and_then(|(buffer_snapshot, range)| {
 5412                            editor
 5413                                .buffer
 5414                                .read(cx)
 5415                                .buffer(buffer_snapshot.remote_id())
 5416                                .map(|buffer| (buffer, range.start.row))
 5417                        })?;
 5418                    let (_, code_actions) = editor
 5419                        .available_code_actions
 5420                        .clone()
 5421                        .and_then(|(location, code_actions)| {
 5422                            let snapshot = location.buffer.read(cx).snapshot();
 5423                            let point_range = location.range.to_point(&snapshot);
 5424                            let point_range = point_range.start.row..=point_range.end.row;
 5425                            if point_range.contains(&buffer_row) {
 5426                                Some((location, code_actions))
 5427                            } else {
 5428                                None
 5429                            }
 5430                        })
 5431                        .unzip();
 5432                    let buffer_id = buffer.read(cx).remote_id();
 5433                    let tasks = editor
 5434                        .tasks
 5435                        .get(&(buffer_id, buffer_row))
 5436                        .map(|t| Arc::new(t.to_owned()));
 5437                    if tasks.is_none() && code_actions.is_none() {
 5438                        return None;
 5439                    }
 5440
 5441                    editor.completion_tasks.clear();
 5442                    editor.discard_inline_completion(false, cx);
 5443                    let task_context =
 5444                        tasks
 5445                            .as_ref()
 5446                            .zip(editor.project.clone())
 5447                            .map(|(tasks, project)| {
 5448                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5449                            });
 5450
 5451                    Some(cx.spawn_in(window, async move |editor, cx| {
 5452                        let task_context = match task_context {
 5453                            Some(task_context) => task_context.await,
 5454                            None => None,
 5455                        };
 5456                        let resolved_tasks =
 5457                            tasks
 5458                                .zip(task_context.clone())
 5459                                .map(|(tasks, task_context)| ResolvedTasks {
 5460                                    templates: tasks.resolve(&task_context).collect(),
 5461                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5462                                        multibuffer_point.row,
 5463                                        tasks.column,
 5464                                    )),
 5465                                });
 5466                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5467                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5468                                maybe!({
 5469                                    let project = editor.project.as_ref()?;
 5470                                    let dap_store = project.read(cx).dap_store();
 5471                                    let mut scenarios = vec![];
 5472                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5473                                    let buffer = buffer.read(cx);
 5474                                    let language = buffer.language()?;
 5475                                    let file = buffer.file();
 5476                                    let debug_adapter =
 5477                                        language_settings(language.name().into(), file, cx)
 5478                                            .debuggers
 5479                                            .first()
 5480                                            .map(SharedString::from)
 5481                                            .or_else(|| {
 5482                                                language
 5483                                                    .config()
 5484                                                    .debuggers
 5485                                                    .first()
 5486                                                    .map(SharedString::from)
 5487                                            })?;
 5488
 5489                                    dap_store.update(cx, |dap_store, cx| {
 5490                                        for (_, task) in &resolved_tasks.templates {
 5491                                            if let Some(scenario) = dap_store
 5492                                                .debug_scenario_for_build_task(
 5493                                                    task.original_task().clone(),
 5494                                                    debug_adapter.clone().into(),
 5495                                                    task.display_label().to_owned().into(),
 5496                                                    cx,
 5497                                                )
 5498                                            {
 5499                                                scenarios.push(scenario);
 5500                                            }
 5501                                        }
 5502                                    });
 5503                                    Some(scenarios)
 5504                                })
 5505                                .unwrap_or_default()
 5506                            } else {
 5507                                vec![]
 5508                            }
 5509                        })?;
 5510                        let spawn_straight_away = quick_launch
 5511                            && resolved_tasks
 5512                                .as_ref()
 5513                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5514                            && code_actions
 5515                                .as_ref()
 5516                                .map_or(true, |actions| actions.is_empty())
 5517                            && debug_scenarios.is_empty();
 5518                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5519                            crate::hover_popover::hide_hover(editor, cx);
 5520                            *editor.context_menu.borrow_mut() =
 5521                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5522                                    buffer,
 5523                                    actions: CodeActionContents::new(
 5524                                        resolved_tasks,
 5525                                        code_actions,
 5526                                        debug_scenarios,
 5527                                        task_context.unwrap_or_default(),
 5528                                    ),
 5529                                    selected_item: Default::default(),
 5530                                    scroll_handle: UniformListScrollHandle::default(),
 5531                                    deployed_from_indicator,
 5532                                }));
 5533                            if spawn_straight_away {
 5534                                if let Some(task) = editor.confirm_code_action(
 5535                                    &ConfirmCodeAction { item_ix: Some(0) },
 5536                                    window,
 5537                                    cx,
 5538                                ) {
 5539                                    cx.notify();
 5540                                    return task;
 5541                                }
 5542                            }
 5543                            cx.notify();
 5544                            Task::ready(Ok(()))
 5545                        }) {
 5546                            task.await
 5547                        } else {
 5548                            Ok(())
 5549                        }
 5550                    }))
 5551                } else {
 5552                    Some(Task::ready(Ok(())))
 5553                }
 5554            })?;
 5555            if let Some(task) = spawned_test_task {
 5556                task.await?;
 5557            }
 5558
 5559            anyhow::Ok(())
 5560        })
 5561        .detach_and_log_err(cx);
 5562    }
 5563
 5564    pub fn confirm_code_action(
 5565        &mut self,
 5566        action: &ConfirmCodeAction,
 5567        window: &mut Window,
 5568        cx: &mut Context<Self>,
 5569    ) -> Option<Task<Result<()>>> {
 5570        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5571
 5572        let actions_menu =
 5573            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5574                menu
 5575            } else {
 5576                return None;
 5577            };
 5578
 5579        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5580        let action = actions_menu.actions.get(action_ix)?;
 5581        let title = action.label();
 5582        let buffer = actions_menu.buffer;
 5583        let workspace = self.workspace()?;
 5584
 5585        match action {
 5586            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5587                workspace.update(cx, |workspace, cx| {
 5588                    workspace.schedule_resolved_task(
 5589                        task_source_kind,
 5590                        resolved_task,
 5591                        false,
 5592                        window,
 5593                        cx,
 5594                    );
 5595
 5596                    Some(Task::ready(Ok(())))
 5597                })
 5598            }
 5599            CodeActionsItem::CodeAction {
 5600                excerpt_id,
 5601                action,
 5602                provider,
 5603            } => {
 5604                let apply_code_action =
 5605                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5606                let workspace = workspace.downgrade();
 5607                Some(cx.spawn_in(window, async move |editor, cx| {
 5608                    let project_transaction = apply_code_action.await?;
 5609                    Self::open_project_transaction(
 5610                        &editor,
 5611                        workspace,
 5612                        project_transaction,
 5613                        title,
 5614                        cx,
 5615                    )
 5616                    .await
 5617                }))
 5618            }
 5619            CodeActionsItem::DebugScenario(scenario) => {
 5620                let context = actions_menu.actions.context.clone();
 5621
 5622                workspace.update(cx, |workspace, cx| {
 5623                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5624                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5625                });
 5626                Some(Task::ready(Ok(())))
 5627            }
 5628        }
 5629    }
 5630
 5631    pub async fn open_project_transaction(
 5632        this: &WeakEntity<Editor>,
 5633        workspace: WeakEntity<Workspace>,
 5634        transaction: ProjectTransaction,
 5635        title: String,
 5636        cx: &mut AsyncWindowContext,
 5637    ) -> Result<()> {
 5638        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5639        cx.update(|_, cx| {
 5640            entries.sort_unstable_by_key(|(buffer, _)| {
 5641                buffer.read(cx).file().map(|f| f.path().clone())
 5642            });
 5643        })?;
 5644
 5645        // If the project transaction's edits are all contained within this editor, then
 5646        // avoid opening a new editor to display them.
 5647
 5648        if let Some((buffer, transaction)) = entries.first() {
 5649            if entries.len() == 1 {
 5650                let excerpt = this.update(cx, |editor, cx| {
 5651                    editor
 5652                        .buffer()
 5653                        .read(cx)
 5654                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5655                })?;
 5656                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5657                    if excerpted_buffer == *buffer {
 5658                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5659                            let excerpt_range = excerpt_range.to_offset(buffer);
 5660                            buffer
 5661                                .edited_ranges_for_transaction::<usize>(transaction)
 5662                                .all(|range| {
 5663                                    excerpt_range.start <= range.start
 5664                                        && excerpt_range.end >= range.end
 5665                                })
 5666                        })?;
 5667
 5668                        if all_edits_within_excerpt {
 5669                            return Ok(());
 5670                        }
 5671                    }
 5672                }
 5673            }
 5674        } else {
 5675            return Ok(());
 5676        }
 5677
 5678        let mut ranges_to_highlight = Vec::new();
 5679        let excerpt_buffer = cx.new(|cx| {
 5680            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5681            for (buffer_handle, transaction) in &entries {
 5682                let edited_ranges = buffer_handle
 5683                    .read(cx)
 5684                    .edited_ranges_for_transaction::<Point>(transaction)
 5685                    .collect::<Vec<_>>();
 5686                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5687                    PathKey::for_buffer(buffer_handle, cx),
 5688                    buffer_handle.clone(),
 5689                    edited_ranges,
 5690                    DEFAULT_MULTIBUFFER_CONTEXT,
 5691                    cx,
 5692                );
 5693
 5694                ranges_to_highlight.extend(ranges);
 5695            }
 5696            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5697            multibuffer
 5698        })?;
 5699
 5700        workspace.update_in(cx, |workspace, window, cx| {
 5701            let project = workspace.project().clone();
 5702            let editor =
 5703                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5704            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5705            editor.update(cx, |editor, cx| {
 5706                editor.highlight_background::<Self>(
 5707                    &ranges_to_highlight,
 5708                    |theme| theme.editor_highlighted_line_background,
 5709                    cx,
 5710                );
 5711            });
 5712        })?;
 5713
 5714        Ok(())
 5715    }
 5716
 5717    pub fn clear_code_action_providers(&mut self) {
 5718        self.code_action_providers.clear();
 5719        self.available_code_actions.take();
 5720    }
 5721
 5722    pub fn add_code_action_provider(
 5723        &mut self,
 5724        provider: Rc<dyn CodeActionProvider>,
 5725        window: &mut Window,
 5726        cx: &mut Context<Self>,
 5727    ) {
 5728        if self
 5729            .code_action_providers
 5730            .iter()
 5731            .any(|existing_provider| existing_provider.id() == provider.id())
 5732        {
 5733            return;
 5734        }
 5735
 5736        self.code_action_providers.push(provider);
 5737        self.refresh_code_actions(window, cx);
 5738    }
 5739
 5740    pub fn remove_code_action_provider(
 5741        &mut self,
 5742        id: Arc<str>,
 5743        window: &mut Window,
 5744        cx: &mut Context<Self>,
 5745    ) {
 5746        self.code_action_providers
 5747            .retain(|provider| provider.id() != id);
 5748        self.refresh_code_actions(window, cx);
 5749    }
 5750
 5751    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5752        let newest_selection = self.selections.newest_anchor().clone();
 5753        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5754        let buffer = self.buffer.read(cx);
 5755        if newest_selection.head().diff_base_anchor.is_some() {
 5756            return None;
 5757        }
 5758        let (start_buffer, start) =
 5759            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5760        let (end_buffer, end) =
 5761            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5762        if start_buffer != end_buffer {
 5763            return None;
 5764        }
 5765
 5766        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5767            cx.background_executor()
 5768                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5769                .await;
 5770
 5771            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5772                let providers = this.code_action_providers.clone();
 5773                let tasks = this
 5774                    .code_action_providers
 5775                    .iter()
 5776                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5777                    .collect::<Vec<_>>();
 5778                (providers, tasks)
 5779            })?;
 5780
 5781            let mut actions = Vec::new();
 5782            for (provider, provider_actions) in
 5783                providers.into_iter().zip(future::join_all(tasks).await)
 5784            {
 5785                if let Some(provider_actions) = provider_actions.log_err() {
 5786                    actions.extend(provider_actions.into_iter().map(|action| {
 5787                        AvailableCodeAction {
 5788                            excerpt_id: newest_selection.start.excerpt_id,
 5789                            action,
 5790                            provider: provider.clone(),
 5791                        }
 5792                    }));
 5793                }
 5794            }
 5795
 5796            this.update(cx, |this, cx| {
 5797                this.available_code_actions = if actions.is_empty() {
 5798                    None
 5799                } else {
 5800                    Some((
 5801                        Location {
 5802                            buffer: start_buffer,
 5803                            range: start..end,
 5804                        },
 5805                        actions.into(),
 5806                    ))
 5807                };
 5808                cx.notify();
 5809            })
 5810        }));
 5811        None
 5812    }
 5813
 5814    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5815        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5816            self.show_git_blame_inline = false;
 5817
 5818            self.show_git_blame_inline_delay_task =
 5819                Some(cx.spawn_in(window, async move |this, cx| {
 5820                    cx.background_executor().timer(delay).await;
 5821
 5822                    this.update(cx, |this, cx| {
 5823                        this.show_git_blame_inline = true;
 5824                        cx.notify();
 5825                    })
 5826                    .log_err();
 5827                }));
 5828        }
 5829    }
 5830
 5831    fn show_blame_popover(
 5832        &mut self,
 5833        blame_entry: &BlameEntry,
 5834        position: gpui::Point<Pixels>,
 5835        cx: &mut Context<Self>,
 5836    ) {
 5837        if let Some(state) = &mut self.inline_blame_popover {
 5838            state.hide_task.take();
 5839            cx.notify();
 5840        } else {
 5841            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5842            let show_task = cx.spawn(async move |editor, cx| {
 5843                cx.background_executor()
 5844                    .timer(std::time::Duration::from_millis(delay))
 5845                    .await;
 5846                editor
 5847                    .update(cx, |editor, cx| {
 5848                        if let Some(state) = &mut editor.inline_blame_popover {
 5849                            state.show_task = None;
 5850                            cx.notify();
 5851                        }
 5852                    })
 5853                    .ok();
 5854            });
 5855            let Some(blame) = self.blame.as_ref() else {
 5856                return;
 5857            };
 5858            let blame = blame.read(cx);
 5859            let details = blame.details_for_entry(&blame_entry);
 5860            let markdown = cx.new(|cx| {
 5861                Markdown::new(
 5862                    details
 5863                        .as_ref()
 5864                        .map(|message| message.message.clone())
 5865                        .unwrap_or_default(),
 5866                    None,
 5867                    None,
 5868                    cx,
 5869                )
 5870            });
 5871            self.inline_blame_popover = Some(InlineBlamePopover {
 5872                position,
 5873                show_task: Some(show_task),
 5874                hide_task: None,
 5875                popover_bounds: None,
 5876                popover_state: InlineBlamePopoverState {
 5877                    scroll_handle: ScrollHandle::new(),
 5878                    commit_message: details,
 5879                    markdown,
 5880                },
 5881            });
 5882        }
 5883    }
 5884
 5885    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5886        if let Some(state) = &mut self.inline_blame_popover {
 5887            if state.show_task.is_some() {
 5888                self.inline_blame_popover.take();
 5889                cx.notify();
 5890            } else {
 5891                let hide_task = cx.spawn(async move |editor, cx| {
 5892                    cx.background_executor()
 5893                        .timer(std::time::Duration::from_millis(100))
 5894                        .await;
 5895                    editor
 5896                        .update(cx, |editor, cx| {
 5897                            editor.inline_blame_popover.take();
 5898                            cx.notify();
 5899                        })
 5900                        .ok();
 5901                });
 5902                state.hide_task = Some(hide_task);
 5903            }
 5904        }
 5905    }
 5906
 5907    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5908        if self.pending_rename.is_some() {
 5909            return None;
 5910        }
 5911
 5912        let provider = self.semantics_provider.clone()?;
 5913        let buffer = self.buffer.read(cx);
 5914        let newest_selection = self.selections.newest_anchor().clone();
 5915        let cursor_position = newest_selection.head();
 5916        let (cursor_buffer, cursor_buffer_position) =
 5917            buffer.text_anchor_for_position(cursor_position, cx)?;
 5918        let (tail_buffer, tail_buffer_position) =
 5919            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5920        if cursor_buffer != tail_buffer {
 5921            return None;
 5922        }
 5923
 5924        let snapshot = cursor_buffer.read(cx).snapshot();
 5925        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5926        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5927        if start_word_range != end_word_range {
 5928            self.document_highlights_task.take();
 5929            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5930            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5931            return None;
 5932        }
 5933
 5934        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5935        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5936            cx.background_executor()
 5937                .timer(Duration::from_millis(debounce))
 5938                .await;
 5939
 5940            let highlights = if let Some(highlights) = cx
 5941                .update(|cx| {
 5942                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5943                })
 5944                .ok()
 5945                .flatten()
 5946            {
 5947                highlights.await.log_err()
 5948            } else {
 5949                None
 5950            };
 5951
 5952            if let Some(highlights) = highlights {
 5953                this.update(cx, |this, cx| {
 5954                    if this.pending_rename.is_some() {
 5955                        return;
 5956                    }
 5957
 5958                    let buffer_id = cursor_position.buffer_id;
 5959                    let buffer = this.buffer.read(cx);
 5960                    if !buffer
 5961                        .text_anchor_for_position(cursor_position, cx)
 5962                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5963                    {
 5964                        return;
 5965                    }
 5966
 5967                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5968                    let mut write_ranges = Vec::new();
 5969                    let mut read_ranges = Vec::new();
 5970                    for highlight in highlights {
 5971                        for (excerpt_id, excerpt_range) in
 5972                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5973                        {
 5974                            let start = highlight
 5975                                .range
 5976                                .start
 5977                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5978                            let end = highlight
 5979                                .range
 5980                                .end
 5981                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5982                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5983                                continue;
 5984                            }
 5985
 5986                            let range = Anchor {
 5987                                buffer_id,
 5988                                excerpt_id,
 5989                                text_anchor: start,
 5990                                diff_base_anchor: None,
 5991                            }..Anchor {
 5992                                buffer_id,
 5993                                excerpt_id,
 5994                                text_anchor: end,
 5995                                diff_base_anchor: None,
 5996                            };
 5997                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5998                                write_ranges.push(range);
 5999                            } else {
 6000                                read_ranges.push(range);
 6001                            }
 6002                        }
 6003                    }
 6004
 6005                    this.highlight_background::<DocumentHighlightRead>(
 6006                        &read_ranges,
 6007                        |theme| theme.editor_document_highlight_read_background,
 6008                        cx,
 6009                    );
 6010                    this.highlight_background::<DocumentHighlightWrite>(
 6011                        &write_ranges,
 6012                        |theme| theme.editor_document_highlight_write_background,
 6013                        cx,
 6014                    );
 6015                    cx.notify();
 6016                })
 6017                .log_err();
 6018            }
 6019        }));
 6020        None
 6021    }
 6022
 6023    fn prepare_highlight_query_from_selection(
 6024        &mut self,
 6025        cx: &mut Context<Editor>,
 6026    ) -> Option<(String, Range<Anchor>)> {
 6027        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6028            return None;
 6029        }
 6030        if !EditorSettings::get_global(cx).selection_highlight {
 6031            return None;
 6032        }
 6033        if self.selections.count() != 1 || self.selections.line_mode {
 6034            return None;
 6035        }
 6036        let selection = self.selections.newest::<Point>(cx);
 6037        if selection.is_empty() || selection.start.row != selection.end.row {
 6038            return None;
 6039        }
 6040        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6041        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6042        let query = multi_buffer_snapshot
 6043            .text_for_range(selection_anchor_range.clone())
 6044            .collect::<String>();
 6045        if query.trim().is_empty() {
 6046            return None;
 6047        }
 6048        Some((query, selection_anchor_range))
 6049    }
 6050
 6051    fn update_selection_occurrence_highlights(
 6052        &mut self,
 6053        query_text: String,
 6054        query_range: Range<Anchor>,
 6055        multi_buffer_range_to_query: Range<Point>,
 6056        use_debounce: bool,
 6057        window: &mut Window,
 6058        cx: &mut Context<Editor>,
 6059    ) -> Task<()> {
 6060        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6061        cx.spawn_in(window, async move |editor, cx| {
 6062            if use_debounce {
 6063                cx.background_executor()
 6064                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6065                    .await;
 6066            }
 6067            let match_task = cx.background_spawn(async move {
 6068                let buffer_ranges = multi_buffer_snapshot
 6069                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6070                    .into_iter()
 6071                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6072                let mut match_ranges = Vec::new();
 6073                let Ok(regex) = project::search::SearchQuery::text(
 6074                    query_text.clone(),
 6075                    false,
 6076                    false,
 6077                    false,
 6078                    Default::default(),
 6079                    Default::default(),
 6080                    false,
 6081                    None,
 6082                ) else {
 6083                    return Vec::default();
 6084                };
 6085                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6086                    match_ranges.extend(
 6087                        regex
 6088                            .search(&buffer_snapshot, Some(search_range.clone()))
 6089                            .await
 6090                            .into_iter()
 6091                            .filter_map(|match_range| {
 6092                                let match_start = buffer_snapshot
 6093                                    .anchor_after(search_range.start + match_range.start);
 6094                                let match_end = buffer_snapshot
 6095                                    .anchor_before(search_range.start + match_range.end);
 6096                                let match_anchor_range = Anchor::range_in_buffer(
 6097                                    excerpt_id,
 6098                                    buffer_snapshot.remote_id(),
 6099                                    match_start..match_end,
 6100                                );
 6101                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6102                            }),
 6103                    );
 6104                }
 6105                match_ranges
 6106            });
 6107            let match_ranges = match_task.await;
 6108            editor
 6109                .update_in(cx, |editor, _, cx| {
 6110                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6111                    if !match_ranges.is_empty() {
 6112                        editor.highlight_background::<SelectedTextHighlight>(
 6113                            &match_ranges,
 6114                            |theme| theme.editor_document_highlight_bracket_background,
 6115                            cx,
 6116                        )
 6117                    }
 6118                })
 6119                .log_err();
 6120        })
 6121    }
 6122
 6123    fn refresh_selected_text_highlights(
 6124        &mut self,
 6125        on_buffer_edit: bool,
 6126        window: &mut Window,
 6127        cx: &mut Context<Editor>,
 6128    ) {
 6129        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6130        else {
 6131            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6132            self.quick_selection_highlight_task.take();
 6133            self.debounced_selection_highlight_task.take();
 6134            return;
 6135        };
 6136        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6137        if on_buffer_edit
 6138            || self
 6139                .quick_selection_highlight_task
 6140                .as_ref()
 6141                .map_or(true, |(prev_anchor_range, _)| {
 6142                    prev_anchor_range != &query_range
 6143                })
 6144        {
 6145            let multi_buffer_visible_start = self
 6146                .scroll_manager
 6147                .anchor()
 6148                .anchor
 6149                .to_point(&multi_buffer_snapshot);
 6150            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6151                multi_buffer_visible_start
 6152                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6153                Bias::Left,
 6154            );
 6155            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6156            self.quick_selection_highlight_task = Some((
 6157                query_range.clone(),
 6158                self.update_selection_occurrence_highlights(
 6159                    query_text.clone(),
 6160                    query_range.clone(),
 6161                    multi_buffer_visible_range,
 6162                    false,
 6163                    window,
 6164                    cx,
 6165                ),
 6166            ));
 6167        }
 6168        if on_buffer_edit
 6169            || self
 6170                .debounced_selection_highlight_task
 6171                .as_ref()
 6172                .map_or(true, |(prev_anchor_range, _)| {
 6173                    prev_anchor_range != &query_range
 6174                })
 6175        {
 6176            let multi_buffer_start = multi_buffer_snapshot
 6177                .anchor_before(0)
 6178                .to_point(&multi_buffer_snapshot);
 6179            let multi_buffer_end = multi_buffer_snapshot
 6180                .anchor_after(multi_buffer_snapshot.len())
 6181                .to_point(&multi_buffer_snapshot);
 6182            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6183            self.debounced_selection_highlight_task = Some((
 6184                query_range.clone(),
 6185                self.update_selection_occurrence_highlights(
 6186                    query_text,
 6187                    query_range,
 6188                    multi_buffer_full_range,
 6189                    true,
 6190                    window,
 6191                    cx,
 6192                ),
 6193            ));
 6194        }
 6195    }
 6196
 6197    pub fn refresh_inline_completion(
 6198        &mut self,
 6199        debounce: bool,
 6200        user_requested: bool,
 6201        window: &mut Window,
 6202        cx: &mut Context<Self>,
 6203    ) -> Option<()> {
 6204        let provider = self.edit_prediction_provider()?;
 6205        let cursor = self.selections.newest_anchor().head();
 6206        let (buffer, cursor_buffer_position) =
 6207            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6208
 6209        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6210            self.discard_inline_completion(false, cx);
 6211            return None;
 6212        }
 6213
 6214        if !user_requested
 6215            && (!self.should_show_edit_predictions()
 6216                || !self.is_focused(window)
 6217                || buffer.read(cx).is_empty())
 6218        {
 6219            self.discard_inline_completion(false, cx);
 6220            return None;
 6221        }
 6222
 6223        self.update_visible_inline_completion(window, cx);
 6224        provider.refresh(
 6225            self.project.clone(),
 6226            buffer,
 6227            cursor_buffer_position,
 6228            debounce,
 6229            cx,
 6230        );
 6231        Some(())
 6232    }
 6233
 6234    fn show_edit_predictions_in_menu(&self) -> bool {
 6235        match self.edit_prediction_settings {
 6236            EditPredictionSettings::Disabled => false,
 6237            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6238        }
 6239    }
 6240
 6241    pub fn edit_predictions_enabled(&self) -> bool {
 6242        match self.edit_prediction_settings {
 6243            EditPredictionSettings::Disabled => false,
 6244            EditPredictionSettings::Enabled { .. } => true,
 6245        }
 6246    }
 6247
 6248    fn edit_prediction_requires_modifier(&self) -> bool {
 6249        match self.edit_prediction_settings {
 6250            EditPredictionSettings::Disabled => false,
 6251            EditPredictionSettings::Enabled {
 6252                preview_requires_modifier,
 6253                ..
 6254            } => preview_requires_modifier,
 6255        }
 6256    }
 6257
 6258    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6259        if self.edit_prediction_provider.is_none() {
 6260            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6261        } else {
 6262            let selection = self.selections.newest_anchor();
 6263            let cursor = selection.head();
 6264
 6265            if let Some((buffer, cursor_buffer_position)) =
 6266                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6267            {
 6268                self.edit_prediction_settings =
 6269                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6270            }
 6271        }
 6272    }
 6273
 6274    fn edit_prediction_settings_at_position(
 6275        &self,
 6276        buffer: &Entity<Buffer>,
 6277        buffer_position: language::Anchor,
 6278        cx: &App,
 6279    ) -> EditPredictionSettings {
 6280        if !self.mode.is_full()
 6281            || !self.show_inline_completions_override.unwrap_or(true)
 6282            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6283        {
 6284            return EditPredictionSettings::Disabled;
 6285        }
 6286
 6287        let buffer = buffer.read(cx);
 6288
 6289        let file = buffer.file();
 6290
 6291        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6292            return EditPredictionSettings::Disabled;
 6293        };
 6294
 6295        let by_provider = matches!(
 6296            self.menu_inline_completions_policy,
 6297            MenuInlineCompletionsPolicy::ByProvider
 6298        );
 6299
 6300        let show_in_menu = by_provider
 6301            && self
 6302                .edit_prediction_provider
 6303                .as_ref()
 6304                .map_or(false, |provider| {
 6305                    provider.provider.show_completions_in_menu()
 6306                });
 6307
 6308        let preview_requires_modifier =
 6309            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6310
 6311        EditPredictionSettings::Enabled {
 6312            show_in_menu,
 6313            preview_requires_modifier,
 6314        }
 6315    }
 6316
 6317    fn should_show_edit_predictions(&self) -> bool {
 6318        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6319    }
 6320
 6321    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6322        matches!(
 6323            self.edit_prediction_preview,
 6324            EditPredictionPreview::Active { .. }
 6325        )
 6326    }
 6327
 6328    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6329        let cursor = self.selections.newest_anchor().head();
 6330        if let Some((buffer, cursor_position)) =
 6331            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6332        {
 6333            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6334        } else {
 6335            false
 6336        }
 6337    }
 6338
 6339    pub fn supports_minimap(&self, cx: &App) -> bool {
 6340        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6341    }
 6342
 6343    fn edit_predictions_enabled_in_buffer(
 6344        &self,
 6345        buffer: &Entity<Buffer>,
 6346        buffer_position: language::Anchor,
 6347        cx: &App,
 6348    ) -> bool {
 6349        maybe!({
 6350            if self.read_only(cx) {
 6351                return Some(false);
 6352            }
 6353            let provider = self.edit_prediction_provider()?;
 6354            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6355                return Some(false);
 6356            }
 6357            let buffer = buffer.read(cx);
 6358            let Some(file) = buffer.file() else {
 6359                return Some(true);
 6360            };
 6361            let settings = all_language_settings(Some(file), cx);
 6362            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6363        })
 6364        .unwrap_or(false)
 6365    }
 6366
 6367    fn cycle_inline_completion(
 6368        &mut self,
 6369        direction: Direction,
 6370        window: &mut Window,
 6371        cx: &mut Context<Self>,
 6372    ) -> Option<()> {
 6373        let provider = self.edit_prediction_provider()?;
 6374        let cursor = self.selections.newest_anchor().head();
 6375        let (buffer, cursor_buffer_position) =
 6376            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6377        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6378            return None;
 6379        }
 6380
 6381        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6382        self.update_visible_inline_completion(window, cx);
 6383
 6384        Some(())
 6385    }
 6386
 6387    pub fn show_inline_completion(
 6388        &mut self,
 6389        _: &ShowEditPrediction,
 6390        window: &mut Window,
 6391        cx: &mut Context<Self>,
 6392    ) {
 6393        if !self.has_active_inline_completion() {
 6394            self.refresh_inline_completion(false, true, window, cx);
 6395            return;
 6396        }
 6397
 6398        self.update_visible_inline_completion(window, cx);
 6399    }
 6400
 6401    pub fn display_cursor_names(
 6402        &mut self,
 6403        _: &DisplayCursorNames,
 6404        window: &mut Window,
 6405        cx: &mut Context<Self>,
 6406    ) {
 6407        self.show_cursor_names(window, cx);
 6408    }
 6409
 6410    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6411        self.show_cursor_names = true;
 6412        cx.notify();
 6413        cx.spawn_in(window, async move |this, cx| {
 6414            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6415            this.update(cx, |this, cx| {
 6416                this.show_cursor_names = false;
 6417                cx.notify()
 6418            })
 6419            .ok()
 6420        })
 6421        .detach();
 6422    }
 6423
 6424    pub fn next_edit_prediction(
 6425        &mut self,
 6426        _: &NextEditPrediction,
 6427        window: &mut Window,
 6428        cx: &mut Context<Self>,
 6429    ) {
 6430        if self.has_active_inline_completion() {
 6431            self.cycle_inline_completion(Direction::Next, window, cx);
 6432        } else {
 6433            let is_copilot_disabled = self
 6434                .refresh_inline_completion(false, true, window, cx)
 6435                .is_none();
 6436            if is_copilot_disabled {
 6437                cx.propagate();
 6438            }
 6439        }
 6440    }
 6441
 6442    pub fn previous_edit_prediction(
 6443        &mut self,
 6444        _: &PreviousEditPrediction,
 6445        window: &mut Window,
 6446        cx: &mut Context<Self>,
 6447    ) {
 6448        if self.has_active_inline_completion() {
 6449            self.cycle_inline_completion(Direction::Prev, window, cx);
 6450        } else {
 6451            let is_copilot_disabled = self
 6452                .refresh_inline_completion(false, true, window, cx)
 6453                .is_none();
 6454            if is_copilot_disabled {
 6455                cx.propagate();
 6456            }
 6457        }
 6458    }
 6459
 6460    pub fn accept_edit_prediction(
 6461        &mut self,
 6462        _: &AcceptEditPrediction,
 6463        window: &mut Window,
 6464        cx: &mut Context<Self>,
 6465    ) {
 6466        if self.show_edit_predictions_in_menu() {
 6467            self.hide_context_menu(window, cx);
 6468        }
 6469
 6470        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6471            return;
 6472        };
 6473
 6474        self.report_inline_completion_event(
 6475            active_inline_completion.completion_id.clone(),
 6476            true,
 6477            cx,
 6478        );
 6479
 6480        match &active_inline_completion.completion {
 6481            InlineCompletion::Move { target, .. } => {
 6482                let target = *target;
 6483
 6484                if let Some(position_map) = &self.last_position_map {
 6485                    if position_map
 6486                        .visible_row_range
 6487                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6488                        || !self.edit_prediction_requires_modifier()
 6489                    {
 6490                        self.unfold_ranges(&[target..target], true, false, cx);
 6491                        // Note that this is also done in vim's handler of the Tab action.
 6492                        self.change_selections(
 6493                            Some(Autoscroll::newest()),
 6494                            window,
 6495                            cx,
 6496                            |selections| {
 6497                                selections.select_anchor_ranges([target..target]);
 6498                            },
 6499                        );
 6500                        self.clear_row_highlights::<EditPredictionPreview>();
 6501
 6502                        self.edit_prediction_preview
 6503                            .set_previous_scroll_position(None);
 6504                    } else {
 6505                        self.edit_prediction_preview
 6506                            .set_previous_scroll_position(Some(
 6507                                position_map.snapshot.scroll_anchor,
 6508                            ));
 6509
 6510                        self.highlight_rows::<EditPredictionPreview>(
 6511                            target..target,
 6512                            cx.theme().colors().editor_highlighted_line_background,
 6513                            RowHighlightOptions {
 6514                                autoscroll: true,
 6515                                ..Default::default()
 6516                            },
 6517                            cx,
 6518                        );
 6519                        self.request_autoscroll(Autoscroll::fit(), cx);
 6520                    }
 6521                }
 6522            }
 6523            InlineCompletion::Edit { edits, .. } => {
 6524                if let Some(provider) = self.edit_prediction_provider() {
 6525                    provider.accept(cx);
 6526                }
 6527
 6528                // Store the transaction ID and selections before applying the edit
 6529                let transaction_id_prev =
 6530                    self.buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
 6531
 6532                let snapshot = self.buffer.read(cx).snapshot(cx);
 6533                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6534
 6535                self.buffer.update(cx, |buffer, cx| {
 6536                    buffer.edit(edits.iter().cloned(), None, cx)
 6537                });
 6538
 6539                self.change_selections(None, window, cx, |s| {
 6540                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6541                });
 6542
 6543                let selections = self.selections.disjoint_anchors();
 6544                if let Some(transaction_id_now) =
 6545                    self.buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
 6546                {
 6547                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6548                    if has_new_transaction {
 6549                        self.selection_history
 6550                            .insert_transaction(transaction_id_now, selections);
 6551                    }
 6552                }
 6553
 6554                self.update_visible_inline_completion(window, cx);
 6555                if self.active_inline_completion.is_none() {
 6556                    self.refresh_inline_completion(true, true, window, cx);
 6557                }
 6558
 6559                cx.notify();
 6560            }
 6561        }
 6562
 6563        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6564    }
 6565
 6566    pub fn accept_partial_inline_completion(
 6567        &mut self,
 6568        _: &AcceptPartialEditPrediction,
 6569        window: &mut Window,
 6570        cx: &mut Context<Self>,
 6571    ) {
 6572        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6573            return;
 6574        };
 6575        if self.selections.count() != 1 {
 6576            return;
 6577        }
 6578
 6579        self.report_inline_completion_event(
 6580            active_inline_completion.completion_id.clone(),
 6581            true,
 6582            cx,
 6583        );
 6584
 6585        match &active_inline_completion.completion {
 6586            InlineCompletion::Move { target, .. } => {
 6587                let target = *target;
 6588                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6589                    selections.select_anchor_ranges([target..target]);
 6590                });
 6591            }
 6592            InlineCompletion::Edit { edits, .. } => {
 6593                // Find an insertion that starts at the cursor position.
 6594                let snapshot = self.buffer.read(cx).snapshot(cx);
 6595                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6596                let insertion = edits.iter().find_map(|(range, text)| {
 6597                    let range = range.to_offset(&snapshot);
 6598                    if range.is_empty() && range.start == cursor_offset {
 6599                        Some(text)
 6600                    } else {
 6601                        None
 6602                    }
 6603                });
 6604
 6605                if let Some(text) = insertion {
 6606                    let mut partial_completion = text
 6607                        .chars()
 6608                        .by_ref()
 6609                        .take_while(|c| c.is_alphabetic())
 6610                        .collect::<String>();
 6611                    if partial_completion.is_empty() {
 6612                        partial_completion = text
 6613                            .chars()
 6614                            .by_ref()
 6615                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6616                            .collect::<String>();
 6617                    }
 6618
 6619                    cx.emit(EditorEvent::InputHandled {
 6620                        utf16_range_to_replace: None,
 6621                        text: partial_completion.clone().into(),
 6622                    });
 6623
 6624                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6625
 6626                    self.refresh_inline_completion(true, true, window, cx);
 6627                    cx.notify();
 6628                } else {
 6629                    self.accept_edit_prediction(&Default::default(), window, cx);
 6630                }
 6631            }
 6632        }
 6633    }
 6634
 6635    fn discard_inline_completion(
 6636        &mut self,
 6637        should_report_inline_completion_event: bool,
 6638        cx: &mut Context<Self>,
 6639    ) -> bool {
 6640        if should_report_inline_completion_event {
 6641            let completion_id = self
 6642                .active_inline_completion
 6643                .as_ref()
 6644                .and_then(|active_completion| active_completion.completion_id.clone());
 6645
 6646            self.report_inline_completion_event(completion_id, false, cx);
 6647        }
 6648
 6649        if let Some(provider) = self.edit_prediction_provider() {
 6650            provider.discard(cx);
 6651        }
 6652
 6653        self.take_active_inline_completion(cx)
 6654    }
 6655
 6656    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6657        let Some(provider) = self.edit_prediction_provider() else {
 6658            return;
 6659        };
 6660
 6661        let Some((_, buffer, _)) = self
 6662            .buffer
 6663            .read(cx)
 6664            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6665        else {
 6666            return;
 6667        };
 6668
 6669        let extension = buffer
 6670            .read(cx)
 6671            .file()
 6672            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6673
 6674        let event_type = match accepted {
 6675            true => "Edit Prediction Accepted",
 6676            false => "Edit Prediction Discarded",
 6677        };
 6678        telemetry::event!(
 6679            event_type,
 6680            provider = provider.name(),
 6681            prediction_id = id,
 6682            suggestion_accepted = accepted,
 6683            file_extension = extension,
 6684        );
 6685    }
 6686
 6687    pub fn has_active_inline_completion(&self) -> bool {
 6688        self.active_inline_completion.is_some()
 6689    }
 6690
 6691    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6692        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6693            return false;
 6694        };
 6695
 6696        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6697        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6698        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6699        true
 6700    }
 6701
 6702    /// Returns true when we're displaying the edit prediction popover below the cursor
 6703    /// like we are not previewing and the LSP autocomplete menu is visible
 6704    /// or we are in `when_holding_modifier` mode.
 6705    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6706        if self.edit_prediction_preview_is_active()
 6707            || !self.show_edit_predictions_in_menu()
 6708            || !self.edit_predictions_enabled()
 6709        {
 6710            return false;
 6711        }
 6712
 6713        if self.has_visible_completions_menu() {
 6714            return true;
 6715        }
 6716
 6717        has_completion && self.edit_prediction_requires_modifier()
 6718    }
 6719
 6720    fn handle_modifiers_changed(
 6721        &mut self,
 6722        modifiers: Modifiers,
 6723        position_map: &PositionMap,
 6724        window: &mut Window,
 6725        cx: &mut Context<Self>,
 6726    ) {
 6727        if self.show_edit_predictions_in_menu() {
 6728            self.update_edit_prediction_preview(&modifiers, window, cx);
 6729        }
 6730
 6731        self.update_selection_mode(&modifiers, position_map, window, cx);
 6732
 6733        let mouse_position = window.mouse_position();
 6734        if !position_map.text_hitbox.is_hovered(window) {
 6735            return;
 6736        }
 6737
 6738        self.update_hovered_link(
 6739            position_map.point_for_position(mouse_position),
 6740            &position_map.snapshot,
 6741            modifiers,
 6742            window,
 6743            cx,
 6744        )
 6745    }
 6746
 6747    fn update_selection_mode(
 6748        &mut self,
 6749        modifiers: &Modifiers,
 6750        position_map: &PositionMap,
 6751        window: &mut Window,
 6752        cx: &mut Context<Self>,
 6753    ) {
 6754        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6755            return;
 6756        }
 6757
 6758        let mouse_position = window.mouse_position();
 6759        let point_for_position = position_map.point_for_position(mouse_position);
 6760        let position = point_for_position.previous_valid;
 6761
 6762        self.select(
 6763            SelectPhase::BeginColumnar {
 6764                position,
 6765                reset: false,
 6766                goal_column: point_for_position.exact_unclipped.column(),
 6767            },
 6768            window,
 6769            cx,
 6770        );
 6771    }
 6772
 6773    fn update_edit_prediction_preview(
 6774        &mut self,
 6775        modifiers: &Modifiers,
 6776        window: &mut Window,
 6777        cx: &mut Context<Self>,
 6778    ) {
 6779        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6780        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6781            return;
 6782        };
 6783
 6784        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6785            if matches!(
 6786                self.edit_prediction_preview,
 6787                EditPredictionPreview::Inactive { .. }
 6788            ) {
 6789                self.edit_prediction_preview = EditPredictionPreview::Active {
 6790                    previous_scroll_position: None,
 6791                    since: Instant::now(),
 6792                };
 6793
 6794                self.update_visible_inline_completion(window, cx);
 6795                cx.notify();
 6796            }
 6797        } else if let EditPredictionPreview::Active {
 6798            previous_scroll_position,
 6799            since,
 6800        } = self.edit_prediction_preview
 6801        {
 6802            if let (Some(previous_scroll_position), Some(position_map)) =
 6803                (previous_scroll_position, self.last_position_map.as_ref())
 6804            {
 6805                self.set_scroll_position(
 6806                    previous_scroll_position
 6807                        .scroll_position(&position_map.snapshot.display_snapshot),
 6808                    window,
 6809                    cx,
 6810                );
 6811            }
 6812
 6813            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6814                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6815            };
 6816            self.clear_row_highlights::<EditPredictionPreview>();
 6817            self.update_visible_inline_completion(window, cx);
 6818            cx.notify();
 6819        }
 6820    }
 6821
 6822    fn update_visible_inline_completion(
 6823        &mut self,
 6824        _window: &mut Window,
 6825        cx: &mut Context<Self>,
 6826    ) -> Option<()> {
 6827        let selection = self.selections.newest_anchor();
 6828        let cursor = selection.head();
 6829        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6830        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6831        let excerpt_id = cursor.excerpt_id;
 6832
 6833        let show_in_menu = self.show_edit_predictions_in_menu();
 6834        let completions_menu_has_precedence = !show_in_menu
 6835            && (self.context_menu.borrow().is_some()
 6836                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6837
 6838        if completions_menu_has_precedence
 6839            || !offset_selection.is_empty()
 6840            || self
 6841                .active_inline_completion
 6842                .as_ref()
 6843                .map_or(false, |completion| {
 6844                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6845                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6846                    !invalidation_range.contains(&offset_selection.head())
 6847                })
 6848        {
 6849            self.discard_inline_completion(false, cx);
 6850            return None;
 6851        }
 6852
 6853        self.take_active_inline_completion(cx);
 6854        let Some(provider) = self.edit_prediction_provider() else {
 6855            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6856            return None;
 6857        };
 6858
 6859        let (buffer, cursor_buffer_position) =
 6860            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6861
 6862        self.edit_prediction_settings =
 6863            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6864
 6865        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6866
 6867        if self.edit_prediction_indent_conflict {
 6868            let cursor_point = cursor.to_point(&multibuffer);
 6869
 6870            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6871
 6872            if let Some((_, indent)) = indents.iter().next() {
 6873                if indent.len == cursor_point.column {
 6874                    self.edit_prediction_indent_conflict = false;
 6875                }
 6876            }
 6877        }
 6878
 6879        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6880        let edits = inline_completion
 6881            .edits
 6882            .into_iter()
 6883            .flat_map(|(range, new_text)| {
 6884                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6885                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6886                Some((start..end, new_text))
 6887            })
 6888            .collect::<Vec<_>>();
 6889        if edits.is_empty() {
 6890            return None;
 6891        }
 6892
 6893        let first_edit_start = edits.first().unwrap().0.start;
 6894        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6895        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6896
 6897        let last_edit_end = edits.last().unwrap().0.end;
 6898        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6899        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6900
 6901        let cursor_row = cursor.to_point(&multibuffer).row;
 6902
 6903        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6904
 6905        let mut inlay_ids = Vec::new();
 6906        let invalidation_row_range;
 6907        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6908            Some(cursor_row..edit_end_row)
 6909        } else if cursor_row > edit_end_row {
 6910            Some(edit_start_row..cursor_row)
 6911        } else {
 6912            None
 6913        };
 6914        let is_move =
 6915            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6916        let completion = if is_move {
 6917            invalidation_row_range =
 6918                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6919            let target = first_edit_start;
 6920            InlineCompletion::Move { target, snapshot }
 6921        } else {
 6922            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6923                && !self.inline_completions_hidden_for_vim_mode;
 6924
 6925            if show_completions_in_buffer {
 6926                if edits
 6927                    .iter()
 6928                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6929                {
 6930                    let mut inlays = Vec::new();
 6931                    for (range, new_text) in &edits {
 6932                        let inlay = Inlay::inline_completion(
 6933                            post_inc(&mut self.next_inlay_id),
 6934                            range.start,
 6935                            new_text.as_str(),
 6936                        );
 6937                        inlay_ids.push(inlay.id);
 6938                        inlays.push(inlay);
 6939                    }
 6940
 6941                    self.splice_inlays(&[], inlays, cx);
 6942                } else {
 6943                    let background_color = cx.theme().status().deleted_background;
 6944                    self.highlight_text::<InlineCompletionHighlight>(
 6945                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6946                        HighlightStyle {
 6947                            background_color: Some(background_color),
 6948                            ..Default::default()
 6949                        },
 6950                        cx,
 6951                    );
 6952                }
 6953            }
 6954
 6955            invalidation_row_range = edit_start_row..edit_end_row;
 6956
 6957            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6958                if provider.show_tab_accept_marker() {
 6959                    EditDisplayMode::TabAccept
 6960                } else {
 6961                    EditDisplayMode::Inline
 6962                }
 6963            } else {
 6964                EditDisplayMode::DiffPopover
 6965            };
 6966
 6967            InlineCompletion::Edit {
 6968                edits,
 6969                edit_preview: inline_completion.edit_preview,
 6970                display_mode,
 6971                snapshot,
 6972            }
 6973        };
 6974
 6975        let invalidation_range = multibuffer
 6976            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6977            ..multibuffer.anchor_after(Point::new(
 6978                invalidation_row_range.end,
 6979                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6980            ));
 6981
 6982        self.stale_inline_completion_in_menu = None;
 6983        self.active_inline_completion = Some(InlineCompletionState {
 6984            inlay_ids,
 6985            completion,
 6986            completion_id: inline_completion.id,
 6987            invalidation_range,
 6988        });
 6989
 6990        cx.notify();
 6991
 6992        Some(())
 6993    }
 6994
 6995    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6996        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6997    }
 6998
 6999    fn clear_tasks(&mut self) {
 7000        self.tasks.clear()
 7001    }
 7002
 7003    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7004        if self.tasks.insert(key, value).is_some() {
 7005            // This case should hopefully be rare, but just in case...
 7006            log::error!(
 7007                "multiple different run targets found on a single line, only the last target will be rendered"
 7008            )
 7009        }
 7010    }
 7011
 7012    /// Get all display points of breakpoints that will be rendered within editor
 7013    ///
 7014    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7015    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7016    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7017    fn active_breakpoints(
 7018        &self,
 7019        range: Range<DisplayRow>,
 7020        window: &mut Window,
 7021        cx: &mut Context<Self>,
 7022    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7023        let mut breakpoint_display_points = HashMap::default();
 7024
 7025        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7026            return breakpoint_display_points;
 7027        };
 7028
 7029        let snapshot = self.snapshot(window, cx);
 7030
 7031        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7032        let Some(project) = self.project.as_ref() else {
 7033            return breakpoint_display_points;
 7034        };
 7035
 7036        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7037            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7038
 7039        for (buffer_snapshot, range, excerpt_id) in
 7040            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7041        {
 7042            let Some(buffer) = project.read_with(cx, |this, cx| {
 7043                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7044            }) else {
 7045                continue;
 7046            };
 7047            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7048                &buffer,
 7049                Some(
 7050                    buffer_snapshot.anchor_before(range.start)
 7051                        ..buffer_snapshot.anchor_after(range.end),
 7052                ),
 7053                buffer_snapshot,
 7054                cx,
 7055            );
 7056            for (breakpoint, state) in breakpoints {
 7057                let multi_buffer_anchor =
 7058                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7059                let position = multi_buffer_anchor
 7060                    .to_point(&multi_buffer_snapshot)
 7061                    .to_display_point(&snapshot);
 7062
 7063                breakpoint_display_points.insert(
 7064                    position.row(),
 7065                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7066                );
 7067            }
 7068        }
 7069
 7070        breakpoint_display_points
 7071    }
 7072
 7073    fn breakpoint_context_menu(
 7074        &self,
 7075        anchor: Anchor,
 7076        window: &mut Window,
 7077        cx: &mut Context<Self>,
 7078    ) -> Entity<ui::ContextMenu> {
 7079        let weak_editor = cx.weak_entity();
 7080        let focus_handle = self.focus_handle(cx);
 7081
 7082        let row = self
 7083            .buffer
 7084            .read(cx)
 7085            .snapshot(cx)
 7086            .summary_for_anchor::<Point>(&anchor)
 7087            .row;
 7088
 7089        let breakpoint = self
 7090            .breakpoint_at_row(row, window, cx)
 7091            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7092
 7093        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7094            "Edit Log Breakpoint"
 7095        } else {
 7096            "Set Log Breakpoint"
 7097        };
 7098
 7099        let condition_breakpoint_msg = if breakpoint
 7100            .as_ref()
 7101            .is_some_and(|bp| bp.1.condition.is_some())
 7102        {
 7103            "Edit Condition Breakpoint"
 7104        } else {
 7105            "Set Condition Breakpoint"
 7106        };
 7107
 7108        let hit_condition_breakpoint_msg = if breakpoint
 7109            .as_ref()
 7110            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7111        {
 7112            "Edit Hit Condition Breakpoint"
 7113        } else {
 7114            "Set Hit Condition Breakpoint"
 7115        };
 7116
 7117        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7118            "Unset Breakpoint"
 7119        } else {
 7120            "Set Breakpoint"
 7121        };
 7122
 7123        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7124            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7125
 7126        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7127            BreakpointState::Enabled => Some("Disable"),
 7128            BreakpointState::Disabled => Some("Enable"),
 7129        });
 7130
 7131        let (anchor, breakpoint) =
 7132            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7133
 7134        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7135            menu.on_blur_subscription(Subscription::new(|| {}))
 7136                .context(focus_handle)
 7137                .when(run_to_cursor, |this| {
 7138                    let weak_editor = weak_editor.clone();
 7139                    this.entry("Run to cursor", None, move |window, cx| {
 7140                        weak_editor
 7141                            .update(cx, |editor, cx| {
 7142                                editor.change_selections(None, window, cx, |s| {
 7143                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7144                                });
 7145                            })
 7146                            .ok();
 7147
 7148                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7149                    })
 7150                    .separator()
 7151                })
 7152                .when_some(toggle_state_msg, |this, msg| {
 7153                    this.entry(msg, None, {
 7154                        let weak_editor = weak_editor.clone();
 7155                        let breakpoint = breakpoint.clone();
 7156                        move |_window, cx| {
 7157                            weak_editor
 7158                                .update(cx, |this, cx| {
 7159                                    this.edit_breakpoint_at_anchor(
 7160                                        anchor,
 7161                                        breakpoint.as_ref().clone(),
 7162                                        BreakpointEditAction::InvertState,
 7163                                        cx,
 7164                                    );
 7165                                })
 7166                                .log_err();
 7167                        }
 7168                    })
 7169                })
 7170                .entry(set_breakpoint_msg, None, {
 7171                    let weak_editor = weak_editor.clone();
 7172                    let breakpoint = breakpoint.clone();
 7173                    move |_window, cx| {
 7174                        weak_editor
 7175                            .update(cx, |this, cx| {
 7176                                this.edit_breakpoint_at_anchor(
 7177                                    anchor,
 7178                                    breakpoint.as_ref().clone(),
 7179                                    BreakpointEditAction::Toggle,
 7180                                    cx,
 7181                                );
 7182                            })
 7183                            .log_err();
 7184                    }
 7185                })
 7186                .entry(log_breakpoint_msg, None, {
 7187                    let breakpoint = breakpoint.clone();
 7188                    let weak_editor = weak_editor.clone();
 7189                    move |window, cx| {
 7190                        weak_editor
 7191                            .update(cx, |this, cx| {
 7192                                this.add_edit_breakpoint_block(
 7193                                    anchor,
 7194                                    breakpoint.as_ref(),
 7195                                    BreakpointPromptEditAction::Log,
 7196                                    window,
 7197                                    cx,
 7198                                );
 7199                            })
 7200                            .log_err();
 7201                    }
 7202                })
 7203                .entry(condition_breakpoint_msg, None, {
 7204                    let breakpoint = breakpoint.clone();
 7205                    let weak_editor = weak_editor.clone();
 7206                    move |window, cx| {
 7207                        weak_editor
 7208                            .update(cx, |this, cx| {
 7209                                this.add_edit_breakpoint_block(
 7210                                    anchor,
 7211                                    breakpoint.as_ref(),
 7212                                    BreakpointPromptEditAction::Condition,
 7213                                    window,
 7214                                    cx,
 7215                                );
 7216                            })
 7217                            .log_err();
 7218                    }
 7219                })
 7220                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7221                    weak_editor
 7222                        .update(cx, |this, cx| {
 7223                            this.add_edit_breakpoint_block(
 7224                                anchor,
 7225                                breakpoint.as_ref(),
 7226                                BreakpointPromptEditAction::HitCondition,
 7227                                window,
 7228                                cx,
 7229                            );
 7230                        })
 7231                        .log_err();
 7232                })
 7233        })
 7234    }
 7235
 7236    fn render_breakpoint(
 7237        &self,
 7238        position: Anchor,
 7239        row: DisplayRow,
 7240        breakpoint: &Breakpoint,
 7241        state: Option<BreakpointSessionState>,
 7242        cx: &mut Context<Self>,
 7243    ) -> IconButton {
 7244        let is_rejected = state.is_some_and(|s| !s.verified);
 7245        // Is it a breakpoint that shows up when hovering over gutter?
 7246        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7247            (false, false),
 7248            |PhantomBreakpointIndicator {
 7249                 is_active,
 7250                 display_row,
 7251                 collides_with_existing_breakpoint,
 7252             }| {
 7253                (
 7254                    is_active && display_row == row,
 7255                    collides_with_existing_breakpoint,
 7256                )
 7257            },
 7258        );
 7259
 7260        let (color, icon) = {
 7261            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7262                (false, false) => ui::IconName::DebugBreakpoint,
 7263                (true, false) => ui::IconName::DebugLogBreakpoint,
 7264                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7265                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7266            };
 7267
 7268            let color = if is_phantom {
 7269                Color::Hint
 7270            } else if is_rejected {
 7271                Color::Disabled
 7272            } else {
 7273                Color::Debugger
 7274            };
 7275
 7276            (color, icon)
 7277        };
 7278
 7279        let breakpoint = Arc::from(breakpoint.clone());
 7280
 7281        let alt_as_text = gpui::Keystroke {
 7282            modifiers: Modifiers::secondary_key(),
 7283            ..Default::default()
 7284        };
 7285        let primary_action_text = if breakpoint.is_disabled() {
 7286            "Enable breakpoint"
 7287        } else if is_phantom && !collides_with_existing {
 7288            "Set breakpoint"
 7289        } else {
 7290            "Unset breakpoint"
 7291        };
 7292        let focus_handle = self.focus_handle.clone();
 7293
 7294        let meta = if is_rejected {
 7295            SharedString::from("No executable code is associated with this line.")
 7296        } else if collides_with_existing && !breakpoint.is_disabled() {
 7297            SharedString::from(format!(
 7298                "{alt_as_text}-click to disable,\nright-click for more options."
 7299            ))
 7300        } else {
 7301            SharedString::from("Right-click for more options.")
 7302        };
 7303        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7304            .icon_size(IconSize::XSmall)
 7305            .size(ui::ButtonSize::None)
 7306            .when(is_rejected, |this| {
 7307                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7308            })
 7309            .icon_color(color)
 7310            .style(ButtonStyle::Transparent)
 7311            .on_click(cx.listener({
 7312                let breakpoint = breakpoint.clone();
 7313
 7314                move |editor, event: &ClickEvent, window, cx| {
 7315                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7316                        BreakpointEditAction::InvertState
 7317                    } else {
 7318                        BreakpointEditAction::Toggle
 7319                    };
 7320
 7321                    window.focus(&editor.focus_handle(cx));
 7322                    editor.edit_breakpoint_at_anchor(
 7323                        position,
 7324                        breakpoint.as_ref().clone(),
 7325                        edit_action,
 7326                        cx,
 7327                    );
 7328                }
 7329            }))
 7330            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7331                editor.set_breakpoint_context_menu(
 7332                    row,
 7333                    Some(position),
 7334                    event.down.position,
 7335                    window,
 7336                    cx,
 7337                );
 7338            }))
 7339            .tooltip(move |window, cx| {
 7340                Tooltip::with_meta_in(
 7341                    primary_action_text,
 7342                    Some(&ToggleBreakpoint),
 7343                    meta.clone(),
 7344                    &focus_handle,
 7345                    window,
 7346                    cx,
 7347                )
 7348            })
 7349    }
 7350
 7351    fn build_tasks_context(
 7352        project: &Entity<Project>,
 7353        buffer: &Entity<Buffer>,
 7354        buffer_row: u32,
 7355        tasks: &Arc<RunnableTasks>,
 7356        cx: &mut Context<Self>,
 7357    ) -> Task<Option<task::TaskContext>> {
 7358        let position = Point::new(buffer_row, tasks.column);
 7359        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7360        let location = Location {
 7361            buffer: buffer.clone(),
 7362            range: range_start..range_start,
 7363        };
 7364        // Fill in the environmental variables from the tree-sitter captures
 7365        let mut captured_task_variables = TaskVariables::default();
 7366        for (capture_name, value) in tasks.extra_variables.clone() {
 7367            captured_task_variables.insert(
 7368                task::VariableName::Custom(capture_name.into()),
 7369                value.clone(),
 7370            );
 7371        }
 7372        project.update(cx, |project, cx| {
 7373            project.task_store().update(cx, |task_store, cx| {
 7374                task_store.task_context_for_location(captured_task_variables, location, cx)
 7375            })
 7376        })
 7377    }
 7378
 7379    pub fn spawn_nearest_task(
 7380        &mut self,
 7381        action: &SpawnNearestTask,
 7382        window: &mut Window,
 7383        cx: &mut Context<Self>,
 7384    ) {
 7385        let Some((workspace, _)) = self.workspace.clone() else {
 7386            return;
 7387        };
 7388        let Some(project) = self.project.clone() else {
 7389            return;
 7390        };
 7391
 7392        // Try to find a closest, enclosing node using tree-sitter that has a
 7393        // task
 7394        let Some((buffer, buffer_row, tasks)) = self
 7395            .find_enclosing_node_task(cx)
 7396            // Or find the task that's closest in row-distance.
 7397            .or_else(|| self.find_closest_task(cx))
 7398        else {
 7399            return;
 7400        };
 7401
 7402        let reveal_strategy = action.reveal;
 7403        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7404        cx.spawn_in(window, async move |_, cx| {
 7405            let context = task_context.await?;
 7406            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7407
 7408            let resolved = &mut resolved_task.resolved;
 7409            resolved.reveal = reveal_strategy;
 7410
 7411            workspace
 7412                .update_in(cx, |workspace, window, cx| {
 7413                    workspace.schedule_resolved_task(
 7414                        task_source_kind,
 7415                        resolved_task,
 7416                        false,
 7417                        window,
 7418                        cx,
 7419                    );
 7420                })
 7421                .ok()
 7422        })
 7423        .detach();
 7424    }
 7425
 7426    fn find_closest_task(
 7427        &mut self,
 7428        cx: &mut Context<Self>,
 7429    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7430        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7431
 7432        let ((buffer_id, row), tasks) = self
 7433            .tasks
 7434            .iter()
 7435            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7436
 7437        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7438        let tasks = Arc::new(tasks.to_owned());
 7439        Some((buffer, *row, tasks))
 7440    }
 7441
 7442    fn find_enclosing_node_task(
 7443        &mut self,
 7444        cx: &mut Context<Self>,
 7445    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7446        let snapshot = self.buffer.read(cx).snapshot(cx);
 7447        let offset = self.selections.newest::<usize>(cx).head();
 7448        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7449        let buffer_id = excerpt.buffer().remote_id();
 7450
 7451        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7452        let mut cursor = layer.node().walk();
 7453
 7454        while cursor.goto_first_child_for_byte(offset).is_some() {
 7455            if cursor.node().end_byte() == offset {
 7456                cursor.goto_next_sibling();
 7457            }
 7458        }
 7459
 7460        // Ascend to the smallest ancestor that contains the range and has a task.
 7461        loop {
 7462            let node = cursor.node();
 7463            let node_range = node.byte_range();
 7464            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7465
 7466            // Check if this node contains our offset
 7467            if node_range.start <= offset && node_range.end >= offset {
 7468                // If it contains offset, check for task
 7469                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7470                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7471                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7472                }
 7473            }
 7474
 7475            if !cursor.goto_parent() {
 7476                break;
 7477            }
 7478        }
 7479        None
 7480    }
 7481
 7482    fn render_run_indicator(
 7483        &self,
 7484        _style: &EditorStyle,
 7485        is_active: bool,
 7486        row: DisplayRow,
 7487        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7488        cx: &mut Context<Self>,
 7489    ) -> IconButton {
 7490        let color = Color::Muted;
 7491        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7492
 7493        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7494            .shape(ui::IconButtonShape::Square)
 7495            .icon_size(IconSize::XSmall)
 7496            .icon_color(color)
 7497            .toggle_state(is_active)
 7498            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7499                let quick_launch = e.down.button == MouseButton::Left;
 7500                window.focus(&editor.focus_handle(cx));
 7501                editor.toggle_code_actions(
 7502                    &ToggleCodeActions {
 7503                        deployed_from_indicator: Some(row),
 7504                        quick_launch,
 7505                    },
 7506                    window,
 7507                    cx,
 7508                );
 7509            }))
 7510            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7511                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7512            }))
 7513    }
 7514
 7515    pub fn context_menu_visible(&self) -> bool {
 7516        !self.edit_prediction_preview_is_active()
 7517            && self
 7518                .context_menu
 7519                .borrow()
 7520                .as_ref()
 7521                .map_or(false, |menu| menu.visible())
 7522    }
 7523
 7524    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7525        self.context_menu
 7526            .borrow()
 7527            .as_ref()
 7528            .map(|menu| menu.origin())
 7529    }
 7530
 7531    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7532        self.context_menu_options = Some(options);
 7533    }
 7534
 7535    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7536    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7537
 7538    fn render_edit_prediction_popover(
 7539        &mut self,
 7540        text_bounds: &Bounds<Pixels>,
 7541        content_origin: gpui::Point<Pixels>,
 7542        right_margin: Pixels,
 7543        editor_snapshot: &EditorSnapshot,
 7544        visible_row_range: Range<DisplayRow>,
 7545        scroll_top: f32,
 7546        scroll_bottom: f32,
 7547        line_layouts: &[LineWithInvisibles],
 7548        line_height: Pixels,
 7549        scroll_pixel_position: gpui::Point<Pixels>,
 7550        newest_selection_head: Option<DisplayPoint>,
 7551        editor_width: Pixels,
 7552        style: &EditorStyle,
 7553        window: &mut Window,
 7554        cx: &mut App,
 7555    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7556        if self.mode().is_minimap() {
 7557            return None;
 7558        }
 7559        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7560
 7561        if self.edit_prediction_visible_in_cursor_popover(true) {
 7562            return None;
 7563        }
 7564
 7565        match &active_inline_completion.completion {
 7566            InlineCompletion::Move { target, .. } => {
 7567                let target_display_point = target.to_display_point(editor_snapshot);
 7568
 7569                if self.edit_prediction_requires_modifier() {
 7570                    if !self.edit_prediction_preview_is_active() {
 7571                        return None;
 7572                    }
 7573
 7574                    self.render_edit_prediction_modifier_jump_popover(
 7575                        text_bounds,
 7576                        content_origin,
 7577                        visible_row_range,
 7578                        line_layouts,
 7579                        line_height,
 7580                        scroll_pixel_position,
 7581                        newest_selection_head,
 7582                        target_display_point,
 7583                        window,
 7584                        cx,
 7585                    )
 7586                } else {
 7587                    self.render_edit_prediction_eager_jump_popover(
 7588                        text_bounds,
 7589                        content_origin,
 7590                        editor_snapshot,
 7591                        visible_row_range,
 7592                        scroll_top,
 7593                        scroll_bottom,
 7594                        line_height,
 7595                        scroll_pixel_position,
 7596                        target_display_point,
 7597                        editor_width,
 7598                        window,
 7599                        cx,
 7600                    )
 7601                }
 7602            }
 7603            InlineCompletion::Edit {
 7604                display_mode: EditDisplayMode::Inline,
 7605                ..
 7606            } => None,
 7607            InlineCompletion::Edit {
 7608                display_mode: EditDisplayMode::TabAccept,
 7609                edits,
 7610                ..
 7611            } => {
 7612                let range = &edits.first()?.0;
 7613                let target_display_point = range.end.to_display_point(editor_snapshot);
 7614
 7615                self.render_edit_prediction_end_of_line_popover(
 7616                    "Accept",
 7617                    editor_snapshot,
 7618                    visible_row_range,
 7619                    target_display_point,
 7620                    line_height,
 7621                    scroll_pixel_position,
 7622                    content_origin,
 7623                    editor_width,
 7624                    window,
 7625                    cx,
 7626                )
 7627            }
 7628            InlineCompletion::Edit {
 7629                edits,
 7630                edit_preview,
 7631                display_mode: EditDisplayMode::DiffPopover,
 7632                snapshot,
 7633            } => self.render_edit_prediction_diff_popover(
 7634                text_bounds,
 7635                content_origin,
 7636                right_margin,
 7637                editor_snapshot,
 7638                visible_row_range,
 7639                line_layouts,
 7640                line_height,
 7641                scroll_pixel_position,
 7642                newest_selection_head,
 7643                editor_width,
 7644                style,
 7645                edits,
 7646                edit_preview,
 7647                snapshot,
 7648                window,
 7649                cx,
 7650            ),
 7651        }
 7652    }
 7653
 7654    fn render_edit_prediction_modifier_jump_popover(
 7655        &mut self,
 7656        text_bounds: &Bounds<Pixels>,
 7657        content_origin: gpui::Point<Pixels>,
 7658        visible_row_range: Range<DisplayRow>,
 7659        line_layouts: &[LineWithInvisibles],
 7660        line_height: Pixels,
 7661        scroll_pixel_position: gpui::Point<Pixels>,
 7662        newest_selection_head: Option<DisplayPoint>,
 7663        target_display_point: DisplayPoint,
 7664        window: &mut Window,
 7665        cx: &mut App,
 7666    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7667        let scrolled_content_origin =
 7668            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7669
 7670        const SCROLL_PADDING_Y: Pixels = px(12.);
 7671
 7672        if target_display_point.row() < visible_row_range.start {
 7673            return self.render_edit_prediction_scroll_popover(
 7674                |_| SCROLL_PADDING_Y,
 7675                IconName::ArrowUp,
 7676                visible_row_range,
 7677                line_layouts,
 7678                newest_selection_head,
 7679                scrolled_content_origin,
 7680                window,
 7681                cx,
 7682            );
 7683        } else if target_display_point.row() >= visible_row_range.end {
 7684            return self.render_edit_prediction_scroll_popover(
 7685                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7686                IconName::ArrowDown,
 7687                visible_row_range,
 7688                line_layouts,
 7689                newest_selection_head,
 7690                scrolled_content_origin,
 7691                window,
 7692                cx,
 7693            );
 7694        }
 7695
 7696        const POLE_WIDTH: Pixels = px(2.);
 7697
 7698        let line_layout =
 7699            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7700        let target_column = target_display_point.column() as usize;
 7701
 7702        let target_x = line_layout.x_for_index(target_column);
 7703        let target_y =
 7704            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7705
 7706        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7707
 7708        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7709        border_color.l += 0.001;
 7710
 7711        let mut element = v_flex()
 7712            .items_end()
 7713            .when(flag_on_right, |el| el.items_start())
 7714            .child(if flag_on_right {
 7715                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7716                    .rounded_bl(px(0.))
 7717                    .rounded_tl(px(0.))
 7718                    .border_l_2()
 7719                    .border_color(border_color)
 7720            } else {
 7721                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7722                    .rounded_br(px(0.))
 7723                    .rounded_tr(px(0.))
 7724                    .border_r_2()
 7725                    .border_color(border_color)
 7726            })
 7727            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7728            .into_any();
 7729
 7730        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7731
 7732        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7733            - point(
 7734                if flag_on_right {
 7735                    POLE_WIDTH
 7736                } else {
 7737                    size.width - POLE_WIDTH
 7738                },
 7739                size.height - line_height,
 7740            );
 7741
 7742        origin.x = origin.x.max(content_origin.x);
 7743
 7744        element.prepaint_at(origin, window, cx);
 7745
 7746        Some((element, origin))
 7747    }
 7748
 7749    fn render_edit_prediction_scroll_popover(
 7750        &mut self,
 7751        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7752        scroll_icon: IconName,
 7753        visible_row_range: Range<DisplayRow>,
 7754        line_layouts: &[LineWithInvisibles],
 7755        newest_selection_head: Option<DisplayPoint>,
 7756        scrolled_content_origin: gpui::Point<Pixels>,
 7757        window: &mut Window,
 7758        cx: &mut App,
 7759    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7760        let mut element = self
 7761            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7762            .into_any();
 7763
 7764        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7765
 7766        let cursor = newest_selection_head?;
 7767        let cursor_row_layout =
 7768            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7769        let cursor_column = cursor.column() as usize;
 7770
 7771        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7772
 7773        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7774
 7775        element.prepaint_at(origin, window, cx);
 7776        Some((element, origin))
 7777    }
 7778
 7779    fn render_edit_prediction_eager_jump_popover(
 7780        &mut self,
 7781        text_bounds: &Bounds<Pixels>,
 7782        content_origin: gpui::Point<Pixels>,
 7783        editor_snapshot: &EditorSnapshot,
 7784        visible_row_range: Range<DisplayRow>,
 7785        scroll_top: f32,
 7786        scroll_bottom: f32,
 7787        line_height: Pixels,
 7788        scroll_pixel_position: gpui::Point<Pixels>,
 7789        target_display_point: DisplayPoint,
 7790        editor_width: Pixels,
 7791        window: &mut Window,
 7792        cx: &mut App,
 7793    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7794        if target_display_point.row().as_f32() < scroll_top {
 7795            let mut element = self
 7796                .render_edit_prediction_line_popover(
 7797                    "Jump to Edit",
 7798                    Some(IconName::ArrowUp),
 7799                    window,
 7800                    cx,
 7801                )?
 7802                .into_any();
 7803
 7804            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7805            let offset = point(
 7806                (text_bounds.size.width - size.width) / 2.,
 7807                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7808            );
 7809
 7810            let origin = text_bounds.origin + offset;
 7811            element.prepaint_at(origin, window, cx);
 7812            Some((element, origin))
 7813        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7814            let mut element = self
 7815                .render_edit_prediction_line_popover(
 7816                    "Jump to Edit",
 7817                    Some(IconName::ArrowDown),
 7818                    window,
 7819                    cx,
 7820                )?
 7821                .into_any();
 7822
 7823            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7824            let offset = point(
 7825                (text_bounds.size.width - size.width) / 2.,
 7826                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7827            );
 7828
 7829            let origin = text_bounds.origin + offset;
 7830            element.prepaint_at(origin, window, cx);
 7831            Some((element, origin))
 7832        } else {
 7833            self.render_edit_prediction_end_of_line_popover(
 7834                "Jump to Edit",
 7835                editor_snapshot,
 7836                visible_row_range,
 7837                target_display_point,
 7838                line_height,
 7839                scroll_pixel_position,
 7840                content_origin,
 7841                editor_width,
 7842                window,
 7843                cx,
 7844            )
 7845        }
 7846    }
 7847
 7848    fn render_edit_prediction_end_of_line_popover(
 7849        self: &mut Editor,
 7850        label: &'static str,
 7851        editor_snapshot: &EditorSnapshot,
 7852        visible_row_range: Range<DisplayRow>,
 7853        target_display_point: DisplayPoint,
 7854        line_height: Pixels,
 7855        scroll_pixel_position: gpui::Point<Pixels>,
 7856        content_origin: gpui::Point<Pixels>,
 7857        editor_width: Pixels,
 7858        window: &mut Window,
 7859        cx: &mut App,
 7860    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7861        let target_line_end = DisplayPoint::new(
 7862            target_display_point.row(),
 7863            editor_snapshot.line_len(target_display_point.row()),
 7864        );
 7865
 7866        let mut element = self
 7867            .render_edit_prediction_line_popover(label, None, window, cx)?
 7868            .into_any();
 7869
 7870        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7871
 7872        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7873
 7874        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7875        let mut origin = start_point
 7876            + line_origin
 7877            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7878        origin.x = origin.x.max(content_origin.x);
 7879
 7880        let max_x = content_origin.x + editor_width - size.width;
 7881
 7882        if origin.x > max_x {
 7883            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7884
 7885            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7886                origin.y += offset;
 7887                IconName::ArrowUp
 7888            } else {
 7889                origin.y -= offset;
 7890                IconName::ArrowDown
 7891            };
 7892
 7893            element = self
 7894                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7895                .into_any();
 7896
 7897            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7898
 7899            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7900        }
 7901
 7902        element.prepaint_at(origin, window, cx);
 7903        Some((element, origin))
 7904    }
 7905
 7906    fn render_edit_prediction_diff_popover(
 7907        self: &Editor,
 7908        text_bounds: &Bounds<Pixels>,
 7909        content_origin: gpui::Point<Pixels>,
 7910        right_margin: Pixels,
 7911        editor_snapshot: &EditorSnapshot,
 7912        visible_row_range: Range<DisplayRow>,
 7913        line_layouts: &[LineWithInvisibles],
 7914        line_height: Pixels,
 7915        scroll_pixel_position: gpui::Point<Pixels>,
 7916        newest_selection_head: Option<DisplayPoint>,
 7917        editor_width: Pixels,
 7918        style: &EditorStyle,
 7919        edits: &Vec<(Range<Anchor>, String)>,
 7920        edit_preview: &Option<language::EditPreview>,
 7921        snapshot: &language::BufferSnapshot,
 7922        window: &mut Window,
 7923        cx: &mut App,
 7924    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7925        let edit_start = edits
 7926            .first()
 7927            .unwrap()
 7928            .0
 7929            .start
 7930            .to_display_point(editor_snapshot);
 7931        let edit_end = edits
 7932            .last()
 7933            .unwrap()
 7934            .0
 7935            .end
 7936            .to_display_point(editor_snapshot);
 7937
 7938        let is_visible = visible_row_range.contains(&edit_start.row())
 7939            || visible_row_range.contains(&edit_end.row());
 7940        if !is_visible {
 7941            return None;
 7942        }
 7943
 7944        let highlighted_edits =
 7945            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7946
 7947        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7948        let line_count = highlighted_edits.text.lines().count();
 7949
 7950        const BORDER_WIDTH: Pixels = px(1.);
 7951
 7952        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7953        let has_keybind = keybind.is_some();
 7954
 7955        let mut element = h_flex()
 7956            .items_start()
 7957            .child(
 7958                h_flex()
 7959                    .bg(cx.theme().colors().editor_background)
 7960                    .border(BORDER_WIDTH)
 7961                    .shadow_sm()
 7962                    .border_color(cx.theme().colors().border)
 7963                    .rounded_l_lg()
 7964                    .when(line_count > 1, |el| el.rounded_br_lg())
 7965                    .pr_1()
 7966                    .child(styled_text),
 7967            )
 7968            .child(
 7969                h_flex()
 7970                    .h(line_height + BORDER_WIDTH * 2.)
 7971                    .px_1p5()
 7972                    .gap_1()
 7973                    // Workaround: For some reason, there's a gap if we don't do this
 7974                    .ml(-BORDER_WIDTH)
 7975                    .shadow(smallvec![gpui::BoxShadow {
 7976                        color: gpui::black().opacity(0.05),
 7977                        offset: point(px(1.), px(1.)),
 7978                        blur_radius: px(2.),
 7979                        spread_radius: px(0.),
 7980                    }])
 7981                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7982                    .border(BORDER_WIDTH)
 7983                    .border_color(cx.theme().colors().border)
 7984                    .rounded_r_lg()
 7985                    .id("edit_prediction_diff_popover_keybind")
 7986                    .when(!has_keybind, |el| {
 7987                        let status_colors = cx.theme().status();
 7988
 7989                        el.bg(status_colors.error_background)
 7990                            .border_color(status_colors.error.opacity(0.6))
 7991                            .child(Icon::new(IconName::Info).color(Color::Error))
 7992                            .cursor_default()
 7993                            .hoverable_tooltip(move |_window, cx| {
 7994                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7995                            })
 7996                    })
 7997                    .children(keybind),
 7998            )
 7999            .into_any();
 8000
 8001        let longest_row =
 8002            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8003        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8004            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8005        } else {
 8006            layout_line(
 8007                longest_row,
 8008                editor_snapshot,
 8009                style,
 8010                editor_width,
 8011                |_| false,
 8012                window,
 8013                cx,
 8014            )
 8015            .width
 8016        };
 8017
 8018        let viewport_bounds =
 8019            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8020                right: -right_margin,
 8021                ..Default::default()
 8022            });
 8023
 8024        let x_after_longest =
 8025            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8026                - scroll_pixel_position.x;
 8027
 8028        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8029
 8030        // Fully visible if it can be displayed within the window (allow overlapping other
 8031        // panes). However, this is only allowed if the popover starts within text_bounds.
 8032        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8033            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8034
 8035        let mut origin = if can_position_to_the_right {
 8036            point(
 8037                x_after_longest,
 8038                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8039                    - scroll_pixel_position.y,
 8040            )
 8041        } else {
 8042            let cursor_row = newest_selection_head.map(|head| head.row());
 8043            let above_edit = edit_start
 8044                .row()
 8045                .0
 8046                .checked_sub(line_count as u32)
 8047                .map(DisplayRow);
 8048            let below_edit = Some(edit_end.row() + 1);
 8049            let above_cursor =
 8050                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8051            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8052
 8053            // Place the edit popover adjacent to the edit if there is a location
 8054            // available that is onscreen and does not obscure the cursor. Otherwise,
 8055            // place it adjacent to the cursor.
 8056            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8057                .into_iter()
 8058                .flatten()
 8059                .find(|&start_row| {
 8060                    let end_row = start_row + line_count as u32;
 8061                    visible_row_range.contains(&start_row)
 8062                        && visible_row_range.contains(&end_row)
 8063                        && cursor_row.map_or(true, |cursor_row| {
 8064                            !((start_row..end_row).contains(&cursor_row))
 8065                        })
 8066                })?;
 8067
 8068            content_origin
 8069                + point(
 8070                    -scroll_pixel_position.x,
 8071                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8072                )
 8073        };
 8074
 8075        origin.x -= BORDER_WIDTH;
 8076
 8077        window.defer_draw(element, origin, 1);
 8078
 8079        // Do not return an element, since it will already be drawn due to defer_draw.
 8080        None
 8081    }
 8082
 8083    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8084        px(30.)
 8085    }
 8086
 8087    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8088        if self.read_only(cx) {
 8089            cx.theme().players().read_only()
 8090        } else {
 8091            self.style.as_ref().unwrap().local_player
 8092        }
 8093    }
 8094
 8095    fn render_edit_prediction_accept_keybind(
 8096        &self,
 8097        window: &mut Window,
 8098        cx: &App,
 8099    ) -> Option<AnyElement> {
 8100        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8101        let accept_keystroke = accept_binding.keystroke()?;
 8102
 8103        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8104
 8105        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8106            Color::Accent
 8107        } else {
 8108            Color::Muted
 8109        };
 8110
 8111        h_flex()
 8112            .px_0p5()
 8113            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8114            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8115            .text_size(TextSize::XSmall.rems(cx))
 8116            .child(h_flex().children(ui::render_modifiers(
 8117                &accept_keystroke.modifiers,
 8118                PlatformStyle::platform(),
 8119                Some(modifiers_color),
 8120                Some(IconSize::XSmall.rems().into()),
 8121                true,
 8122            )))
 8123            .when(is_platform_style_mac, |parent| {
 8124                parent.child(accept_keystroke.key.clone())
 8125            })
 8126            .when(!is_platform_style_mac, |parent| {
 8127                parent.child(
 8128                    Key::new(
 8129                        util::capitalize(&accept_keystroke.key),
 8130                        Some(Color::Default),
 8131                    )
 8132                    .size(Some(IconSize::XSmall.rems().into())),
 8133                )
 8134            })
 8135            .into_any()
 8136            .into()
 8137    }
 8138
 8139    fn render_edit_prediction_line_popover(
 8140        &self,
 8141        label: impl Into<SharedString>,
 8142        icon: Option<IconName>,
 8143        window: &mut Window,
 8144        cx: &App,
 8145    ) -> Option<Stateful<Div>> {
 8146        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8147
 8148        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8149        let has_keybind = keybind.is_some();
 8150
 8151        let result = h_flex()
 8152            .id("ep-line-popover")
 8153            .py_0p5()
 8154            .pl_1()
 8155            .pr(padding_right)
 8156            .gap_1()
 8157            .rounded_md()
 8158            .border_1()
 8159            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8160            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8161            .shadow_sm()
 8162            .when(!has_keybind, |el| {
 8163                let status_colors = cx.theme().status();
 8164
 8165                el.bg(status_colors.error_background)
 8166                    .border_color(status_colors.error.opacity(0.6))
 8167                    .pl_2()
 8168                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8169                    .cursor_default()
 8170                    .hoverable_tooltip(move |_window, cx| {
 8171                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8172                    })
 8173            })
 8174            .children(keybind)
 8175            .child(
 8176                Label::new(label)
 8177                    .size(LabelSize::Small)
 8178                    .when(!has_keybind, |el| {
 8179                        el.color(cx.theme().status().error.into()).strikethrough()
 8180                    }),
 8181            )
 8182            .when(!has_keybind, |el| {
 8183                el.child(
 8184                    h_flex().ml_1().child(
 8185                        Icon::new(IconName::Info)
 8186                            .size(IconSize::Small)
 8187                            .color(cx.theme().status().error.into()),
 8188                    ),
 8189                )
 8190            })
 8191            .when_some(icon, |element, icon| {
 8192                element.child(
 8193                    div()
 8194                        .mt(px(1.5))
 8195                        .child(Icon::new(icon).size(IconSize::Small)),
 8196                )
 8197            });
 8198
 8199        Some(result)
 8200    }
 8201
 8202    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8203        let accent_color = cx.theme().colors().text_accent;
 8204        let editor_bg_color = cx.theme().colors().editor_background;
 8205        editor_bg_color.blend(accent_color.opacity(0.1))
 8206    }
 8207
 8208    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8209        let accent_color = cx.theme().colors().text_accent;
 8210        let editor_bg_color = cx.theme().colors().editor_background;
 8211        editor_bg_color.blend(accent_color.opacity(0.6))
 8212    }
 8213
 8214    fn render_edit_prediction_cursor_popover(
 8215        &self,
 8216        min_width: Pixels,
 8217        max_width: Pixels,
 8218        cursor_point: Point,
 8219        style: &EditorStyle,
 8220        accept_keystroke: Option<&gpui::Keystroke>,
 8221        _window: &Window,
 8222        cx: &mut Context<Editor>,
 8223    ) -> Option<AnyElement> {
 8224        let provider = self.edit_prediction_provider.as_ref()?;
 8225
 8226        if provider.provider.needs_terms_acceptance(cx) {
 8227            return Some(
 8228                h_flex()
 8229                    .min_w(min_width)
 8230                    .flex_1()
 8231                    .px_2()
 8232                    .py_1()
 8233                    .gap_3()
 8234                    .elevation_2(cx)
 8235                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8236                    .id("accept-terms")
 8237                    .cursor_pointer()
 8238                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8239                    .on_click(cx.listener(|this, _event, window, cx| {
 8240                        cx.stop_propagation();
 8241                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8242                        window.dispatch_action(
 8243                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8244                            cx,
 8245                        );
 8246                    }))
 8247                    .child(
 8248                        h_flex()
 8249                            .flex_1()
 8250                            .gap_2()
 8251                            .child(Icon::new(IconName::ZedPredict))
 8252                            .child(Label::new("Accept Terms of Service"))
 8253                            .child(div().w_full())
 8254                            .child(
 8255                                Icon::new(IconName::ArrowUpRight)
 8256                                    .color(Color::Muted)
 8257                                    .size(IconSize::Small),
 8258                            )
 8259                            .into_any_element(),
 8260                    )
 8261                    .into_any(),
 8262            );
 8263        }
 8264
 8265        let is_refreshing = provider.provider.is_refreshing(cx);
 8266
 8267        fn pending_completion_container() -> Div {
 8268            h_flex()
 8269                .h_full()
 8270                .flex_1()
 8271                .gap_2()
 8272                .child(Icon::new(IconName::ZedPredict))
 8273        }
 8274
 8275        let completion = match &self.active_inline_completion {
 8276            Some(prediction) => {
 8277                if !self.has_visible_completions_menu() {
 8278                    const RADIUS: Pixels = px(6.);
 8279                    const BORDER_WIDTH: Pixels = px(1.);
 8280
 8281                    return Some(
 8282                        h_flex()
 8283                            .elevation_2(cx)
 8284                            .border(BORDER_WIDTH)
 8285                            .border_color(cx.theme().colors().border)
 8286                            .when(accept_keystroke.is_none(), |el| {
 8287                                el.border_color(cx.theme().status().error)
 8288                            })
 8289                            .rounded(RADIUS)
 8290                            .rounded_tl(px(0.))
 8291                            .overflow_hidden()
 8292                            .child(div().px_1p5().child(match &prediction.completion {
 8293                                InlineCompletion::Move { target, snapshot } => {
 8294                                    use text::ToPoint as _;
 8295                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8296                                    {
 8297                                        Icon::new(IconName::ZedPredictDown)
 8298                                    } else {
 8299                                        Icon::new(IconName::ZedPredictUp)
 8300                                    }
 8301                                }
 8302                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8303                            }))
 8304                            .child(
 8305                                h_flex()
 8306                                    .gap_1()
 8307                                    .py_1()
 8308                                    .px_2()
 8309                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8310                                    .border_l_1()
 8311                                    .border_color(cx.theme().colors().border)
 8312                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8313                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8314                                        el.child(
 8315                                            Label::new("Hold")
 8316                                                .size(LabelSize::Small)
 8317                                                .when(accept_keystroke.is_none(), |el| {
 8318                                                    el.strikethrough()
 8319                                                })
 8320                                                .line_height_style(LineHeightStyle::UiLabel),
 8321                                        )
 8322                                    })
 8323                                    .id("edit_prediction_cursor_popover_keybind")
 8324                                    .when(accept_keystroke.is_none(), |el| {
 8325                                        let status_colors = cx.theme().status();
 8326
 8327                                        el.bg(status_colors.error_background)
 8328                                            .border_color(status_colors.error.opacity(0.6))
 8329                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8330                                            .cursor_default()
 8331                                            .hoverable_tooltip(move |_window, cx| {
 8332                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8333                                                    .into()
 8334                                            })
 8335                                    })
 8336                                    .when_some(
 8337                                        accept_keystroke.as_ref(),
 8338                                        |el, accept_keystroke| {
 8339                                            el.child(h_flex().children(ui::render_modifiers(
 8340                                                &accept_keystroke.modifiers,
 8341                                                PlatformStyle::platform(),
 8342                                                Some(Color::Default),
 8343                                                Some(IconSize::XSmall.rems().into()),
 8344                                                false,
 8345                                            )))
 8346                                        },
 8347                                    ),
 8348                            )
 8349                            .into_any(),
 8350                    );
 8351                }
 8352
 8353                self.render_edit_prediction_cursor_popover_preview(
 8354                    prediction,
 8355                    cursor_point,
 8356                    style,
 8357                    cx,
 8358                )?
 8359            }
 8360
 8361            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8362                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8363                    stale_completion,
 8364                    cursor_point,
 8365                    style,
 8366                    cx,
 8367                )?,
 8368
 8369                None => {
 8370                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8371                }
 8372            },
 8373
 8374            None => pending_completion_container().child(Label::new("No Prediction")),
 8375        };
 8376
 8377        let completion = if is_refreshing {
 8378            completion
 8379                .with_animation(
 8380                    "loading-completion",
 8381                    Animation::new(Duration::from_secs(2))
 8382                        .repeat()
 8383                        .with_easing(pulsating_between(0.4, 0.8)),
 8384                    |label, delta| label.opacity(delta),
 8385                )
 8386                .into_any_element()
 8387        } else {
 8388            completion.into_any_element()
 8389        };
 8390
 8391        let has_completion = self.active_inline_completion.is_some();
 8392
 8393        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8394        Some(
 8395            h_flex()
 8396                .min_w(min_width)
 8397                .max_w(max_width)
 8398                .flex_1()
 8399                .elevation_2(cx)
 8400                .border_color(cx.theme().colors().border)
 8401                .child(
 8402                    div()
 8403                        .flex_1()
 8404                        .py_1()
 8405                        .px_2()
 8406                        .overflow_hidden()
 8407                        .child(completion),
 8408                )
 8409                .when_some(accept_keystroke, |el, accept_keystroke| {
 8410                    if !accept_keystroke.modifiers.modified() {
 8411                        return el;
 8412                    }
 8413
 8414                    el.child(
 8415                        h_flex()
 8416                            .h_full()
 8417                            .border_l_1()
 8418                            .rounded_r_lg()
 8419                            .border_color(cx.theme().colors().border)
 8420                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8421                            .gap_1()
 8422                            .py_1()
 8423                            .px_2()
 8424                            .child(
 8425                                h_flex()
 8426                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8427                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8428                                    .child(h_flex().children(ui::render_modifiers(
 8429                                        &accept_keystroke.modifiers,
 8430                                        PlatformStyle::platform(),
 8431                                        Some(if !has_completion {
 8432                                            Color::Muted
 8433                                        } else {
 8434                                            Color::Default
 8435                                        }),
 8436                                        None,
 8437                                        false,
 8438                                    ))),
 8439                            )
 8440                            .child(Label::new("Preview").into_any_element())
 8441                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8442                    )
 8443                })
 8444                .into_any(),
 8445        )
 8446    }
 8447
 8448    fn render_edit_prediction_cursor_popover_preview(
 8449        &self,
 8450        completion: &InlineCompletionState,
 8451        cursor_point: Point,
 8452        style: &EditorStyle,
 8453        cx: &mut Context<Editor>,
 8454    ) -> Option<Div> {
 8455        use text::ToPoint as _;
 8456
 8457        fn render_relative_row_jump(
 8458            prefix: impl Into<String>,
 8459            current_row: u32,
 8460            target_row: u32,
 8461        ) -> Div {
 8462            let (row_diff, arrow) = if target_row < current_row {
 8463                (current_row - target_row, IconName::ArrowUp)
 8464            } else {
 8465                (target_row - current_row, IconName::ArrowDown)
 8466            };
 8467
 8468            h_flex()
 8469                .child(
 8470                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8471                        .color(Color::Muted)
 8472                        .size(LabelSize::Small),
 8473                )
 8474                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8475        }
 8476
 8477        match &completion.completion {
 8478            InlineCompletion::Move {
 8479                target, snapshot, ..
 8480            } => Some(
 8481                h_flex()
 8482                    .px_2()
 8483                    .gap_2()
 8484                    .flex_1()
 8485                    .child(
 8486                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8487                            Icon::new(IconName::ZedPredictDown)
 8488                        } else {
 8489                            Icon::new(IconName::ZedPredictUp)
 8490                        },
 8491                    )
 8492                    .child(Label::new("Jump to Edit")),
 8493            ),
 8494
 8495            InlineCompletion::Edit {
 8496                edits,
 8497                edit_preview,
 8498                snapshot,
 8499                display_mode: _,
 8500            } => {
 8501                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8502
 8503                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8504                    &snapshot,
 8505                    &edits,
 8506                    edit_preview.as_ref()?,
 8507                    true,
 8508                    cx,
 8509                )
 8510                .first_line_preview();
 8511
 8512                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8513                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8514
 8515                let preview = h_flex()
 8516                    .gap_1()
 8517                    .min_w_16()
 8518                    .child(styled_text)
 8519                    .when(has_more_lines, |parent| parent.child(""));
 8520
 8521                let left = if first_edit_row != cursor_point.row {
 8522                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8523                        .into_any_element()
 8524                } else {
 8525                    Icon::new(IconName::ZedPredict).into_any_element()
 8526                };
 8527
 8528                Some(
 8529                    h_flex()
 8530                        .h_full()
 8531                        .flex_1()
 8532                        .gap_2()
 8533                        .pr_1()
 8534                        .overflow_x_hidden()
 8535                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8536                        .child(left)
 8537                        .child(preview),
 8538                )
 8539            }
 8540        }
 8541    }
 8542
 8543    fn render_context_menu(
 8544        &self,
 8545        style: &EditorStyle,
 8546        max_height_in_lines: u32,
 8547        window: &mut Window,
 8548        cx: &mut Context<Editor>,
 8549    ) -> Option<AnyElement> {
 8550        let menu = self.context_menu.borrow();
 8551        let menu = menu.as_ref()?;
 8552        if !menu.visible() {
 8553            return None;
 8554        };
 8555        Some(menu.render(style, max_height_in_lines, window, cx))
 8556    }
 8557
 8558    fn render_context_menu_aside(
 8559        &mut self,
 8560        max_size: Size<Pixels>,
 8561        window: &mut Window,
 8562        cx: &mut Context<Editor>,
 8563    ) -> Option<AnyElement> {
 8564        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8565            if menu.visible() {
 8566                menu.render_aside(self, max_size, window, cx)
 8567            } else {
 8568                None
 8569            }
 8570        })
 8571    }
 8572
 8573    fn hide_context_menu(
 8574        &mut self,
 8575        window: &mut Window,
 8576        cx: &mut Context<Self>,
 8577    ) -> Option<CodeContextMenu> {
 8578        cx.notify();
 8579        self.completion_tasks.clear();
 8580        let context_menu = self.context_menu.borrow_mut().take();
 8581        self.stale_inline_completion_in_menu.take();
 8582        self.update_visible_inline_completion(window, cx);
 8583        context_menu
 8584    }
 8585
 8586    fn show_snippet_choices(
 8587        &mut self,
 8588        choices: &Vec<String>,
 8589        selection: Range<Anchor>,
 8590        cx: &mut Context<Self>,
 8591    ) {
 8592        if selection.start.buffer_id.is_none() {
 8593            return;
 8594        }
 8595        let buffer_id = selection.start.buffer_id.unwrap();
 8596        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8597        let id = post_inc(&mut self.next_completion_id);
 8598        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8599
 8600        if let Some(buffer) = buffer {
 8601            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8602                CompletionsMenu::new_snippet_choices(
 8603                    id,
 8604                    true,
 8605                    choices,
 8606                    selection,
 8607                    buffer,
 8608                    snippet_sort_order,
 8609                ),
 8610            ));
 8611        }
 8612    }
 8613
 8614    pub fn insert_snippet(
 8615        &mut self,
 8616        insertion_ranges: &[Range<usize>],
 8617        snippet: Snippet,
 8618        window: &mut Window,
 8619        cx: &mut Context<Self>,
 8620    ) -> Result<()> {
 8621        struct Tabstop<T> {
 8622            is_end_tabstop: bool,
 8623            ranges: Vec<Range<T>>,
 8624            choices: Option<Vec<String>>,
 8625        }
 8626
 8627        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8628            let snippet_text: Arc<str> = snippet.text.clone().into();
 8629            let edits = insertion_ranges
 8630                .iter()
 8631                .cloned()
 8632                .map(|range| (range, snippet_text.clone()));
 8633            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8634
 8635            let snapshot = &*buffer.read(cx);
 8636            let snippet = &snippet;
 8637            snippet
 8638                .tabstops
 8639                .iter()
 8640                .map(|tabstop| {
 8641                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8642                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8643                    });
 8644                    let mut tabstop_ranges = tabstop
 8645                        .ranges
 8646                        .iter()
 8647                        .flat_map(|tabstop_range| {
 8648                            let mut delta = 0_isize;
 8649                            insertion_ranges.iter().map(move |insertion_range| {
 8650                                let insertion_start = insertion_range.start as isize + delta;
 8651                                delta +=
 8652                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8653
 8654                                let start = ((insertion_start + tabstop_range.start) as usize)
 8655                                    .min(snapshot.len());
 8656                                let end = ((insertion_start + tabstop_range.end) as usize)
 8657                                    .min(snapshot.len());
 8658                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8659                            })
 8660                        })
 8661                        .collect::<Vec<_>>();
 8662                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8663
 8664                    Tabstop {
 8665                        is_end_tabstop,
 8666                        ranges: tabstop_ranges,
 8667                        choices: tabstop.choices.clone(),
 8668                    }
 8669                })
 8670                .collect::<Vec<_>>()
 8671        });
 8672        if let Some(tabstop) = tabstops.first() {
 8673            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8674                s.select_ranges(tabstop.ranges.iter().cloned());
 8675            });
 8676
 8677            if let Some(choices) = &tabstop.choices {
 8678                if let Some(selection) = tabstop.ranges.first() {
 8679                    self.show_snippet_choices(choices, selection.clone(), cx)
 8680                }
 8681            }
 8682
 8683            // If we're already at the last tabstop and it's at the end of the snippet,
 8684            // we're done, we don't need to keep the state around.
 8685            if !tabstop.is_end_tabstop {
 8686                let choices = tabstops
 8687                    .iter()
 8688                    .map(|tabstop| tabstop.choices.clone())
 8689                    .collect();
 8690
 8691                let ranges = tabstops
 8692                    .into_iter()
 8693                    .map(|tabstop| tabstop.ranges)
 8694                    .collect::<Vec<_>>();
 8695
 8696                self.snippet_stack.push(SnippetState {
 8697                    active_index: 0,
 8698                    ranges,
 8699                    choices,
 8700                });
 8701            }
 8702
 8703            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8704            if self.autoclose_regions.is_empty() {
 8705                let snapshot = self.buffer.read(cx).snapshot(cx);
 8706                for selection in &mut self.selections.all::<Point>(cx) {
 8707                    let selection_head = selection.head();
 8708                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8709                        continue;
 8710                    };
 8711
 8712                    let mut bracket_pair = None;
 8713                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8714                    let prev_chars = snapshot
 8715                        .reversed_chars_at(selection_head)
 8716                        .collect::<String>();
 8717                    for (pair, enabled) in scope.brackets() {
 8718                        if enabled
 8719                            && pair.close
 8720                            && prev_chars.starts_with(pair.start.as_str())
 8721                            && next_chars.starts_with(pair.end.as_str())
 8722                        {
 8723                            bracket_pair = Some(pair.clone());
 8724                            break;
 8725                        }
 8726                    }
 8727                    if let Some(pair) = bracket_pair {
 8728                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8729                        let autoclose_enabled =
 8730                            self.use_autoclose && snapshot_settings.use_autoclose;
 8731                        if autoclose_enabled {
 8732                            let start = snapshot.anchor_after(selection_head);
 8733                            let end = snapshot.anchor_after(selection_head);
 8734                            self.autoclose_regions.push(AutocloseRegion {
 8735                                selection_id: selection.id,
 8736                                range: start..end,
 8737                                pair,
 8738                            });
 8739                        }
 8740                    }
 8741                }
 8742            }
 8743        }
 8744        Ok(())
 8745    }
 8746
 8747    pub fn move_to_next_snippet_tabstop(
 8748        &mut self,
 8749        window: &mut Window,
 8750        cx: &mut Context<Self>,
 8751    ) -> bool {
 8752        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8753    }
 8754
 8755    pub fn move_to_prev_snippet_tabstop(
 8756        &mut self,
 8757        window: &mut Window,
 8758        cx: &mut Context<Self>,
 8759    ) -> bool {
 8760        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8761    }
 8762
 8763    pub fn move_to_snippet_tabstop(
 8764        &mut self,
 8765        bias: Bias,
 8766        window: &mut Window,
 8767        cx: &mut Context<Self>,
 8768    ) -> bool {
 8769        if let Some(mut snippet) = self.snippet_stack.pop() {
 8770            match bias {
 8771                Bias::Left => {
 8772                    if snippet.active_index > 0 {
 8773                        snippet.active_index -= 1;
 8774                    } else {
 8775                        self.snippet_stack.push(snippet);
 8776                        return false;
 8777                    }
 8778                }
 8779                Bias::Right => {
 8780                    if snippet.active_index + 1 < snippet.ranges.len() {
 8781                        snippet.active_index += 1;
 8782                    } else {
 8783                        self.snippet_stack.push(snippet);
 8784                        return false;
 8785                    }
 8786                }
 8787            }
 8788            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8789                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8790                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8791                });
 8792
 8793                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8794                    if let Some(selection) = current_ranges.first() {
 8795                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8796                    }
 8797                }
 8798
 8799                // If snippet state is not at the last tabstop, push it back on the stack
 8800                if snippet.active_index + 1 < snippet.ranges.len() {
 8801                    self.snippet_stack.push(snippet);
 8802                }
 8803                return true;
 8804            }
 8805        }
 8806
 8807        false
 8808    }
 8809
 8810    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8811        self.transact(window, cx, |this, window, cx| {
 8812            this.select_all(&SelectAll, window, cx);
 8813            this.insert("", window, cx);
 8814        });
 8815    }
 8816
 8817    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8818        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8819        self.transact(window, cx, |this, window, cx| {
 8820            this.select_autoclose_pair(window, cx);
 8821            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8822            if !this.linked_edit_ranges.is_empty() {
 8823                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8824                let snapshot = this.buffer.read(cx).snapshot(cx);
 8825
 8826                for selection in selections.iter() {
 8827                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8828                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8829                    if selection_start.buffer_id != selection_end.buffer_id {
 8830                        continue;
 8831                    }
 8832                    if let Some(ranges) =
 8833                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8834                    {
 8835                        for (buffer, entries) in ranges {
 8836                            linked_ranges.entry(buffer).or_default().extend(entries);
 8837                        }
 8838                    }
 8839                }
 8840            }
 8841
 8842            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8843            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8844            for selection in &mut selections {
 8845                if selection.is_empty() {
 8846                    let old_head = selection.head();
 8847                    let mut new_head =
 8848                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8849                            .to_point(&display_map);
 8850                    if let Some((buffer, line_buffer_range)) = display_map
 8851                        .buffer_snapshot
 8852                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8853                    {
 8854                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8855                        let indent_len = match indent_size.kind {
 8856                            IndentKind::Space => {
 8857                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8858                            }
 8859                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8860                        };
 8861                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8862                            let indent_len = indent_len.get();
 8863                            new_head = cmp::min(
 8864                                new_head,
 8865                                MultiBufferPoint::new(
 8866                                    old_head.row,
 8867                                    ((old_head.column - 1) / indent_len) * indent_len,
 8868                                ),
 8869                            );
 8870                        }
 8871                    }
 8872
 8873                    selection.set_head(new_head, SelectionGoal::None);
 8874                }
 8875            }
 8876
 8877            this.signature_help_state.set_backspace_pressed(true);
 8878            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8879                s.select(selections)
 8880            });
 8881            this.insert("", window, cx);
 8882            let empty_str: Arc<str> = Arc::from("");
 8883            for (buffer, edits) in linked_ranges {
 8884                let snapshot = buffer.read(cx).snapshot();
 8885                use text::ToPoint as TP;
 8886
 8887                let edits = edits
 8888                    .into_iter()
 8889                    .map(|range| {
 8890                        let end_point = TP::to_point(&range.end, &snapshot);
 8891                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8892
 8893                        if end_point == start_point {
 8894                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8895                                .saturating_sub(1);
 8896                            start_point =
 8897                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8898                        };
 8899
 8900                        (start_point..end_point, empty_str.clone())
 8901                    })
 8902                    .sorted_by_key(|(range, _)| range.start)
 8903                    .collect::<Vec<_>>();
 8904                buffer.update(cx, |this, cx| {
 8905                    this.edit(edits, None, cx);
 8906                })
 8907            }
 8908            this.refresh_inline_completion(true, false, window, cx);
 8909            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8910        });
 8911    }
 8912
 8913    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8914        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8915        self.transact(window, cx, |this, window, cx| {
 8916            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8917                s.move_with(|map, selection| {
 8918                    if selection.is_empty() {
 8919                        let cursor = movement::right(map, selection.head());
 8920                        selection.end = cursor;
 8921                        selection.reversed = true;
 8922                        selection.goal = SelectionGoal::None;
 8923                    }
 8924                })
 8925            });
 8926            this.insert("", window, cx);
 8927            this.refresh_inline_completion(true, false, window, cx);
 8928        });
 8929    }
 8930
 8931    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8932        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8933        if self.move_to_prev_snippet_tabstop(window, cx) {
 8934            return;
 8935        }
 8936        self.outdent(&Outdent, window, cx);
 8937    }
 8938
 8939    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8940        if self.move_to_next_snippet_tabstop(window, cx) {
 8941            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8942            return;
 8943        }
 8944        if self.read_only(cx) {
 8945            return;
 8946        }
 8947        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8948        let mut selections = self.selections.all_adjusted(cx);
 8949        let buffer = self.buffer.read(cx);
 8950        let snapshot = buffer.snapshot(cx);
 8951        let rows_iter = selections.iter().map(|s| s.head().row);
 8952        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8953
 8954        let has_some_cursor_in_whitespace = selections
 8955            .iter()
 8956            .filter(|selection| selection.is_empty())
 8957            .any(|selection| {
 8958                let cursor = selection.head();
 8959                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8960                cursor.column < current_indent.len
 8961            });
 8962
 8963        let mut edits = Vec::new();
 8964        let mut prev_edited_row = 0;
 8965        let mut row_delta = 0;
 8966        for selection in &mut selections {
 8967            if selection.start.row != prev_edited_row {
 8968                row_delta = 0;
 8969            }
 8970            prev_edited_row = selection.end.row;
 8971
 8972            // If the selection is non-empty, then increase the indentation of the selected lines.
 8973            if !selection.is_empty() {
 8974                row_delta =
 8975                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8976                continue;
 8977            }
 8978
 8979            let cursor = selection.head();
 8980            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8981            if let Some(suggested_indent) =
 8982                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8983            {
 8984                // Don't do anything if already at suggested indent
 8985                // and there is any other cursor which is not
 8986                if has_some_cursor_in_whitespace
 8987                    && cursor.column == current_indent.len
 8988                    && current_indent.len == suggested_indent.len
 8989                {
 8990                    continue;
 8991                }
 8992
 8993                // Adjust line and move cursor to suggested indent
 8994                // if cursor is not at suggested indent
 8995                if cursor.column < suggested_indent.len
 8996                    && cursor.column <= current_indent.len
 8997                    && current_indent.len <= suggested_indent.len
 8998                {
 8999                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9000                    selection.end = selection.start;
 9001                    if row_delta == 0 {
 9002                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9003                            cursor.row,
 9004                            current_indent,
 9005                            suggested_indent,
 9006                        ));
 9007                        row_delta = suggested_indent.len - current_indent.len;
 9008                    }
 9009                    continue;
 9010                }
 9011
 9012                // If current indent is more than suggested indent
 9013                // only move cursor to current indent and skip indent
 9014                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9015                    selection.start = Point::new(cursor.row, current_indent.len);
 9016                    selection.end = selection.start;
 9017                    continue;
 9018                }
 9019            }
 9020
 9021            // Otherwise, insert a hard or soft tab.
 9022            let settings = buffer.language_settings_at(cursor, cx);
 9023            let tab_size = if settings.hard_tabs {
 9024                IndentSize::tab()
 9025            } else {
 9026                let tab_size = settings.tab_size.get();
 9027                let indent_remainder = snapshot
 9028                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9029                    .flat_map(str::chars)
 9030                    .fold(row_delta % tab_size, |counter: u32, c| {
 9031                        if c == '\t' {
 9032                            0
 9033                        } else {
 9034                            (counter + 1) % tab_size
 9035                        }
 9036                    });
 9037
 9038                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9039                IndentSize::spaces(chars_to_next_tab_stop)
 9040            };
 9041            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9042            selection.end = selection.start;
 9043            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9044            row_delta += tab_size.len;
 9045        }
 9046
 9047        self.transact(window, cx, |this, window, cx| {
 9048            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9049            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9050                s.select(selections)
 9051            });
 9052            this.refresh_inline_completion(true, false, window, cx);
 9053        });
 9054    }
 9055
 9056    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9057        if self.read_only(cx) {
 9058            return;
 9059        }
 9060        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9061        let mut selections = self.selections.all::<Point>(cx);
 9062        let mut prev_edited_row = 0;
 9063        let mut row_delta = 0;
 9064        let mut edits = Vec::new();
 9065        let buffer = self.buffer.read(cx);
 9066        let snapshot = buffer.snapshot(cx);
 9067        for selection in &mut selections {
 9068            if selection.start.row != prev_edited_row {
 9069                row_delta = 0;
 9070            }
 9071            prev_edited_row = selection.end.row;
 9072
 9073            row_delta =
 9074                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9075        }
 9076
 9077        self.transact(window, cx, |this, window, cx| {
 9078            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9079            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9080                s.select(selections)
 9081            });
 9082        });
 9083    }
 9084
 9085    fn indent_selection(
 9086        buffer: &MultiBuffer,
 9087        snapshot: &MultiBufferSnapshot,
 9088        selection: &mut Selection<Point>,
 9089        edits: &mut Vec<(Range<Point>, String)>,
 9090        delta_for_start_row: u32,
 9091        cx: &App,
 9092    ) -> u32 {
 9093        let settings = buffer.language_settings_at(selection.start, cx);
 9094        let tab_size = settings.tab_size.get();
 9095        let indent_kind = if settings.hard_tabs {
 9096            IndentKind::Tab
 9097        } else {
 9098            IndentKind::Space
 9099        };
 9100        let mut start_row = selection.start.row;
 9101        let mut end_row = selection.end.row + 1;
 9102
 9103        // If a selection ends at the beginning of a line, don't indent
 9104        // that last line.
 9105        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9106            end_row -= 1;
 9107        }
 9108
 9109        // Avoid re-indenting a row that has already been indented by a
 9110        // previous selection, but still update this selection's column
 9111        // to reflect that indentation.
 9112        if delta_for_start_row > 0 {
 9113            start_row += 1;
 9114            selection.start.column += delta_for_start_row;
 9115            if selection.end.row == selection.start.row {
 9116                selection.end.column += delta_for_start_row;
 9117            }
 9118        }
 9119
 9120        let mut delta_for_end_row = 0;
 9121        let has_multiple_rows = start_row + 1 != end_row;
 9122        for row in start_row..end_row {
 9123            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9124            let indent_delta = match (current_indent.kind, indent_kind) {
 9125                (IndentKind::Space, IndentKind::Space) => {
 9126                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9127                    IndentSize::spaces(columns_to_next_tab_stop)
 9128                }
 9129                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9130                (_, IndentKind::Tab) => IndentSize::tab(),
 9131            };
 9132
 9133            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9134                0
 9135            } else {
 9136                selection.start.column
 9137            };
 9138            let row_start = Point::new(row, start);
 9139            edits.push((
 9140                row_start..row_start,
 9141                indent_delta.chars().collect::<String>(),
 9142            ));
 9143
 9144            // Update this selection's endpoints to reflect the indentation.
 9145            if row == selection.start.row {
 9146                selection.start.column += indent_delta.len;
 9147            }
 9148            if row == selection.end.row {
 9149                selection.end.column += indent_delta.len;
 9150                delta_for_end_row = indent_delta.len;
 9151            }
 9152        }
 9153
 9154        if selection.start.row == selection.end.row {
 9155            delta_for_start_row + delta_for_end_row
 9156        } else {
 9157            delta_for_end_row
 9158        }
 9159    }
 9160
 9161    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9162        if self.read_only(cx) {
 9163            return;
 9164        }
 9165        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9166        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9167        let selections = self.selections.all::<Point>(cx);
 9168        let mut deletion_ranges = Vec::new();
 9169        let mut last_outdent = None;
 9170        {
 9171            let buffer = self.buffer.read(cx);
 9172            let snapshot = buffer.snapshot(cx);
 9173            for selection in &selections {
 9174                let settings = buffer.language_settings_at(selection.start, cx);
 9175                let tab_size = settings.tab_size.get();
 9176                let mut rows = selection.spanned_rows(false, &display_map);
 9177
 9178                // Avoid re-outdenting a row that has already been outdented by a
 9179                // previous selection.
 9180                if let Some(last_row) = last_outdent {
 9181                    if last_row == rows.start {
 9182                        rows.start = rows.start.next_row();
 9183                    }
 9184                }
 9185                let has_multiple_rows = rows.len() > 1;
 9186                for row in rows.iter_rows() {
 9187                    let indent_size = snapshot.indent_size_for_line(row);
 9188                    if indent_size.len > 0 {
 9189                        let deletion_len = match indent_size.kind {
 9190                            IndentKind::Space => {
 9191                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9192                                if columns_to_prev_tab_stop == 0 {
 9193                                    tab_size
 9194                                } else {
 9195                                    columns_to_prev_tab_stop
 9196                                }
 9197                            }
 9198                            IndentKind::Tab => 1,
 9199                        };
 9200                        let start = if has_multiple_rows
 9201                            || deletion_len > selection.start.column
 9202                            || indent_size.len < selection.start.column
 9203                        {
 9204                            0
 9205                        } else {
 9206                            selection.start.column - deletion_len
 9207                        };
 9208                        deletion_ranges.push(
 9209                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9210                        );
 9211                        last_outdent = Some(row);
 9212                    }
 9213                }
 9214            }
 9215        }
 9216
 9217        self.transact(window, cx, |this, window, cx| {
 9218            this.buffer.update(cx, |buffer, cx| {
 9219                let empty_str: Arc<str> = Arc::default();
 9220                buffer.edit(
 9221                    deletion_ranges
 9222                        .into_iter()
 9223                        .map(|range| (range, empty_str.clone())),
 9224                    None,
 9225                    cx,
 9226                );
 9227            });
 9228            let selections = this.selections.all::<usize>(cx);
 9229            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9230                s.select(selections)
 9231            });
 9232        });
 9233    }
 9234
 9235    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9236        if self.read_only(cx) {
 9237            return;
 9238        }
 9239        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9240        let selections = self
 9241            .selections
 9242            .all::<usize>(cx)
 9243            .into_iter()
 9244            .map(|s| s.range());
 9245
 9246        self.transact(window, cx, |this, window, cx| {
 9247            this.buffer.update(cx, |buffer, cx| {
 9248                buffer.autoindent_ranges(selections, cx);
 9249            });
 9250            let selections = this.selections.all::<usize>(cx);
 9251            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9252                s.select(selections)
 9253            });
 9254        });
 9255    }
 9256
 9257    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9258        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9260        let selections = self.selections.all::<Point>(cx);
 9261
 9262        let mut new_cursors = Vec::new();
 9263        let mut edit_ranges = Vec::new();
 9264        let mut selections = selections.iter().peekable();
 9265        while let Some(selection) = selections.next() {
 9266            let mut rows = selection.spanned_rows(false, &display_map);
 9267            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9268
 9269            // Accumulate contiguous regions of rows that we want to delete.
 9270            while let Some(next_selection) = selections.peek() {
 9271                let next_rows = next_selection.spanned_rows(false, &display_map);
 9272                if next_rows.start <= rows.end {
 9273                    rows.end = next_rows.end;
 9274                    selections.next().unwrap();
 9275                } else {
 9276                    break;
 9277                }
 9278            }
 9279
 9280            let buffer = &display_map.buffer_snapshot;
 9281            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9282            let edit_end;
 9283            let cursor_buffer_row;
 9284            if buffer.max_point().row >= rows.end.0 {
 9285                // If there's a line after the range, delete the \n from the end of the row range
 9286                // and position the cursor on the next line.
 9287                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9288                cursor_buffer_row = rows.end;
 9289            } else {
 9290                // If there isn't a line after the range, delete the \n from the line before the
 9291                // start of the row range and position the cursor there.
 9292                edit_start = edit_start.saturating_sub(1);
 9293                edit_end = buffer.len();
 9294                cursor_buffer_row = rows.start.previous_row();
 9295            }
 9296
 9297            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9298            *cursor.column_mut() =
 9299                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9300
 9301            new_cursors.push((
 9302                selection.id,
 9303                buffer.anchor_after(cursor.to_point(&display_map)),
 9304            ));
 9305            edit_ranges.push(edit_start..edit_end);
 9306        }
 9307
 9308        self.transact(window, cx, |this, window, cx| {
 9309            let buffer = this.buffer.update(cx, |buffer, cx| {
 9310                let empty_str: Arc<str> = Arc::default();
 9311                buffer.edit(
 9312                    edit_ranges
 9313                        .into_iter()
 9314                        .map(|range| (range, empty_str.clone())),
 9315                    None,
 9316                    cx,
 9317                );
 9318                buffer.snapshot(cx)
 9319            });
 9320            let new_selections = new_cursors
 9321                .into_iter()
 9322                .map(|(id, cursor)| {
 9323                    let cursor = cursor.to_point(&buffer);
 9324                    Selection {
 9325                        id,
 9326                        start: cursor,
 9327                        end: cursor,
 9328                        reversed: false,
 9329                        goal: SelectionGoal::None,
 9330                    }
 9331                })
 9332                .collect();
 9333
 9334            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9335                s.select(new_selections);
 9336            });
 9337        });
 9338    }
 9339
 9340    pub fn join_lines_impl(
 9341        &mut self,
 9342        insert_whitespace: bool,
 9343        window: &mut Window,
 9344        cx: &mut Context<Self>,
 9345    ) {
 9346        if self.read_only(cx) {
 9347            return;
 9348        }
 9349        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9350        for selection in self.selections.all::<Point>(cx) {
 9351            let start = MultiBufferRow(selection.start.row);
 9352            // Treat single line selections as if they include the next line. Otherwise this action
 9353            // would do nothing for single line selections individual cursors.
 9354            let end = if selection.start.row == selection.end.row {
 9355                MultiBufferRow(selection.start.row + 1)
 9356            } else {
 9357                MultiBufferRow(selection.end.row)
 9358            };
 9359
 9360            if let Some(last_row_range) = row_ranges.last_mut() {
 9361                if start <= last_row_range.end {
 9362                    last_row_range.end = end;
 9363                    continue;
 9364                }
 9365            }
 9366            row_ranges.push(start..end);
 9367        }
 9368
 9369        let snapshot = self.buffer.read(cx).snapshot(cx);
 9370        let mut cursor_positions = Vec::new();
 9371        for row_range in &row_ranges {
 9372            let anchor = snapshot.anchor_before(Point::new(
 9373                row_range.end.previous_row().0,
 9374                snapshot.line_len(row_range.end.previous_row()),
 9375            ));
 9376            cursor_positions.push(anchor..anchor);
 9377        }
 9378
 9379        self.transact(window, cx, |this, window, cx| {
 9380            for row_range in row_ranges.into_iter().rev() {
 9381                for row in row_range.iter_rows().rev() {
 9382                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9383                    let next_line_row = row.next_row();
 9384                    let indent = snapshot.indent_size_for_line(next_line_row);
 9385                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9386
 9387                    let replace =
 9388                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9389                            " "
 9390                        } else {
 9391                            ""
 9392                        };
 9393
 9394                    this.buffer.update(cx, |buffer, cx| {
 9395                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9396                    });
 9397                }
 9398            }
 9399
 9400            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9401                s.select_anchor_ranges(cursor_positions)
 9402            });
 9403        });
 9404    }
 9405
 9406    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9407        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9408        self.join_lines_impl(true, window, cx);
 9409    }
 9410
 9411    pub fn sort_lines_case_sensitive(
 9412        &mut self,
 9413        _: &SortLinesCaseSensitive,
 9414        window: &mut Window,
 9415        cx: &mut Context<Self>,
 9416    ) {
 9417        self.manipulate_lines(window, cx, |lines| lines.sort())
 9418    }
 9419
 9420    pub fn sort_lines_case_insensitive(
 9421        &mut self,
 9422        _: &SortLinesCaseInsensitive,
 9423        window: &mut Window,
 9424        cx: &mut Context<Self>,
 9425    ) {
 9426        self.manipulate_lines(window, cx, |lines| {
 9427            lines.sort_by_key(|line| line.to_lowercase())
 9428        })
 9429    }
 9430
 9431    pub fn unique_lines_case_insensitive(
 9432        &mut self,
 9433        _: &UniqueLinesCaseInsensitive,
 9434        window: &mut Window,
 9435        cx: &mut Context<Self>,
 9436    ) {
 9437        self.manipulate_lines(window, cx, |lines| {
 9438            let mut seen = HashSet::default();
 9439            lines.retain(|line| seen.insert(line.to_lowercase()));
 9440        })
 9441    }
 9442
 9443    pub fn unique_lines_case_sensitive(
 9444        &mut self,
 9445        _: &UniqueLinesCaseSensitive,
 9446        window: &mut Window,
 9447        cx: &mut Context<Self>,
 9448    ) {
 9449        self.manipulate_lines(window, cx, |lines| {
 9450            let mut seen = HashSet::default();
 9451            lines.retain(|line| seen.insert(*line));
 9452        })
 9453    }
 9454
 9455    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9456        let Some(project) = self.project.clone() else {
 9457            return;
 9458        };
 9459        self.reload(project, window, cx)
 9460            .detach_and_notify_err(window, cx);
 9461    }
 9462
 9463    pub fn restore_file(
 9464        &mut self,
 9465        _: &::git::RestoreFile,
 9466        window: &mut Window,
 9467        cx: &mut Context<Self>,
 9468    ) {
 9469        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9470        let mut buffer_ids = HashSet::default();
 9471        let snapshot = self.buffer().read(cx).snapshot(cx);
 9472        for selection in self.selections.all::<usize>(cx) {
 9473            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9474        }
 9475
 9476        let buffer = self.buffer().read(cx);
 9477        let ranges = buffer_ids
 9478            .into_iter()
 9479            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9480            .collect::<Vec<_>>();
 9481
 9482        self.restore_hunks_in_ranges(ranges, window, cx);
 9483    }
 9484
 9485    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9486        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9487        let selections = self
 9488            .selections
 9489            .all(cx)
 9490            .into_iter()
 9491            .map(|s| s.range())
 9492            .collect();
 9493        self.restore_hunks_in_ranges(selections, window, cx);
 9494    }
 9495
 9496    pub fn restore_hunks_in_ranges(
 9497        &mut self,
 9498        ranges: Vec<Range<Point>>,
 9499        window: &mut Window,
 9500        cx: &mut Context<Editor>,
 9501    ) {
 9502        let mut revert_changes = HashMap::default();
 9503        let chunk_by = self
 9504            .snapshot(window, cx)
 9505            .hunks_for_ranges(ranges)
 9506            .into_iter()
 9507            .chunk_by(|hunk| hunk.buffer_id);
 9508        for (buffer_id, hunks) in &chunk_by {
 9509            let hunks = hunks.collect::<Vec<_>>();
 9510            for hunk in &hunks {
 9511                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9512            }
 9513            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9514        }
 9515        drop(chunk_by);
 9516        if !revert_changes.is_empty() {
 9517            self.transact(window, cx, |editor, window, cx| {
 9518                editor.restore(revert_changes, window, cx);
 9519            });
 9520        }
 9521    }
 9522
 9523    pub fn open_active_item_in_terminal(
 9524        &mut self,
 9525        _: &OpenInTerminal,
 9526        window: &mut Window,
 9527        cx: &mut Context<Self>,
 9528    ) {
 9529        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9530            let project_path = buffer.read(cx).project_path(cx)?;
 9531            let project = self.project.as_ref()?.read(cx);
 9532            let entry = project.entry_for_path(&project_path, cx)?;
 9533            let parent = match &entry.canonical_path {
 9534                Some(canonical_path) => canonical_path.to_path_buf(),
 9535                None => project.absolute_path(&project_path, cx)?,
 9536            }
 9537            .parent()?
 9538            .to_path_buf();
 9539            Some(parent)
 9540        }) {
 9541            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9542        }
 9543    }
 9544
 9545    fn set_breakpoint_context_menu(
 9546        &mut self,
 9547        display_row: DisplayRow,
 9548        position: Option<Anchor>,
 9549        clicked_point: gpui::Point<Pixels>,
 9550        window: &mut Window,
 9551        cx: &mut Context<Self>,
 9552    ) {
 9553        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9554            return;
 9555        }
 9556        let source = self
 9557            .buffer
 9558            .read(cx)
 9559            .snapshot(cx)
 9560            .anchor_before(Point::new(display_row.0, 0u32));
 9561
 9562        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9563
 9564        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9565            self,
 9566            source,
 9567            clicked_point,
 9568            context_menu,
 9569            window,
 9570            cx,
 9571        );
 9572    }
 9573
 9574    fn add_edit_breakpoint_block(
 9575        &mut self,
 9576        anchor: Anchor,
 9577        breakpoint: &Breakpoint,
 9578        edit_action: BreakpointPromptEditAction,
 9579        window: &mut Window,
 9580        cx: &mut Context<Self>,
 9581    ) {
 9582        let weak_editor = cx.weak_entity();
 9583        let bp_prompt = cx.new(|cx| {
 9584            BreakpointPromptEditor::new(
 9585                weak_editor,
 9586                anchor,
 9587                breakpoint.clone(),
 9588                edit_action,
 9589                window,
 9590                cx,
 9591            )
 9592        });
 9593
 9594        let height = bp_prompt.update(cx, |this, cx| {
 9595            this.prompt
 9596                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9597        });
 9598        let cloned_prompt = bp_prompt.clone();
 9599        let blocks = vec![BlockProperties {
 9600            style: BlockStyle::Sticky,
 9601            placement: BlockPlacement::Above(anchor),
 9602            height: Some(height),
 9603            render: Arc::new(move |cx| {
 9604                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9605                cloned_prompt.clone().into_any_element()
 9606            }),
 9607            priority: 0,
 9608            render_in_minimap: true,
 9609        }];
 9610
 9611        let focus_handle = bp_prompt.focus_handle(cx);
 9612        window.focus(&focus_handle);
 9613
 9614        let block_ids = self.insert_blocks(blocks, None, cx);
 9615        bp_prompt.update(cx, |prompt, _| {
 9616            prompt.add_block_ids(block_ids);
 9617        });
 9618    }
 9619
 9620    pub(crate) fn breakpoint_at_row(
 9621        &self,
 9622        row: u32,
 9623        window: &mut Window,
 9624        cx: &mut Context<Self>,
 9625    ) -> Option<(Anchor, Breakpoint)> {
 9626        let snapshot = self.snapshot(window, cx);
 9627        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9628
 9629        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9630    }
 9631
 9632    pub(crate) fn breakpoint_at_anchor(
 9633        &self,
 9634        breakpoint_position: Anchor,
 9635        snapshot: &EditorSnapshot,
 9636        cx: &mut Context<Self>,
 9637    ) -> Option<(Anchor, Breakpoint)> {
 9638        let project = self.project.clone()?;
 9639
 9640        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9641            snapshot
 9642                .buffer_snapshot
 9643                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9644        })?;
 9645
 9646        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9647        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9648        let buffer_snapshot = buffer.read(cx).snapshot();
 9649
 9650        let row = buffer_snapshot
 9651            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9652            .row;
 9653
 9654        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9655        let anchor_end = snapshot
 9656            .buffer_snapshot
 9657            .anchor_after(Point::new(row, line_len));
 9658
 9659        let bp = self
 9660            .breakpoint_store
 9661            .as_ref()?
 9662            .read_with(cx, |breakpoint_store, cx| {
 9663                breakpoint_store
 9664                    .breakpoints(
 9665                        &buffer,
 9666                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9667                        &buffer_snapshot,
 9668                        cx,
 9669                    )
 9670                    .next()
 9671                    .and_then(|(bp, _)| {
 9672                        let breakpoint_row = buffer_snapshot
 9673                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9674                            .row;
 9675
 9676                        if breakpoint_row == row {
 9677                            snapshot
 9678                                .buffer_snapshot
 9679                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9680                                .map(|position| (position, bp.bp.clone()))
 9681                        } else {
 9682                            None
 9683                        }
 9684                    })
 9685            });
 9686        bp
 9687    }
 9688
 9689    pub fn edit_log_breakpoint(
 9690        &mut self,
 9691        _: &EditLogBreakpoint,
 9692        window: &mut Window,
 9693        cx: &mut Context<Self>,
 9694    ) {
 9695        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9696            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9697                message: None,
 9698                state: BreakpointState::Enabled,
 9699                condition: None,
 9700                hit_condition: None,
 9701            });
 9702
 9703            self.add_edit_breakpoint_block(
 9704                anchor,
 9705                &breakpoint,
 9706                BreakpointPromptEditAction::Log,
 9707                window,
 9708                cx,
 9709            );
 9710        }
 9711    }
 9712
 9713    fn breakpoints_at_cursors(
 9714        &self,
 9715        window: &mut Window,
 9716        cx: &mut Context<Self>,
 9717    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9718        let snapshot = self.snapshot(window, cx);
 9719        let cursors = self
 9720            .selections
 9721            .disjoint_anchors()
 9722            .into_iter()
 9723            .map(|selection| {
 9724                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9725
 9726                let breakpoint_position = self
 9727                    .breakpoint_at_row(cursor_position.row, window, cx)
 9728                    .map(|bp| bp.0)
 9729                    .unwrap_or_else(|| {
 9730                        snapshot
 9731                            .display_snapshot
 9732                            .buffer_snapshot
 9733                            .anchor_after(Point::new(cursor_position.row, 0))
 9734                    });
 9735
 9736                let breakpoint = self
 9737                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9738                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9739
 9740                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9741            })
 9742            // 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.
 9743            .collect::<HashMap<Anchor, _>>();
 9744
 9745        cursors.into_iter().collect()
 9746    }
 9747
 9748    pub fn enable_breakpoint(
 9749        &mut self,
 9750        _: &crate::actions::EnableBreakpoint,
 9751        window: &mut Window,
 9752        cx: &mut Context<Self>,
 9753    ) {
 9754        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9755            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9756                continue;
 9757            };
 9758            self.edit_breakpoint_at_anchor(
 9759                anchor,
 9760                breakpoint,
 9761                BreakpointEditAction::InvertState,
 9762                cx,
 9763            );
 9764        }
 9765    }
 9766
 9767    pub fn disable_breakpoint(
 9768        &mut self,
 9769        _: &crate::actions::DisableBreakpoint,
 9770        window: &mut Window,
 9771        cx: &mut Context<Self>,
 9772    ) {
 9773        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9774            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9775                continue;
 9776            };
 9777            self.edit_breakpoint_at_anchor(
 9778                anchor,
 9779                breakpoint,
 9780                BreakpointEditAction::InvertState,
 9781                cx,
 9782            );
 9783        }
 9784    }
 9785
 9786    pub fn toggle_breakpoint(
 9787        &mut self,
 9788        _: &crate::actions::ToggleBreakpoint,
 9789        window: &mut Window,
 9790        cx: &mut Context<Self>,
 9791    ) {
 9792        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9793            if let Some(breakpoint) = breakpoint {
 9794                self.edit_breakpoint_at_anchor(
 9795                    anchor,
 9796                    breakpoint,
 9797                    BreakpointEditAction::Toggle,
 9798                    cx,
 9799                );
 9800            } else {
 9801                self.edit_breakpoint_at_anchor(
 9802                    anchor,
 9803                    Breakpoint::new_standard(),
 9804                    BreakpointEditAction::Toggle,
 9805                    cx,
 9806                );
 9807            }
 9808        }
 9809    }
 9810
 9811    pub fn edit_breakpoint_at_anchor(
 9812        &mut self,
 9813        breakpoint_position: Anchor,
 9814        breakpoint: Breakpoint,
 9815        edit_action: BreakpointEditAction,
 9816        cx: &mut Context<Self>,
 9817    ) {
 9818        let Some(breakpoint_store) = &self.breakpoint_store else {
 9819            return;
 9820        };
 9821
 9822        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9823            if breakpoint_position == Anchor::min() {
 9824                self.buffer()
 9825                    .read(cx)
 9826                    .excerpt_buffer_ids()
 9827                    .into_iter()
 9828                    .next()
 9829            } else {
 9830                None
 9831            }
 9832        }) else {
 9833            return;
 9834        };
 9835
 9836        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9837            return;
 9838        };
 9839
 9840        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9841            breakpoint_store.toggle_breakpoint(
 9842                buffer,
 9843                BreakpointWithPosition {
 9844                    position: breakpoint_position.text_anchor,
 9845                    bp: breakpoint,
 9846                },
 9847                edit_action,
 9848                cx,
 9849            );
 9850        });
 9851
 9852        cx.notify();
 9853    }
 9854
 9855    #[cfg(any(test, feature = "test-support"))]
 9856    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9857        self.breakpoint_store.clone()
 9858    }
 9859
 9860    pub fn prepare_restore_change(
 9861        &self,
 9862        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9863        hunk: &MultiBufferDiffHunk,
 9864        cx: &mut App,
 9865    ) -> Option<()> {
 9866        if hunk.is_created_file() {
 9867            return None;
 9868        }
 9869        let buffer = self.buffer.read(cx);
 9870        let diff = buffer.diff_for(hunk.buffer_id)?;
 9871        let buffer = buffer.buffer(hunk.buffer_id)?;
 9872        let buffer = buffer.read(cx);
 9873        let original_text = diff
 9874            .read(cx)
 9875            .base_text()
 9876            .as_rope()
 9877            .slice(hunk.diff_base_byte_range.clone());
 9878        let buffer_snapshot = buffer.snapshot();
 9879        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9880        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9881            probe
 9882                .0
 9883                .start
 9884                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9885                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9886        }) {
 9887            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9888            Some(())
 9889        } else {
 9890            None
 9891        }
 9892    }
 9893
 9894    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9895        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9896    }
 9897
 9898    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9899        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9900    }
 9901
 9902    fn manipulate_lines<Fn>(
 9903        &mut self,
 9904        window: &mut Window,
 9905        cx: &mut Context<Self>,
 9906        mut callback: Fn,
 9907    ) where
 9908        Fn: FnMut(&mut Vec<&str>),
 9909    {
 9910        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9911
 9912        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9913        let buffer = self.buffer.read(cx).snapshot(cx);
 9914
 9915        let mut edits = Vec::new();
 9916
 9917        let selections = self.selections.all::<Point>(cx);
 9918        let mut selections = selections.iter().peekable();
 9919        let mut contiguous_row_selections = Vec::new();
 9920        let mut new_selections = Vec::new();
 9921        let mut added_lines = 0;
 9922        let mut removed_lines = 0;
 9923
 9924        while let Some(selection) = selections.next() {
 9925            let (start_row, end_row) = consume_contiguous_rows(
 9926                &mut contiguous_row_selections,
 9927                selection,
 9928                &display_map,
 9929                &mut selections,
 9930            );
 9931
 9932            let start_point = Point::new(start_row.0, 0);
 9933            let end_point = Point::new(
 9934                end_row.previous_row().0,
 9935                buffer.line_len(end_row.previous_row()),
 9936            );
 9937            let text = buffer
 9938                .text_for_range(start_point..end_point)
 9939                .collect::<String>();
 9940
 9941            let mut lines = text.split('\n').collect_vec();
 9942
 9943            let lines_before = lines.len();
 9944            callback(&mut lines);
 9945            let lines_after = lines.len();
 9946
 9947            edits.push((start_point..end_point, lines.join("\n")));
 9948
 9949            // Selections must change based on added and removed line count
 9950            let start_row =
 9951                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9952            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9953            new_selections.push(Selection {
 9954                id: selection.id,
 9955                start: start_row,
 9956                end: end_row,
 9957                goal: SelectionGoal::None,
 9958                reversed: selection.reversed,
 9959            });
 9960
 9961            if lines_after > lines_before {
 9962                added_lines += lines_after - lines_before;
 9963            } else if lines_before > lines_after {
 9964                removed_lines += lines_before - lines_after;
 9965            }
 9966        }
 9967
 9968        self.transact(window, cx, |this, window, cx| {
 9969            let buffer = this.buffer.update(cx, |buffer, cx| {
 9970                buffer.edit(edits, None, cx);
 9971                buffer.snapshot(cx)
 9972            });
 9973
 9974            // Recalculate offsets on newly edited buffer
 9975            let new_selections = new_selections
 9976                .iter()
 9977                .map(|s| {
 9978                    let start_point = Point::new(s.start.0, 0);
 9979                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9980                    Selection {
 9981                        id: s.id,
 9982                        start: buffer.point_to_offset(start_point),
 9983                        end: buffer.point_to_offset(end_point),
 9984                        goal: s.goal,
 9985                        reversed: s.reversed,
 9986                    }
 9987                })
 9988                .collect();
 9989
 9990            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9991                s.select(new_selections);
 9992            });
 9993
 9994            this.request_autoscroll(Autoscroll::fit(), cx);
 9995        });
 9996    }
 9997
 9998    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9999        self.manipulate_text(window, cx, |text| {
10000            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10001            if has_upper_case_characters {
10002                text.to_lowercase()
10003            } else {
10004                text.to_uppercase()
10005            }
10006        })
10007    }
10008
10009    pub fn convert_to_upper_case(
10010        &mut self,
10011        _: &ConvertToUpperCase,
10012        window: &mut Window,
10013        cx: &mut Context<Self>,
10014    ) {
10015        self.manipulate_text(window, cx, |text| text.to_uppercase())
10016    }
10017
10018    pub fn convert_to_lower_case(
10019        &mut self,
10020        _: &ConvertToLowerCase,
10021        window: &mut Window,
10022        cx: &mut Context<Self>,
10023    ) {
10024        self.manipulate_text(window, cx, |text| text.to_lowercase())
10025    }
10026
10027    pub fn convert_to_title_case(
10028        &mut self,
10029        _: &ConvertToTitleCase,
10030        window: &mut Window,
10031        cx: &mut Context<Self>,
10032    ) {
10033        self.manipulate_text(window, cx, |text| {
10034            text.split('\n')
10035                .map(|line| line.to_case(Case::Title))
10036                .join("\n")
10037        })
10038    }
10039
10040    pub fn convert_to_snake_case(
10041        &mut self,
10042        _: &ConvertToSnakeCase,
10043        window: &mut Window,
10044        cx: &mut Context<Self>,
10045    ) {
10046        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10047    }
10048
10049    pub fn convert_to_kebab_case(
10050        &mut self,
10051        _: &ConvertToKebabCase,
10052        window: &mut Window,
10053        cx: &mut Context<Self>,
10054    ) {
10055        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10056    }
10057
10058    pub fn convert_to_upper_camel_case(
10059        &mut self,
10060        _: &ConvertToUpperCamelCase,
10061        window: &mut Window,
10062        cx: &mut Context<Self>,
10063    ) {
10064        self.manipulate_text(window, cx, |text| {
10065            text.split('\n')
10066                .map(|line| line.to_case(Case::UpperCamel))
10067                .join("\n")
10068        })
10069    }
10070
10071    pub fn convert_to_lower_camel_case(
10072        &mut self,
10073        _: &ConvertToLowerCamelCase,
10074        window: &mut Window,
10075        cx: &mut Context<Self>,
10076    ) {
10077        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10078    }
10079
10080    pub fn convert_to_opposite_case(
10081        &mut self,
10082        _: &ConvertToOppositeCase,
10083        window: &mut Window,
10084        cx: &mut Context<Self>,
10085    ) {
10086        self.manipulate_text(window, cx, |text| {
10087            text.chars()
10088                .fold(String::with_capacity(text.len()), |mut t, c| {
10089                    if c.is_uppercase() {
10090                        t.extend(c.to_lowercase());
10091                    } else {
10092                        t.extend(c.to_uppercase());
10093                    }
10094                    t
10095                })
10096        })
10097    }
10098
10099    pub fn convert_to_rot13(
10100        &mut self,
10101        _: &ConvertToRot13,
10102        window: &mut Window,
10103        cx: &mut Context<Self>,
10104    ) {
10105        self.manipulate_text(window, cx, |text| {
10106            text.chars()
10107                .map(|c| match c {
10108                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10109                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10110                    _ => c,
10111                })
10112                .collect()
10113        })
10114    }
10115
10116    pub fn convert_to_rot47(
10117        &mut self,
10118        _: &ConvertToRot47,
10119        window: &mut Window,
10120        cx: &mut Context<Self>,
10121    ) {
10122        self.manipulate_text(window, cx, |text| {
10123            text.chars()
10124                .map(|c| {
10125                    let code_point = c as u32;
10126                    if code_point >= 33 && code_point <= 126 {
10127                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10128                    }
10129                    c
10130                })
10131                .collect()
10132        })
10133    }
10134
10135    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10136    where
10137        Fn: FnMut(&str) -> String,
10138    {
10139        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10140        let buffer = self.buffer.read(cx).snapshot(cx);
10141
10142        let mut new_selections = Vec::new();
10143        let mut edits = Vec::new();
10144        let mut selection_adjustment = 0i32;
10145
10146        for selection in self.selections.all::<usize>(cx) {
10147            let selection_is_empty = selection.is_empty();
10148
10149            let (start, end) = if selection_is_empty {
10150                let word_range = movement::surrounding_word(
10151                    &display_map,
10152                    selection.start.to_display_point(&display_map),
10153                );
10154                let start = word_range.start.to_offset(&display_map, Bias::Left);
10155                let end = word_range.end.to_offset(&display_map, Bias::Left);
10156                (start, end)
10157            } else {
10158                (selection.start, selection.end)
10159            };
10160
10161            let text = buffer.text_for_range(start..end).collect::<String>();
10162            let old_length = text.len() as i32;
10163            let text = callback(&text);
10164
10165            new_selections.push(Selection {
10166                start: (start as i32 - selection_adjustment) as usize,
10167                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10168                goal: SelectionGoal::None,
10169                ..selection
10170            });
10171
10172            selection_adjustment += old_length - text.len() as i32;
10173
10174            edits.push((start..end, text));
10175        }
10176
10177        self.transact(window, cx, |this, window, cx| {
10178            this.buffer.update(cx, |buffer, cx| {
10179                buffer.edit(edits, None, cx);
10180            });
10181
10182            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10183                s.select(new_selections);
10184            });
10185
10186            this.request_autoscroll(Autoscroll::fit(), cx);
10187        });
10188    }
10189
10190    pub fn duplicate(
10191        &mut self,
10192        upwards: bool,
10193        whole_lines: bool,
10194        window: &mut Window,
10195        cx: &mut Context<Self>,
10196    ) {
10197        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10198
10199        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10200        let buffer = &display_map.buffer_snapshot;
10201        let selections = self.selections.all::<Point>(cx);
10202
10203        let mut edits = Vec::new();
10204        let mut selections_iter = selections.iter().peekable();
10205        while let Some(selection) = selections_iter.next() {
10206            let mut rows = selection.spanned_rows(false, &display_map);
10207            // duplicate line-wise
10208            if whole_lines || selection.start == selection.end {
10209                // Avoid duplicating the same lines twice.
10210                while let Some(next_selection) = selections_iter.peek() {
10211                    let next_rows = next_selection.spanned_rows(false, &display_map);
10212                    if next_rows.start < rows.end {
10213                        rows.end = next_rows.end;
10214                        selections_iter.next().unwrap();
10215                    } else {
10216                        break;
10217                    }
10218                }
10219
10220                // Copy the text from the selected row region and splice it either at the start
10221                // or end of the region.
10222                let start = Point::new(rows.start.0, 0);
10223                let end = Point::new(
10224                    rows.end.previous_row().0,
10225                    buffer.line_len(rows.end.previous_row()),
10226                );
10227                let text = buffer
10228                    .text_for_range(start..end)
10229                    .chain(Some("\n"))
10230                    .collect::<String>();
10231                let insert_location = if upwards {
10232                    Point::new(rows.end.0, 0)
10233                } else {
10234                    start
10235                };
10236                edits.push((insert_location..insert_location, text));
10237            } else {
10238                // duplicate character-wise
10239                let start = selection.start;
10240                let end = selection.end;
10241                let text = buffer.text_for_range(start..end).collect::<String>();
10242                edits.push((selection.end..selection.end, text));
10243            }
10244        }
10245
10246        self.transact(window, cx, |this, _, cx| {
10247            this.buffer.update(cx, |buffer, cx| {
10248                buffer.edit(edits, None, cx);
10249            });
10250
10251            this.request_autoscroll(Autoscroll::fit(), cx);
10252        });
10253    }
10254
10255    pub fn duplicate_line_up(
10256        &mut self,
10257        _: &DuplicateLineUp,
10258        window: &mut Window,
10259        cx: &mut Context<Self>,
10260    ) {
10261        self.duplicate(true, true, window, cx);
10262    }
10263
10264    pub fn duplicate_line_down(
10265        &mut self,
10266        _: &DuplicateLineDown,
10267        window: &mut Window,
10268        cx: &mut Context<Self>,
10269    ) {
10270        self.duplicate(false, true, window, cx);
10271    }
10272
10273    pub fn duplicate_selection(
10274        &mut self,
10275        _: &DuplicateSelection,
10276        window: &mut Window,
10277        cx: &mut Context<Self>,
10278    ) {
10279        self.duplicate(false, false, window, cx);
10280    }
10281
10282    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10283        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10284
10285        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10286        let buffer = self.buffer.read(cx).snapshot(cx);
10287
10288        let mut edits = Vec::new();
10289        let mut unfold_ranges = Vec::new();
10290        let mut refold_creases = Vec::new();
10291
10292        let selections = self.selections.all::<Point>(cx);
10293        let mut selections = selections.iter().peekable();
10294        let mut contiguous_row_selections = Vec::new();
10295        let mut new_selections = Vec::new();
10296
10297        while let Some(selection) = selections.next() {
10298            // Find all the selections that span a contiguous row range
10299            let (start_row, end_row) = consume_contiguous_rows(
10300                &mut contiguous_row_selections,
10301                selection,
10302                &display_map,
10303                &mut selections,
10304            );
10305
10306            // Move the text spanned by the row range to be before the line preceding the row range
10307            if start_row.0 > 0 {
10308                let range_to_move = Point::new(
10309                    start_row.previous_row().0,
10310                    buffer.line_len(start_row.previous_row()),
10311                )
10312                    ..Point::new(
10313                        end_row.previous_row().0,
10314                        buffer.line_len(end_row.previous_row()),
10315                    );
10316                let insertion_point = display_map
10317                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10318                    .0;
10319
10320                // Don't move lines across excerpts
10321                if buffer
10322                    .excerpt_containing(insertion_point..range_to_move.end)
10323                    .is_some()
10324                {
10325                    let text = buffer
10326                        .text_for_range(range_to_move.clone())
10327                        .flat_map(|s| s.chars())
10328                        .skip(1)
10329                        .chain(['\n'])
10330                        .collect::<String>();
10331
10332                    edits.push((
10333                        buffer.anchor_after(range_to_move.start)
10334                            ..buffer.anchor_before(range_to_move.end),
10335                        String::new(),
10336                    ));
10337                    let insertion_anchor = buffer.anchor_after(insertion_point);
10338                    edits.push((insertion_anchor..insertion_anchor, text));
10339
10340                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10341
10342                    // Move selections up
10343                    new_selections.extend(contiguous_row_selections.drain(..).map(
10344                        |mut selection| {
10345                            selection.start.row -= row_delta;
10346                            selection.end.row -= row_delta;
10347                            selection
10348                        },
10349                    ));
10350
10351                    // Move folds up
10352                    unfold_ranges.push(range_to_move.clone());
10353                    for fold in display_map.folds_in_range(
10354                        buffer.anchor_before(range_to_move.start)
10355                            ..buffer.anchor_after(range_to_move.end),
10356                    ) {
10357                        let mut start = fold.range.start.to_point(&buffer);
10358                        let mut end = fold.range.end.to_point(&buffer);
10359                        start.row -= row_delta;
10360                        end.row -= row_delta;
10361                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10362                    }
10363                }
10364            }
10365
10366            // If we didn't move line(s), preserve the existing selections
10367            new_selections.append(&mut contiguous_row_selections);
10368        }
10369
10370        self.transact(window, cx, |this, window, cx| {
10371            this.unfold_ranges(&unfold_ranges, true, true, cx);
10372            this.buffer.update(cx, |buffer, cx| {
10373                for (range, text) in edits {
10374                    buffer.edit([(range, text)], None, cx);
10375                }
10376            });
10377            this.fold_creases(refold_creases, true, window, cx);
10378            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10379                s.select(new_selections);
10380            })
10381        });
10382    }
10383
10384    pub fn move_line_down(
10385        &mut self,
10386        _: &MoveLineDown,
10387        window: &mut Window,
10388        cx: &mut Context<Self>,
10389    ) {
10390        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10391
10392        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10393        let buffer = self.buffer.read(cx).snapshot(cx);
10394
10395        let mut edits = Vec::new();
10396        let mut unfold_ranges = Vec::new();
10397        let mut refold_creases = Vec::new();
10398
10399        let selections = self.selections.all::<Point>(cx);
10400        let mut selections = selections.iter().peekable();
10401        let mut contiguous_row_selections = Vec::new();
10402        let mut new_selections = Vec::new();
10403
10404        while let Some(selection) = selections.next() {
10405            // Find all the selections that span a contiguous row range
10406            let (start_row, end_row) = consume_contiguous_rows(
10407                &mut contiguous_row_selections,
10408                selection,
10409                &display_map,
10410                &mut selections,
10411            );
10412
10413            // Move the text spanned by the row range to be after the last line of the row range
10414            if end_row.0 <= buffer.max_point().row {
10415                let range_to_move =
10416                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10417                let insertion_point = display_map
10418                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10419                    .0;
10420
10421                // Don't move lines across excerpt boundaries
10422                if buffer
10423                    .excerpt_containing(range_to_move.start..insertion_point)
10424                    .is_some()
10425                {
10426                    let mut text = String::from("\n");
10427                    text.extend(buffer.text_for_range(range_to_move.clone()));
10428                    text.pop(); // Drop trailing newline
10429                    edits.push((
10430                        buffer.anchor_after(range_to_move.start)
10431                            ..buffer.anchor_before(range_to_move.end),
10432                        String::new(),
10433                    ));
10434                    let insertion_anchor = buffer.anchor_after(insertion_point);
10435                    edits.push((insertion_anchor..insertion_anchor, text));
10436
10437                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10438
10439                    // Move selections down
10440                    new_selections.extend(contiguous_row_selections.drain(..).map(
10441                        |mut selection| {
10442                            selection.start.row += row_delta;
10443                            selection.end.row += row_delta;
10444                            selection
10445                        },
10446                    ));
10447
10448                    // Move folds down
10449                    unfold_ranges.push(range_to_move.clone());
10450                    for fold in display_map.folds_in_range(
10451                        buffer.anchor_before(range_to_move.start)
10452                            ..buffer.anchor_after(range_to_move.end),
10453                    ) {
10454                        let mut start = fold.range.start.to_point(&buffer);
10455                        let mut end = fold.range.end.to_point(&buffer);
10456                        start.row += row_delta;
10457                        end.row += row_delta;
10458                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10459                    }
10460                }
10461            }
10462
10463            // If we didn't move line(s), preserve the existing selections
10464            new_selections.append(&mut contiguous_row_selections);
10465        }
10466
10467        self.transact(window, cx, |this, window, cx| {
10468            this.unfold_ranges(&unfold_ranges, true, true, cx);
10469            this.buffer.update(cx, |buffer, cx| {
10470                for (range, text) in edits {
10471                    buffer.edit([(range, text)], None, cx);
10472                }
10473            });
10474            this.fold_creases(refold_creases, true, window, cx);
10475            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10476                s.select(new_selections)
10477            });
10478        });
10479    }
10480
10481    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10482        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10483        let text_layout_details = &self.text_layout_details(window);
10484        self.transact(window, cx, |this, window, cx| {
10485            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10486                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10487                s.move_with(|display_map, selection| {
10488                    if !selection.is_empty() {
10489                        return;
10490                    }
10491
10492                    let mut head = selection.head();
10493                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10494                    if head.column() == display_map.line_len(head.row()) {
10495                        transpose_offset = display_map
10496                            .buffer_snapshot
10497                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10498                    }
10499
10500                    if transpose_offset == 0 {
10501                        return;
10502                    }
10503
10504                    *head.column_mut() += 1;
10505                    head = display_map.clip_point(head, Bias::Right);
10506                    let goal = SelectionGoal::HorizontalPosition(
10507                        display_map
10508                            .x_for_display_point(head, text_layout_details)
10509                            .into(),
10510                    );
10511                    selection.collapse_to(head, goal);
10512
10513                    let transpose_start = display_map
10514                        .buffer_snapshot
10515                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10516                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10517                        let transpose_end = display_map
10518                            .buffer_snapshot
10519                            .clip_offset(transpose_offset + 1, Bias::Right);
10520                        if let Some(ch) =
10521                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10522                        {
10523                            edits.push((transpose_start..transpose_offset, String::new()));
10524                            edits.push((transpose_end..transpose_end, ch.to_string()));
10525                        }
10526                    }
10527                });
10528                edits
10529            });
10530            this.buffer
10531                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10532            let selections = this.selections.all::<usize>(cx);
10533            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10534                s.select(selections);
10535            });
10536        });
10537    }
10538
10539    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10540        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10541        self.rewrap_impl(RewrapOptions::default(), cx)
10542    }
10543
10544    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10545        let buffer = self.buffer.read(cx).snapshot(cx);
10546        let selections = self.selections.all::<Point>(cx);
10547        let mut selections = selections.iter().peekable();
10548
10549        let mut edits = Vec::new();
10550        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10551
10552        while let Some(selection) = selections.next() {
10553            let mut start_row = selection.start.row;
10554            let mut end_row = selection.end.row;
10555
10556            // Skip selections that overlap with a range that has already been rewrapped.
10557            let selection_range = start_row..end_row;
10558            if rewrapped_row_ranges
10559                .iter()
10560                .any(|range| range.overlaps(&selection_range))
10561            {
10562                continue;
10563            }
10564
10565            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10566
10567            // Since not all lines in the selection may be at the same indent
10568            // level, choose the indent size that is the most common between all
10569            // of the lines.
10570            //
10571            // If there is a tie, we use the deepest indent.
10572            let (indent_size, indent_end) = {
10573                let mut indent_size_occurrences = HashMap::default();
10574                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10575
10576                for row in start_row..=end_row {
10577                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10578                    rows_by_indent_size.entry(indent).or_default().push(row);
10579                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10580                }
10581
10582                let indent_size = indent_size_occurrences
10583                    .into_iter()
10584                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10585                    .map(|(indent, _)| indent)
10586                    .unwrap_or_default();
10587                let row = rows_by_indent_size[&indent_size][0];
10588                let indent_end = Point::new(row, indent_size.len);
10589
10590                (indent_size, indent_end)
10591            };
10592
10593            let mut line_prefix = indent_size.chars().collect::<String>();
10594
10595            let mut inside_comment = false;
10596            if let Some(comment_prefix) =
10597                buffer
10598                    .language_scope_at(selection.head())
10599                    .and_then(|language| {
10600                        language
10601                            .line_comment_prefixes()
10602                            .iter()
10603                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10604                            .cloned()
10605                    })
10606            {
10607                line_prefix.push_str(&comment_prefix);
10608                inside_comment = true;
10609            }
10610
10611            let language_settings = buffer.language_settings_at(selection.head(), cx);
10612            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10613                RewrapBehavior::InComments => inside_comment,
10614                RewrapBehavior::InSelections => !selection.is_empty(),
10615                RewrapBehavior::Anywhere => true,
10616            };
10617
10618            let should_rewrap = options.override_language_settings
10619                || allow_rewrap_based_on_language
10620                || self.hard_wrap.is_some();
10621            if !should_rewrap {
10622                continue;
10623            }
10624
10625            if selection.is_empty() {
10626                'expand_upwards: while start_row > 0 {
10627                    let prev_row = start_row - 1;
10628                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10629                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10630                    {
10631                        start_row = prev_row;
10632                    } else {
10633                        break 'expand_upwards;
10634                    }
10635                }
10636
10637                'expand_downwards: while end_row < buffer.max_point().row {
10638                    let next_row = end_row + 1;
10639                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10640                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10641                    {
10642                        end_row = next_row;
10643                    } else {
10644                        break 'expand_downwards;
10645                    }
10646                }
10647            }
10648
10649            let start = Point::new(start_row, 0);
10650            let start_offset = start.to_offset(&buffer);
10651            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10652            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10653            let Some(lines_without_prefixes) = selection_text
10654                .lines()
10655                .map(|line| {
10656                    line.strip_prefix(&line_prefix)
10657                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10658                        .with_context(|| {
10659                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10660                        })
10661                })
10662                .collect::<Result<Vec<_>, _>>()
10663                .log_err()
10664            else {
10665                continue;
10666            };
10667
10668            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10669                buffer
10670                    .language_settings_at(Point::new(start_row, 0), cx)
10671                    .preferred_line_length as usize
10672            });
10673            let wrapped_text = wrap_with_prefix(
10674                line_prefix,
10675                lines_without_prefixes.join("\n"),
10676                wrap_column,
10677                tab_size,
10678                options.preserve_existing_whitespace,
10679            );
10680
10681            // TODO: should always use char-based diff while still supporting cursor behavior that
10682            // matches vim.
10683            let mut diff_options = DiffOptions::default();
10684            if options.override_language_settings {
10685                diff_options.max_word_diff_len = 0;
10686                diff_options.max_word_diff_line_count = 0;
10687            } else {
10688                diff_options.max_word_diff_len = usize::MAX;
10689                diff_options.max_word_diff_line_count = usize::MAX;
10690            }
10691
10692            for (old_range, new_text) in
10693                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10694            {
10695                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10696                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10697                edits.push((edit_start..edit_end, new_text));
10698            }
10699
10700            rewrapped_row_ranges.push(start_row..=end_row);
10701        }
10702
10703        self.buffer
10704            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10705    }
10706
10707    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10708        let mut text = String::new();
10709        let buffer = self.buffer.read(cx).snapshot(cx);
10710        let mut selections = self.selections.all::<Point>(cx);
10711        let mut clipboard_selections = Vec::with_capacity(selections.len());
10712        {
10713            let max_point = buffer.max_point();
10714            let mut is_first = true;
10715            for selection in &mut selections {
10716                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10717                if is_entire_line {
10718                    selection.start = Point::new(selection.start.row, 0);
10719                    if !selection.is_empty() && selection.end.column == 0 {
10720                        selection.end = cmp::min(max_point, selection.end);
10721                    } else {
10722                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10723                    }
10724                    selection.goal = SelectionGoal::None;
10725                }
10726                if is_first {
10727                    is_first = false;
10728                } else {
10729                    text += "\n";
10730                }
10731                let mut len = 0;
10732                for chunk in buffer.text_for_range(selection.start..selection.end) {
10733                    text.push_str(chunk);
10734                    len += chunk.len();
10735                }
10736                clipboard_selections.push(ClipboardSelection {
10737                    len,
10738                    is_entire_line,
10739                    first_line_indent: buffer
10740                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10741                        .len,
10742                });
10743            }
10744        }
10745
10746        self.transact(window, cx, |this, window, cx| {
10747            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10748                s.select(selections);
10749            });
10750            this.insert("", window, cx);
10751        });
10752        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10753    }
10754
10755    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10756        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10757        let item = self.cut_common(window, cx);
10758        cx.write_to_clipboard(item);
10759    }
10760
10761    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10762        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10763        self.change_selections(None, window, cx, |s| {
10764            s.move_with(|snapshot, sel| {
10765                if sel.is_empty() {
10766                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10767                }
10768            });
10769        });
10770        let item = self.cut_common(window, cx);
10771        cx.set_global(KillRing(item))
10772    }
10773
10774    pub fn kill_ring_yank(
10775        &mut self,
10776        _: &KillRingYank,
10777        window: &mut Window,
10778        cx: &mut Context<Self>,
10779    ) {
10780        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10781        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10782            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10783                (kill_ring.text().to_string(), kill_ring.metadata_json())
10784            } else {
10785                return;
10786            }
10787        } else {
10788            return;
10789        };
10790        self.do_paste(&text, metadata, false, window, cx);
10791    }
10792
10793    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10794        self.do_copy(true, cx);
10795    }
10796
10797    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10798        self.do_copy(false, cx);
10799    }
10800
10801    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10802        let selections = self.selections.all::<Point>(cx);
10803        let buffer = self.buffer.read(cx).read(cx);
10804        let mut text = String::new();
10805
10806        let mut clipboard_selections = Vec::with_capacity(selections.len());
10807        {
10808            let max_point = buffer.max_point();
10809            let mut is_first = true;
10810            for selection in &selections {
10811                let mut start = selection.start;
10812                let mut end = selection.end;
10813                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10814                if is_entire_line {
10815                    start = Point::new(start.row, 0);
10816                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10817                }
10818
10819                let mut trimmed_selections = Vec::new();
10820                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10821                    let row = MultiBufferRow(start.row);
10822                    let first_indent = buffer.indent_size_for_line(row);
10823                    if first_indent.len == 0 || start.column > first_indent.len {
10824                        trimmed_selections.push(start..end);
10825                    } else {
10826                        trimmed_selections.push(
10827                            Point::new(row.0, first_indent.len)
10828                                ..Point::new(row.0, buffer.line_len(row)),
10829                        );
10830                        for row in start.row + 1..=end.row {
10831                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10832                            if row == end.row {
10833                                line_len = end.column;
10834                            }
10835                            if line_len == 0 {
10836                                trimmed_selections
10837                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10838                                continue;
10839                            }
10840                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10841                            if row_indent_size.len >= first_indent.len {
10842                                trimmed_selections.push(
10843                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10844                                );
10845                            } else {
10846                                trimmed_selections.clear();
10847                                trimmed_selections.push(start..end);
10848                                break;
10849                            }
10850                        }
10851                    }
10852                } else {
10853                    trimmed_selections.push(start..end);
10854                }
10855
10856                for trimmed_range in trimmed_selections {
10857                    if is_first {
10858                        is_first = false;
10859                    } else {
10860                        text += "\n";
10861                    }
10862                    let mut len = 0;
10863                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10864                        text.push_str(chunk);
10865                        len += chunk.len();
10866                    }
10867                    clipboard_selections.push(ClipboardSelection {
10868                        len,
10869                        is_entire_line,
10870                        first_line_indent: buffer
10871                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10872                            .len,
10873                    });
10874                }
10875            }
10876        }
10877
10878        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10879            text,
10880            clipboard_selections,
10881        ));
10882    }
10883
10884    pub fn do_paste(
10885        &mut self,
10886        text: &String,
10887        clipboard_selections: Option<Vec<ClipboardSelection>>,
10888        handle_entire_lines: bool,
10889        window: &mut Window,
10890        cx: &mut Context<Self>,
10891    ) {
10892        if self.read_only(cx) {
10893            return;
10894        }
10895
10896        let clipboard_text = Cow::Borrowed(text);
10897
10898        self.transact(window, cx, |this, window, cx| {
10899            if let Some(mut clipboard_selections) = clipboard_selections {
10900                let old_selections = this.selections.all::<usize>(cx);
10901                let all_selections_were_entire_line =
10902                    clipboard_selections.iter().all(|s| s.is_entire_line);
10903                let first_selection_indent_column =
10904                    clipboard_selections.first().map(|s| s.first_line_indent);
10905                if clipboard_selections.len() != old_selections.len() {
10906                    clipboard_selections.drain(..);
10907                }
10908                let cursor_offset = this.selections.last::<usize>(cx).head();
10909                let mut auto_indent_on_paste = true;
10910
10911                this.buffer.update(cx, |buffer, cx| {
10912                    let snapshot = buffer.read(cx);
10913                    auto_indent_on_paste = snapshot
10914                        .language_settings_at(cursor_offset, cx)
10915                        .auto_indent_on_paste;
10916
10917                    let mut start_offset = 0;
10918                    let mut edits = Vec::new();
10919                    let mut original_indent_columns = Vec::new();
10920                    for (ix, selection) in old_selections.iter().enumerate() {
10921                        let to_insert;
10922                        let entire_line;
10923                        let original_indent_column;
10924                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10925                            let end_offset = start_offset + clipboard_selection.len;
10926                            to_insert = &clipboard_text[start_offset..end_offset];
10927                            entire_line = clipboard_selection.is_entire_line;
10928                            start_offset = end_offset + 1;
10929                            original_indent_column = Some(clipboard_selection.first_line_indent);
10930                        } else {
10931                            to_insert = clipboard_text.as_str();
10932                            entire_line = all_selections_were_entire_line;
10933                            original_indent_column = first_selection_indent_column
10934                        }
10935
10936                        // If the corresponding selection was empty when this slice of the
10937                        // clipboard text was written, then the entire line containing the
10938                        // selection was copied. If this selection is also currently empty,
10939                        // then paste the line before the current line of the buffer.
10940                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10941                            let column = selection.start.to_point(&snapshot).column as usize;
10942                            let line_start = selection.start - column;
10943                            line_start..line_start
10944                        } else {
10945                            selection.range()
10946                        };
10947
10948                        edits.push((range, to_insert));
10949                        original_indent_columns.push(original_indent_column);
10950                    }
10951                    drop(snapshot);
10952
10953                    buffer.edit(
10954                        edits,
10955                        if auto_indent_on_paste {
10956                            Some(AutoindentMode::Block {
10957                                original_indent_columns,
10958                            })
10959                        } else {
10960                            None
10961                        },
10962                        cx,
10963                    );
10964                });
10965
10966                let selections = this.selections.all::<usize>(cx);
10967                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10968                    s.select(selections)
10969                });
10970            } else {
10971                this.insert(&clipboard_text, window, cx);
10972            }
10973        });
10974    }
10975
10976    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10977        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10978        if let Some(item) = cx.read_from_clipboard() {
10979            let entries = item.entries();
10980
10981            match entries.first() {
10982                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10983                // of all the pasted entries.
10984                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10985                    .do_paste(
10986                        clipboard_string.text(),
10987                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10988                        true,
10989                        window,
10990                        cx,
10991                    ),
10992                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10993            }
10994        }
10995    }
10996
10997    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10998        if self.read_only(cx) {
10999            return;
11000        }
11001
11002        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11003
11004        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11005            if let Some((selections, _)) =
11006                self.selection_history.transaction(transaction_id).cloned()
11007            {
11008                self.change_selections(None, window, cx, |s| {
11009                    s.select_anchors(selections.to_vec());
11010                });
11011            } else {
11012                log::error!(
11013                    "No entry in selection_history found for undo. \
11014                     This may correspond to a bug where undo does not update the selection. \
11015                     If this is occurring, please add details to \
11016                     https://github.com/zed-industries/zed/issues/22692"
11017                );
11018            }
11019            self.request_autoscroll(Autoscroll::fit(), cx);
11020            self.unmark_text(window, cx);
11021            self.refresh_inline_completion(true, false, window, cx);
11022            cx.emit(EditorEvent::Edited { transaction_id });
11023            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11024        }
11025    }
11026
11027    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11028        if self.read_only(cx) {
11029            return;
11030        }
11031
11032        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11033
11034        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11035            if let Some((_, Some(selections))) =
11036                self.selection_history.transaction(transaction_id).cloned()
11037            {
11038                self.change_selections(None, window, cx, |s| {
11039                    s.select_anchors(selections.to_vec());
11040                });
11041            } else {
11042                log::error!(
11043                    "No entry in selection_history found for redo. \
11044                     This may correspond to a bug where undo does not update the selection. \
11045                     If this is occurring, please add details to \
11046                     https://github.com/zed-industries/zed/issues/22692"
11047                );
11048            }
11049            self.request_autoscroll(Autoscroll::fit(), cx);
11050            self.unmark_text(window, cx);
11051            self.refresh_inline_completion(true, false, window, cx);
11052            cx.emit(EditorEvent::Edited { transaction_id });
11053        }
11054    }
11055
11056    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11057        self.buffer
11058            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11059    }
11060
11061    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11062        self.buffer
11063            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11064    }
11065
11066    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11067        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11068        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11069            s.move_with(|map, selection| {
11070                let cursor = if selection.is_empty() {
11071                    movement::left(map, selection.start)
11072                } else {
11073                    selection.start
11074                };
11075                selection.collapse_to(cursor, SelectionGoal::None);
11076            });
11077        })
11078    }
11079
11080    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11081        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11082        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11083            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11084        })
11085    }
11086
11087    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11088        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11089        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11090            s.move_with(|map, selection| {
11091                let cursor = if selection.is_empty() {
11092                    movement::right(map, selection.end)
11093                } else {
11094                    selection.end
11095                };
11096                selection.collapse_to(cursor, SelectionGoal::None)
11097            });
11098        })
11099    }
11100
11101    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11102        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11103        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11104            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11105        })
11106    }
11107
11108    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11109        if self.take_rename(true, window, cx).is_some() {
11110            return;
11111        }
11112
11113        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11114            cx.propagate();
11115            return;
11116        }
11117
11118        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11119
11120        let text_layout_details = &self.text_layout_details(window);
11121        let selection_count = self.selections.count();
11122        let first_selection = self.selections.first_anchor();
11123
11124        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11125            s.move_with(|map, selection| {
11126                if !selection.is_empty() {
11127                    selection.goal = SelectionGoal::None;
11128                }
11129                let (cursor, goal) = movement::up(
11130                    map,
11131                    selection.start,
11132                    selection.goal,
11133                    false,
11134                    text_layout_details,
11135                );
11136                selection.collapse_to(cursor, goal);
11137            });
11138        });
11139
11140        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11141        {
11142            cx.propagate();
11143        }
11144    }
11145
11146    pub fn move_up_by_lines(
11147        &mut self,
11148        action: &MoveUpByLines,
11149        window: &mut Window,
11150        cx: &mut Context<Self>,
11151    ) {
11152        if self.take_rename(true, window, cx).is_some() {
11153            return;
11154        }
11155
11156        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11157            cx.propagate();
11158            return;
11159        }
11160
11161        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11162
11163        let text_layout_details = &self.text_layout_details(window);
11164
11165        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11166            s.move_with(|map, selection| {
11167                if !selection.is_empty() {
11168                    selection.goal = SelectionGoal::None;
11169                }
11170                let (cursor, goal) = movement::up_by_rows(
11171                    map,
11172                    selection.start,
11173                    action.lines,
11174                    selection.goal,
11175                    false,
11176                    text_layout_details,
11177                );
11178                selection.collapse_to(cursor, goal);
11179            });
11180        })
11181    }
11182
11183    pub fn move_down_by_lines(
11184        &mut self,
11185        action: &MoveDownByLines,
11186        window: &mut Window,
11187        cx: &mut Context<Self>,
11188    ) {
11189        if self.take_rename(true, window, cx).is_some() {
11190            return;
11191        }
11192
11193        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11194            cx.propagate();
11195            return;
11196        }
11197
11198        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11199
11200        let text_layout_details = &self.text_layout_details(window);
11201
11202        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11203            s.move_with(|map, selection| {
11204                if !selection.is_empty() {
11205                    selection.goal = SelectionGoal::None;
11206                }
11207                let (cursor, goal) = movement::down_by_rows(
11208                    map,
11209                    selection.start,
11210                    action.lines,
11211                    selection.goal,
11212                    false,
11213                    text_layout_details,
11214                );
11215                selection.collapse_to(cursor, goal);
11216            });
11217        })
11218    }
11219
11220    pub fn select_down_by_lines(
11221        &mut self,
11222        action: &SelectDownByLines,
11223        window: &mut Window,
11224        cx: &mut Context<Self>,
11225    ) {
11226        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11227        let text_layout_details = &self.text_layout_details(window);
11228        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11229            s.move_heads_with(|map, head, goal| {
11230                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11231            })
11232        })
11233    }
11234
11235    pub fn select_up_by_lines(
11236        &mut self,
11237        action: &SelectUpByLines,
11238        window: &mut Window,
11239        cx: &mut Context<Self>,
11240    ) {
11241        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11242        let text_layout_details = &self.text_layout_details(window);
11243        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11244            s.move_heads_with(|map, head, goal| {
11245                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11246            })
11247        })
11248    }
11249
11250    pub fn select_page_up(
11251        &mut self,
11252        _: &SelectPageUp,
11253        window: &mut Window,
11254        cx: &mut Context<Self>,
11255    ) {
11256        let Some(row_count) = self.visible_row_count() else {
11257            return;
11258        };
11259
11260        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11261
11262        let text_layout_details = &self.text_layout_details(window);
11263
11264        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11265            s.move_heads_with(|map, head, goal| {
11266                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11267            })
11268        })
11269    }
11270
11271    pub fn move_page_up(
11272        &mut self,
11273        action: &MovePageUp,
11274        window: &mut Window,
11275        cx: &mut Context<Self>,
11276    ) {
11277        if self.take_rename(true, window, cx).is_some() {
11278            return;
11279        }
11280
11281        if self
11282            .context_menu
11283            .borrow_mut()
11284            .as_mut()
11285            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11286            .unwrap_or(false)
11287        {
11288            return;
11289        }
11290
11291        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11292            cx.propagate();
11293            return;
11294        }
11295
11296        let Some(row_count) = self.visible_row_count() else {
11297            return;
11298        };
11299
11300        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11301
11302        let autoscroll = if action.center_cursor {
11303            Autoscroll::center()
11304        } else {
11305            Autoscroll::fit()
11306        };
11307
11308        let text_layout_details = &self.text_layout_details(window);
11309
11310        self.change_selections(Some(autoscroll), window, cx, |s| {
11311            s.move_with(|map, selection| {
11312                if !selection.is_empty() {
11313                    selection.goal = SelectionGoal::None;
11314                }
11315                let (cursor, goal) = movement::up_by_rows(
11316                    map,
11317                    selection.end,
11318                    row_count,
11319                    selection.goal,
11320                    false,
11321                    text_layout_details,
11322                );
11323                selection.collapse_to(cursor, goal);
11324            });
11325        });
11326    }
11327
11328    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11329        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11330        let text_layout_details = &self.text_layout_details(window);
11331        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11332            s.move_heads_with(|map, head, goal| {
11333                movement::up(map, head, goal, false, text_layout_details)
11334            })
11335        })
11336    }
11337
11338    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11339        self.take_rename(true, window, cx);
11340
11341        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11342            cx.propagate();
11343            return;
11344        }
11345
11346        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11347
11348        let text_layout_details = &self.text_layout_details(window);
11349        let selection_count = self.selections.count();
11350        let first_selection = self.selections.first_anchor();
11351
11352        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11353            s.move_with(|map, selection| {
11354                if !selection.is_empty() {
11355                    selection.goal = SelectionGoal::None;
11356                }
11357                let (cursor, goal) = movement::down(
11358                    map,
11359                    selection.end,
11360                    selection.goal,
11361                    false,
11362                    text_layout_details,
11363                );
11364                selection.collapse_to(cursor, goal);
11365            });
11366        });
11367
11368        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11369        {
11370            cx.propagate();
11371        }
11372    }
11373
11374    pub fn select_page_down(
11375        &mut self,
11376        _: &SelectPageDown,
11377        window: &mut Window,
11378        cx: &mut Context<Self>,
11379    ) {
11380        let Some(row_count) = self.visible_row_count() else {
11381            return;
11382        };
11383
11384        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11385
11386        let text_layout_details = &self.text_layout_details(window);
11387
11388        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11389            s.move_heads_with(|map, head, goal| {
11390                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11391            })
11392        })
11393    }
11394
11395    pub fn move_page_down(
11396        &mut self,
11397        action: &MovePageDown,
11398        window: &mut Window,
11399        cx: &mut Context<Self>,
11400    ) {
11401        if self.take_rename(true, window, cx).is_some() {
11402            return;
11403        }
11404
11405        if self
11406            .context_menu
11407            .borrow_mut()
11408            .as_mut()
11409            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11410            .unwrap_or(false)
11411        {
11412            return;
11413        }
11414
11415        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11416            cx.propagate();
11417            return;
11418        }
11419
11420        let Some(row_count) = self.visible_row_count() else {
11421            return;
11422        };
11423
11424        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11425
11426        let autoscroll = if action.center_cursor {
11427            Autoscroll::center()
11428        } else {
11429            Autoscroll::fit()
11430        };
11431
11432        let text_layout_details = &self.text_layout_details(window);
11433        self.change_selections(Some(autoscroll), window, cx, |s| {
11434            s.move_with(|map, selection| {
11435                if !selection.is_empty() {
11436                    selection.goal = SelectionGoal::None;
11437                }
11438                let (cursor, goal) = movement::down_by_rows(
11439                    map,
11440                    selection.end,
11441                    row_count,
11442                    selection.goal,
11443                    false,
11444                    text_layout_details,
11445                );
11446                selection.collapse_to(cursor, goal);
11447            });
11448        });
11449    }
11450
11451    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11452        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11453        let text_layout_details = &self.text_layout_details(window);
11454        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11455            s.move_heads_with(|map, head, goal| {
11456                movement::down(map, head, goal, false, text_layout_details)
11457            })
11458        });
11459    }
11460
11461    pub fn context_menu_first(
11462        &mut self,
11463        _: &ContextMenuFirst,
11464        _window: &mut Window,
11465        cx: &mut Context<Self>,
11466    ) {
11467        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11468            context_menu.select_first(self.completion_provider.as_deref(), cx);
11469        }
11470    }
11471
11472    pub fn context_menu_prev(
11473        &mut self,
11474        _: &ContextMenuPrevious,
11475        _window: &mut Window,
11476        cx: &mut Context<Self>,
11477    ) {
11478        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11479            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11480        }
11481    }
11482
11483    pub fn context_menu_next(
11484        &mut self,
11485        _: &ContextMenuNext,
11486        _window: &mut Window,
11487        cx: &mut Context<Self>,
11488    ) {
11489        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11490            context_menu.select_next(self.completion_provider.as_deref(), cx);
11491        }
11492    }
11493
11494    pub fn context_menu_last(
11495        &mut self,
11496        _: &ContextMenuLast,
11497        _window: &mut Window,
11498        cx: &mut Context<Self>,
11499    ) {
11500        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11501            context_menu.select_last(self.completion_provider.as_deref(), cx);
11502        }
11503    }
11504
11505    pub fn move_to_previous_word_start(
11506        &mut self,
11507        _: &MoveToPreviousWordStart,
11508        window: &mut Window,
11509        cx: &mut Context<Self>,
11510    ) {
11511        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11512        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11513            s.move_cursors_with(|map, head, _| {
11514                (
11515                    movement::previous_word_start(map, head),
11516                    SelectionGoal::None,
11517                )
11518            });
11519        })
11520    }
11521
11522    pub fn move_to_previous_subword_start(
11523        &mut self,
11524        _: &MoveToPreviousSubwordStart,
11525        window: &mut Window,
11526        cx: &mut Context<Self>,
11527    ) {
11528        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11529        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11530            s.move_cursors_with(|map, head, _| {
11531                (
11532                    movement::previous_subword_start(map, head),
11533                    SelectionGoal::None,
11534                )
11535            });
11536        })
11537    }
11538
11539    pub fn select_to_previous_word_start(
11540        &mut self,
11541        _: &SelectToPreviousWordStart,
11542        window: &mut Window,
11543        cx: &mut Context<Self>,
11544    ) {
11545        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11546        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11547            s.move_heads_with(|map, head, _| {
11548                (
11549                    movement::previous_word_start(map, head),
11550                    SelectionGoal::None,
11551                )
11552            });
11553        })
11554    }
11555
11556    pub fn select_to_previous_subword_start(
11557        &mut self,
11558        _: &SelectToPreviousSubwordStart,
11559        window: &mut Window,
11560        cx: &mut Context<Self>,
11561    ) {
11562        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11563        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11564            s.move_heads_with(|map, head, _| {
11565                (
11566                    movement::previous_subword_start(map, head),
11567                    SelectionGoal::None,
11568                )
11569            });
11570        })
11571    }
11572
11573    pub fn delete_to_previous_word_start(
11574        &mut self,
11575        action: &DeleteToPreviousWordStart,
11576        window: &mut Window,
11577        cx: &mut Context<Self>,
11578    ) {
11579        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11580        self.transact(window, cx, |this, window, cx| {
11581            this.select_autoclose_pair(window, cx);
11582            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11583                s.move_with(|map, selection| {
11584                    if selection.is_empty() {
11585                        let cursor = if action.ignore_newlines {
11586                            movement::previous_word_start(map, selection.head())
11587                        } else {
11588                            movement::previous_word_start_or_newline(map, selection.head())
11589                        };
11590                        selection.set_head(cursor, SelectionGoal::None);
11591                    }
11592                });
11593            });
11594            this.insert("", window, cx);
11595        });
11596    }
11597
11598    pub fn delete_to_previous_subword_start(
11599        &mut self,
11600        _: &DeleteToPreviousSubwordStart,
11601        window: &mut Window,
11602        cx: &mut Context<Self>,
11603    ) {
11604        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11605        self.transact(window, cx, |this, window, cx| {
11606            this.select_autoclose_pair(window, cx);
11607            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11608                s.move_with(|map, selection| {
11609                    if selection.is_empty() {
11610                        let cursor = movement::previous_subword_start(map, selection.head());
11611                        selection.set_head(cursor, SelectionGoal::None);
11612                    }
11613                });
11614            });
11615            this.insert("", window, cx);
11616        });
11617    }
11618
11619    pub fn move_to_next_word_end(
11620        &mut self,
11621        _: &MoveToNextWordEnd,
11622        window: &mut Window,
11623        cx: &mut Context<Self>,
11624    ) {
11625        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11626        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11627            s.move_cursors_with(|map, head, _| {
11628                (movement::next_word_end(map, head), SelectionGoal::None)
11629            });
11630        })
11631    }
11632
11633    pub fn move_to_next_subword_end(
11634        &mut self,
11635        _: &MoveToNextSubwordEnd,
11636        window: &mut Window,
11637        cx: &mut Context<Self>,
11638    ) {
11639        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11640        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11641            s.move_cursors_with(|map, head, _| {
11642                (movement::next_subword_end(map, head), SelectionGoal::None)
11643            });
11644        })
11645    }
11646
11647    pub fn select_to_next_word_end(
11648        &mut self,
11649        _: &SelectToNextWordEnd,
11650        window: &mut Window,
11651        cx: &mut Context<Self>,
11652    ) {
11653        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11654        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11655            s.move_heads_with(|map, head, _| {
11656                (movement::next_word_end(map, head), SelectionGoal::None)
11657            });
11658        })
11659    }
11660
11661    pub fn select_to_next_subword_end(
11662        &mut self,
11663        _: &SelectToNextSubwordEnd,
11664        window: &mut Window,
11665        cx: &mut Context<Self>,
11666    ) {
11667        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11668        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11669            s.move_heads_with(|map, head, _| {
11670                (movement::next_subword_end(map, head), SelectionGoal::None)
11671            });
11672        })
11673    }
11674
11675    pub fn delete_to_next_word_end(
11676        &mut self,
11677        action: &DeleteToNextWordEnd,
11678        window: &mut Window,
11679        cx: &mut Context<Self>,
11680    ) {
11681        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11682        self.transact(window, cx, |this, window, cx| {
11683            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11684                s.move_with(|map, selection| {
11685                    if selection.is_empty() {
11686                        let cursor = if action.ignore_newlines {
11687                            movement::next_word_end(map, selection.head())
11688                        } else {
11689                            movement::next_word_end_or_newline(map, selection.head())
11690                        };
11691                        selection.set_head(cursor, SelectionGoal::None);
11692                    }
11693                });
11694            });
11695            this.insert("", window, cx);
11696        });
11697    }
11698
11699    pub fn delete_to_next_subword_end(
11700        &mut self,
11701        _: &DeleteToNextSubwordEnd,
11702        window: &mut Window,
11703        cx: &mut Context<Self>,
11704    ) {
11705        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11706        self.transact(window, cx, |this, window, cx| {
11707            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11708                s.move_with(|map, selection| {
11709                    if selection.is_empty() {
11710                        let cursor = movement::next_subword_end(map, selection.head());
11711                        selection.set_head(cursor, SelectionGoal::None);
11712                    }
11713                });
11714            });
11715            this.insert("", window, cx);
11716        });
11717    }
11718
11719    pub fn move_to_beginning_of_line(
11720        &mut self,
11721        action: &MoveToBeginningOfLine,
11722        window: &mut Window,
11723        cx: &mut Context<Self>,
11724    ) {
11725        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11726        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11727            s.move_cursors_with(|map, head, _| {
11728                (
11729                    movement::indented_line_beginning(
11730                        map,
11731                        head,
11732                        action.stop_at_soft_wraps,
11733                        action.stop_at_indent,
11734                    ),
11735                    SelectionGoal::None,
11736                )
11737            });
11738        })
11739    }
11740
11741    pub fn select_to_beginning_of_line(
11742        &mut self,
11743        action: &SelectToBeginningOfLine,
11744        window: &mut Window,
11745        cx: &mut Context<Self>,
11746    ) {
11747        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11748        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11749            s.move_heads_with(|map, head, _| {
11750                (
11751                    movement::indented_line_beginning(
11752                        map,
11753                        head,
11754                        action.stop_at_soft_wraps,
11755                        action.stop_at_indent,
11756                    ),
11757                    SelectionGoal::None,
11758                )
11759            });
11760        });
11761    }
11762
11763    pub fn delete_to_beginning_of_line(
11764        &mut self,
11765        action: &DeleteToBeginningOfLine,
11766        window: &mut Window,
11767        cx: &mut Context<Self>,
11768    ) {
11769        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11770        self.transact(window, cx, |this, window, cx| {
11771            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11772                s.move_with(|_, selection| {
11773                    selection.reversed = true;
11774                });
11775            });
11776
11777            this.select_to_beginning_of_line(
11778                &SelectToBeginningOfLine {
11779                    stop_at_soft_wraps: false,
11780                    stop_at_indent: action.stop_at_indent,
11781                },
11782                window,
11783                cx,
11784            );
11785            this.backspace(&Backspace, window, cx);
11786        });
11787    }
11788
11789    pub fn move_to_end_of_line(
11790        &mut self,
11791        action: &MoveToEndOfLine,
11792        window: &mut Window,
11793        cx: &mut Context<Self>,
11794    ) {
11795        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11796        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11797            s.move_cursors_with(|map, head, _| {
11798                (
11799                    movement::line_end(map, head, action.stop_at_soft_wraps),
11800                    SelectionGoal::None,
11801                )
11802            });
11803        })
11804    }
11805
11806    pub fn select_to_end_of_line(
11807        &mut self,
11808        action: &SelectToEndOfLine,
11809        window: &mut Window,
11810        cx: &mut Context<Self>,
11811    ) {
11812        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11813        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11814            s.move_heads_with(|map, head, _| {
11815                (
11816                    movement::line_end(map, head, action.stop_at_soft_wraps),
11817                    SelectionGoal::None,
11818                )
11819            });
11820        })
11821    }
11822
11823    pub fn delete_to_end_of_line(
11824        &mut self,
11825        _: &DeleteToEndOfLine,
11826        window: &mut Window,
11827        cx: &mut Context<Self>,
11828    ) {
11829        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11830        self.transact(window, cx, |this, window, cx| {
11831            this.select_to_end_of_line(
11832                &SelectToEndOfLine {
11833                    stop_at_soft_wraps: false,
11834                },
11835                window,
11836                cx,
11837            );
11838            this.delete(&Delete, window, cx);
11839        });
11840    }
11841
11842    pub fn cut_to_end_of_line(
11843        &mut self,
11844        _: &CutToEndOfLine,
11845        window: &mut Window,
11846        cx: &mut Context<Self>,
11847    ) {
11848        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11849        self.transact(window, cx, |this, window, cx| {
11850            this.select_to_end_of_line(
11851                &SelectToEndOfLine {
11852                    stop_at_soft_wraps: false,
11853                },
11854                window,
11855                cx,
11856            );
11857            this.cut(&Cut, window, cx);
11858        });
11859    }
11860
11861    pub fn move_to_start_of_paragraph(
11862        &mut self,
11863        _: &MoveToStartOfParagraph,
11864        window: &mut Window,
11865        cx: &mut Context<Self>,
11866    ) {
11867        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11868            cx.propagate();
11869            return;
11870        }
11871        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11872        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11873            s.move_with(|map, selection| {
11874                selection.collapse_to(
11875                    movement::start_of_paragraph(map, selection.head(), 1),
11876                    SelectionGoal::None,
11877                )
11878            });
11879        })
11880    }
11881
11882    pub fn move_to_end_of_paragraph(
11883        &mut self,
11884        _: &MoveToEndOfParagraph,
11885        window: &mut Window,
11886        cx: &mut Context<Self>,
11887    ) {
11888        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11889            cx.propagate();
11890            return;
11891        }
11892        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11893        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11894            s.move_with(|map, selection| {
11895                selection.collapse_to(
11896                    movement::end_of_paragraph(map, selection.head(), 1),
11897                    SelectionGoal::None,
11898                )
11899            });
11900        })
11901    }
11902
11903    pub fn select_to_start_of_paragraph(
11904        &mut self,
11905        _: &SelectToStartOfParagraph,
11906        window: &mut Window,
11907        cx: &mut Context<Self>,
11908    ) {
11909        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11910            cx.propagate();
11911            return;
11912        }
11913        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11914        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11915            s.move_heads_with(|map, head, _| {
11916                (
11917                    movement::start_of_paragraph(map, head, 1),
11918                    SelectionGoal::None,
11919                )
11920            });
11921        })
11922    }
11923
11924    pub fn select_to_end_of_paragraph(
11925        &mut self,
11926        _: &SelectToEndOfParagraph,
11927        window: &mut Window,
11928        cx: &mut Context<Self>,
11929    ) {
11930        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11931            cx.propagate();
11932            return;
11933        }
11934        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11935        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11936            s.move_heads_with(|map, head, _| {
11937                (
11938                    movement::end_of_paragraph(map, head, 1),
11939                    SelectionGoal::None,
11940                )
11941            });
11942        })
11943    }
11944
11945    pub fn move_to_start_of_excerpt(
11946        &mut self,
11947        _: &MoveToStartOfExcerpt,
11948        window: &mut Window,
11949        cx: &mut Context<Self>,
11950    ) {
11951        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11952            cx.propagate();
11953            return;
11954        }
11955        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11956        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11957            s.move_with(|map, selection| {
11958                selection.collapse_to(
11959                    movement::start_of_excerpt(
11960                        map,
11961                        selection.head(),
11962                        workspace::searchable::Direction::Prev,
11963                    ),
11964                    SelectionGoal::None,
11965                )
11966            });
11967        })
11968    }
11969
11970    pub fn move_to_start_of_next_excerpt(
11971        &mut self,
11972        _: &MoveToStartOfNextExcerpt,
11973        window: &mut Window,
11974        cx: &mut Context<Self>,
11975    ) {
11976        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11977            cx.propagate();
11978            return;
11979        }
11980
11981        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11982            s.move_with(|map, selection| {
11983                selection.collapse_to(
11984                    movement::start_of_excerpt(
11985                        map,
11986                        selection.head(),
11987                        workspace::searchable::Direction::Next,
11988                    ),
11989                    SelectionGoal::None,
11990                )
11991            });
11992        })
11993    }
11994
11995    pub fn move_to_end_of_excerpt(
11996        &mut self,
11997        _: &MoveToEndOfExcerpt,
11998        window: &mut Window,
11999        cx: &mut Context<Self>,
12000    ) {
12001        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12002            cx.propagate();
12003            return;
12004        }
12005        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12006        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12007            s.move_with(|map, selection| {
12008                selection.collapse_to(
12009                    movement::end_of_excerpt(
12010                        map,
12011                        selection.head(),
12012                        workspace::searchable::Direction::Next,
12013                    ),
12014                    SelectionGoal::None,
12015                )
12016            });
12017        })
12018    }
12019
12020    pub fn move_to_end_of_previous_excerpt(
12021        &mut self,
12022        _: &MoveToEndOfPreviousExcerpt,
12023        window: &mut Window,
12024        cx: &mut Context<Self>,
12025    ) {
12026        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12027            cx.propagate();
12028            return;
12029        }
12030        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12031        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12032            s.move_with(|map, selection| {
12033                selection.collapse_to(
12034                    movement::end_of_excerpt(
12035                        map,
12036                        selection.head(),
12037                        workspace::searchable::Direction::Prev,
12038                    ),
12039                    SelectionGoal::None,
12040                )
12041            });
12042        })
12043    }
12044
12045    pub fn select_to_start_of_excerpt(
12046        &mut self,
12047        _: &SelectToStartOfExcerpt,
12048        window: &mut Window,
12049        cx: &mut Context<Self>,
12050    ) {
12051        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12052            cx.propagate();
12053            return;
12054        }
12055        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12056        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12057            s.move_heads_with(|map, head, _| {
12058                (
12059                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12060                    SelectionGoal::None,
12061                )
12062            });
12063        })
12064    }
12065
12066    pub fn select_to_start_of_next_excerpt(
12067        &mut self,
12068        _: &SelectToStartOfNextExcerpt,
12069        window: &mut Window,
12070        cx: &mut Context<Self>,
12071    ) {
12072        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12073            cx.propagate();
12074            return;
12075        }
12076        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12077        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12078            s.move_heads_with(|map, head, _| {
12079                (
12080                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12081                    SelectionGoal::None,
12082                )
12083            });
12084        })
12085    }
12086
12087    pub fn select_to_end_of_excerpt(
12088        &mut self,
12089        _: &SelectToEndOfExcerpt,
12090        window: &mut Window,
12091        cx: &mut Context<Self>,
12092    ) {
12093        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12094            cx.propagate();
12095            return;
12096        }
12097        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12098        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12099            s.move_heads_with(|map, head, _| {
12100                (
12101                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12102                    SelectionGoal::None,
12103                )
12104            });
12105        })
12106    }
12107
12108    pub fn select_to_end_of_previous_excerpt(
12109        &mut self,
12110        _: &SelectToEndOfPreviousExcerpt,
12111        window: &mut Window,
12112        cx: &mut Context<Self>,
12113    ) {
12114        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12115            cx.propagate();
12116            return;
12117        }
12118        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12119        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12120            s.move_heads_with(|map, head, _| {
12121                (
12122                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12123                    SelectionGoal::None,
12124                )
12125            });
12126        })
12127    }
12128
12129    pub fn move_to_beginning(
12130        &mut self,
12131        _: &MoveToBeginning,
12132        window: &mut Window,
12133        cx: &mut Context<Self>,
12134    ) {
12135        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12136            cx.propagate();
12137            return;
12138        }
12139        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12140        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12141            s.select_ranges(vec![0..0]);
12142        });
12143    }
12144
12145    pub fn select_to_beginning(
12146        &mut self,
12147        _: &SelectToBeginning,
12148        window: &mut Window,
12149        cx: &mut Context<Self>,
12150    ) {
12151        let mut selection = self.selections.last::<Point>(cx);
12152        selection.set_head(Point::zero(), SelectionGoal::None);
12153        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12154        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12155            s.select(vec![selection]);
12156        });
12157    }
12158
12159    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12160        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12161            cx.propagate();
12162            return;
12163        }
12164        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12165        let cursor = self.buffer.read(cx).read(cx).len();
12166        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12167            s.select_ranges(vec![cursor..cursor])
12168        });
12169    }
12170
12171    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12172        self.nav_history = nav_history;
12173    }
12174
12175    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12176        self.nav_history.as_ref()
12177    }
12178
12179    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12180        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12181    }
12182
12183    fn push_to_nav_history(
12184        &mut self,
12185        cursor_anchor: Anchor,
12186        new_position: Option<Point>,
12187        is_deactivate: bool,
12188        cx: &mut Context<Self>,
12189    ) {
12190        if let Some(nav_history) = self.nav_history.as_mut() {
12191            let buffer = self.buffer.read(cx).read(cx);
12192            let cursor_position = cursor_anchor.to_point(&buffer);
12193            let scroll_state = self.scroll_manager.anchor();
12194            let scroll_top_row = scroll_state.top_row(&buffer);
12195            drop(buffer);
12196
12197            if let Some(new_position) = new_position {
12198                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12199                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12200                    return;
12201                }
12202            }
12203
12204            nav_history.push(
12205                Some(NavigationData {
12206                    cursor_anchor,
12207                    cursor_position,
12208                    scroll_anchor: scroll_state,
12209                    scroll_top_row,
12210                }),
12211                cx,
12212            );
12213            cx.emit(EditorEvent::PushedToNavHistory {
12214                anchor: cursor_anchor,
12215                is_deactivate,
12216            })
12217        }
12218    }
12219
12220    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12221        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12222        let buffer = self.buffer.read(cx).snapshot(cx);
12223        let mut selection = self.selections.first::<usize>(cx);
12224        selection.set_head(buffer.len(), SelectionGoal::None);
12225        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12226            s.select(vec![selection]);
12227        });
12228    }
12229
12230    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12231        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12232        let end = self.buffer.read(cx).read(cx).len();
12233        self.change_selections(None, window, cx, |s| {
12234            s.select_ranges(vec![0..end]);
12235        });
12236    }
12237
12238    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12239        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12240        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12241        let mut selections = self.selections.all::<Point>(cx);
12242        let max_point = display_map.buffer_snapshot.max_point();
12243        for selection in &mut selections {
12244            let rows = selection.spanned_rows(true, &display_map);
12245            selection.start = Point::new(rows.start.0, 0);
12246            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12247            selection.reversed = false;
12248        }
12249        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12250            s.select(selections);
12251        });
12252    }
12253
12254    pub fn split_selection_into_lines(
12255        &mut self,
12256        _: &SplitSelectionIntoLines,
12257        window: &mut Window,
12258        cx: &mut Context<Self>,
12259    ) {
12260        let selections = self
12261            .selections
12262            .all::<Point>(cx)
12263            .into_iter()
12264            .map(|selection| selection.start..selection.end)
12265            .collect::<Vec<_>>();
12266        self.unfold_ranges(&selections, true, true, cx);
12267
12268        let mut new_selection_ranges = Vec::new();
12269        {
12270            let buffer = self.buffer.read(cx).read(cx);
12271            for selection in selections {
12272                for row in selection.start.row..selection.end.row {
12273                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12274                    new_selection_ranges.push(cursor..cursor);
12275                }
12276
12277                let is_multiline_selection = selection.start.row != selection.end.row;
12278                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12279                // so this action feels more ergonomic when paired with other selection operations
12280                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12281                if !should_skip_last {
12282                    new_selection_ranges.push(selection.end..selection.end);
12283                }
12284            }
12285        }
12286        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12287            s.select_ranges(new_selection_ranges);
12288        });
12289    }
12290
12291    pub fn add_selection_above(
12292        &mut self,
12293        _: &AddSelectionAbove,
12294        window: &mut Window,
12295        cx: &mut Context<Self>,
12296    ) {
12297        self.add_selection(true, window, cx);
12298    }
12299
12300    pub fn add_selection_below(
12301        &mut self,
12302        _: &AddSelectionBelow,
12303        window: &mut Window,
12304        cx: &mut Context<Self>,
12305    ) {
12306        self.add_selection(false, window, cx);
12307    }
12308
12309    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12310        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12311
12312        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12313        let mut selections = self.selections.all::<Point>(cx);
12314        let text_layout_details = self.text_layout_details(window);
12315        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12316            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12317            let range = oldest_selection.display_range(&display_map).sorted();
12318
12319            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12320            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12321            let positions = start_x.min(end_x)..start_x.max(end_x);
12322
12323            selections.clear();
12324            let mut stack = Vec::new();
12325            for row in range.start.row().0..=range.end.row().0 {
12326                if let Some(selection) = self.selections.build_columnar_selection(
12327                    &display_map,
12328                    DisplayRow(row),
12329                    &positions,
12330                    oldest_selection.reversed,
12331                    &text_layout_details,
12332                ) {
12333                    stack.push(selection.id);
12334                    selections.push(selection);
12335                }
12336            }
12337
12338            if above {
12339                stack.reverse();
12340            }
12341
12342            AddSelectionsState { above, stack }
12343        });
12344
12345        let last_added_selection = *state.stack.last().unwrap();
12346        let mut new_selections = Vec::new();
12347        if above == state.above {
12348            let end_row = if above {
12349                DisplayRow(0)
12350            } else {
12351                display_map.max_point().row()
12352            };
12353
12354            'outer: for selection in selections {
12355                if selection.id == last_added_selection {
12356                    let range = selection.display_range(&display_map).sorted();
12357                    debug_assert_eq!(range.start.row(), range.end.row());
12358                    let mut row = range.start.row();
12359                    let positions =
12360                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12361                            px(start)..px(end)
12362                        } else {
12363                            let start_x =
12364                                display_map.x_for_display_point(range.start, &text_layout_details);
12365                            let end_x =
12366                                display_map.x_for_display_point(range.end, &text_layout_details);
12367                            start_x.min(end_x)..start_x.max(end_x)
12368                        };
12369
12370                    while row != end_row {
12371                        if above {
12372                            row.0 -= 1;
12373                        } else {
12374                            row.0 += 1;
12375                        }
12376
12377                        if let Some(new_selection) = self.selections.build_columnar_selection(
12378                            &display_map,
12379                            row,
12380                            &positions,
12381                            selection.reversed,
12382                            &text_layout_details,
12383                        ) {
12384                            state.stack.push(new_selection.id);
12385                            if above {
12386                                new_selections.push(new_selection);
12387                                new_selections.push(selection);
12388                            } else {
12389                                new_selections.push(selection);
12390                                new_selections.push(new_selection);
12391                            }
12392
12393                            continue 'outer;
12394                        }
12395                    }
12396                }
12397
12398                new_selections.push(selection);
12399            }
12400        } else {
12401            new_selections = selections;
12402            new_selections.retain(|s| s.id != last_added_selection);
12403            state.stack.pop();
12404        }
12405
12406        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12407            s.select(new_selections);
12408        });
12409        if state.stack.len() > 1 {
12410            self.add_selections_state = Some(state);
12411        }
12412    }
12413
12414    fn select_match_ranges(
12415        &mut self,
12416        range: Range<usize>,
12417        reversed: bool,
12418        replace_newest: bool,
12419        auto_scroll: Option<Autoscroll>,
12420        window: &mut Window,
12421        cx: &mut Context<Editor>,
12422    ) {
12423        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12424        self.change_selections(auto_scroll, window, cx, |s| {
12425            if replace_newest {
12426                s.delete(s.newest_anchor().id);
12427            }
12428            if reversed {
12429                s.insert_range(range.end..range.start);
12430            } else {
12431                s.insert_range(range);
12432            }
12433        });
12434    }
12435
12436    pub fn select_next_match_internal(
12437        &mut self,
12438        display_map: &DisplaySnapshot,
12439        replace_newest: bool,
12440        autoscroll: Option<Autoscroll>,
12441        window: &mut Window,
12442        cx: &mut Context<Self>,
12443    ) -> Result<()> {
12444        let buffer = &display_map.buffer_snapshot;
12445        let mut selections = self.selections.all::<usize>(cx);
12446        if let Some(mut select_next_state) = self.select_next_state.take() {
12447            let query = &select_next_state.query;
12448            if !select_next_state.done {
12449                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12450                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12451                let mut next_selected_range = None;
12452
12453                let bytes_after_last_selection =
12454                    buffer.bytes_in_range(last_selection.end..buffer.len());
12455                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12456                let query_matches = query
12457                    .stream_find_iter(bytes_after_last_selection)
12458                    .map(|result| (last_selection.end, result))
12459                    .chain(
12460                        query
12461                            .stream_find_iter(bytes_before_first_selection)
12462                            .map(|result| (0, result)),
12463                    );
12464
12465                for (start_offset, query_match) in query_matches {
12466                    let query_match = query_match.unwrap(); // can only fail due to I/O
12467                    let offset_range =
12468                        start_offset + query_match.start()..start_offset + query_match.end();
12469                    let display_range = offset_range.start.to_display_point(display_map)
12470                        ..offset_range.end.to_display_point(display_map);
12471
12472                    if !select_next_state.wordwise
12473                        || (!movement::is_inside_word(display_map, display_range.start)
12474                            && !movement::is_inside_word(display_map, display_range.end))
12475                    {
12476                        // TODO: This is n^2, because we might check all the selections
12477                        if !selections
12478                            .iter()
12479                            .any(|selection| selection.range().overlaps(&offset_range))
12480                        {
12481                            next_selected_range = Some(offset_range);
12482                            break;
12483                        }
12484                    }
12485                }
12486
12487                if let Some(next_selected_range) = next_selected_range {
12488                    self.select_match_ranges(
12489                        next_selected_range,
12490                        last_selection.reversed,
12491                        replace_newest,
12492                        autoscroll,
12493                        window,
12494                        cx,
12495                    );
12496                } else {
12497                    select_next_state.done = true;
12498                }
12499            }
12500
12501            self.select_next_state = Some(select_next_state);
12502        } else {
12503            let mut only_carets = true;
12504            let mut same_text_selected = true;
12505            let mut selected_text = None;
12506
12507            let mut selections_iter = selections.iter().peekable();
12508            while let Some(selection) = selections_iter.next() {
12509                if selection.start != selection.end {
12510                    only_carets = false;
12511                }
12512
12513                if same_text_selected {
12514                    if selected_text.is_none() {
12515                        selected_text =
12516                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12517                    }
12518
12519                    if let Some(next_selection) = selections_iter.peek() {
12520                        if next_selection.range().len() == selection.range().len() {
12521                            let next_selected_text = buffer
12522                                .text_for_range(next_selection.range())
12523                                .collect::<String>();
12524                            if Some(next_selected_text) != selected_text {
12525                                same_text_selected = false;
12526                                selected_text = None;
12527                            }
12528                        } else {
12529                            same_text_selected = false;
12530                            selected_text = None;
12531                        }
12532                    }
12533                }
12534            }
12535
12536            if only_carets {
12537                for selection in &mut selections {
12538                    let word_range = movement::surrounding_word(
12539                        display_map,
12540                        selection.start.to_display_point(display_map),
12541                    );
12542                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12543                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12544                    selection.goal = SelectionGoal::None;
12545                    selection.reversed = false;
12546                    self.select_match_ranges(
12547                        selection.start..selection.end,
12548                        selection.reversed,
12549                        replace_newest,
12550                        autoscroll,
12551                        window,
12552                        cx,
12553                    );
12554                }
12555
12556                if selections.len() == 1 {
12557                    let selection = selections
12558                        .last()
12559                        .expect("ensured that there's only one selection");
12560                    let query = buffer
12561                        .text_for_range(selection.start..selection.end)
12562                        .collect::<String>();
12563                    let is_empty = query.is_empty();
12564                    let select_state = SelectNextState {
12565                        query: AhoCorasick::new(&[query])?,
12566                        wordwise: true,
12567                        done: is_empty,
12568                    };
12569                    self.select_next_state = Some(select_state);
12570                } else {
12571                    self.select_next_state = None;
12572                }
12573            } else if let Some(selected_text) = selected_text {
12574                self.select_next_state = Some(SelectNextState {
12575                    query: AhoCorasick::new(&[selected_text])?,
12576                    wordwise: false,
12577                    done: false,
12578                });
12579                self.select_next_match_internal(
12580                    display_map,
12581                    replace_newest,
12582                    autoscroll,
12583                    window,
12584                    cx,
12585                )?;
12586            }
12587        }
12588        Ok(())
12589    }
12590
12591    pub fn select_all_matches(
12592        &mut self,
12593        _action: &SelectAllMatches,
12594        window: &mut Window,
12595        cx: &mut Context<Self>,
12596    ) -> Result<()> {
12597        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12598
12599        self.push_to_selection_history();
12600        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12601
12602        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12603        let Some(select_next_state) = self.select_next_state.as_mut() else {
12604            return Ok(());
12605        };
12606        if select_next_state.done {
12607            return Ok(());
12608        }
12609
12610        let mut new_selections = Vec::new();
12611
12612        let reversed = self.selections.oldest::<usize>(cx).reversed;
12613        let buffer = &display_map.buffer_snapshot;
12614        let query_matches = select_next_state
12615            .query
12616            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12617
12618        for query_match in query_matches.into_iter() {
12619            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12620            let offset_range = if reversed {
12621                query_match.end()..query_match.start()
12622            } else {
12623                query_match.start()..query_match.end()
12624            };
12625            let display_range = offset_range.start.to_display_point(&display_map)
12626                ..offset_range.end.to_display_point(&display_map);
12627
12628            if !select_next_state.wordwise
12629                || (!movement::is_inside_word(&display_map, display_range.start)
12630                    && !movement::is_inside_word(&display_map, display_range.end))
12631            {
12632                new_selections.push(offset_range.start..offset_range.end);
12633            }
12634        }
12635
12636        select_next_state.done = true;
12637        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12638        self.change_selections(None, window, cx, |selections| {
12639            selections.select_ranges(new_selections)
12640        });
12641
12642        Ok(())
12643    }
12644
12645    pub fn select_next(
12646        &mut self,
12647        action: &SelectNext,
12648        window: &mut Window,
12649        cx: &mut Context<Self>,
12650    ) -> Result<()> {
12651        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12652        self.push_to_selection_history();
12653        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12654        self.select_next_match_internal(
12655            &display_map,
12656            action.replace_newest,
12657            Some(Autoscroll::newest()),
12658            window,
12659            cx,
12660        )?;
12661        Ok(())
12662    }
12663
12664    pub fn select_previous(
12665        &mut self,
12666        action: &SelectPrevious,
12667        window: &mut Window,
12668        cx: &mut Context<Self>,
12669    ) -> Result<()> {
12670        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12671        self.push_to_selection_history();
12672        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12673        let buffer = &display_map.buffer_snapshot;
12674        let mut selections = self.selections.all::<usize>(cx);
12675        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12676            let query = &select_prev_state.query;
12677            if !select_prev_state.done {
12678                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12679                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12680                let mut next_selected_range = None;
12681                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12682                let bytes_before_last_selection =
12683                    buffer.reversed_bytes_in_range(0..last_selection.start);
12684                let bytes_after_first_selection =
12685                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12686                let query_matches = query
12687                    .stream_find_iter(bytes_before_last_selection)
12688                    .map(|result| (last_selection.start, result))
12689                    .chain(
12690                        query
12691                            .stream_find_iter(bytes_after_first_selection)
12692                            .map(|result| (buffer.len(), result)),
12693                    );
12694                for (end_offset, query_match) in query_matches {
12695                    let query_match = query_match.unwrap(); // can only fail due to I/O
12696                    let offset_range =
12697                        end_offset - query_match.end()..end_offset - query_match.start();
12698                    let display_range = offset_range.start.to_display_point(&display_map)
12699                        ..offset_range.end.to_display_point(&display_map);
12700
12701                    if !select_prev_state.wordwise
12702                        || (!movement::is_inside_word(&display_map, display_range.start)
12703                            && !movement::is_inside_word(&display_map, display_range.end))
12704                    {
12705                        next_selected_range = Some(offset_range);
12706                        break;
12707                    }
12708                }
12709
12710                if let Some(next_selected_range) = next_selected_range {
12711                    self.select_match_ranges(
12712                        next_selected_range,
12713                        last_selection.reversed,
12714                        action.replace_newest,
12715                        Some(Autoscroll::newest()),
12716                        window,
12717                        cx,
12718                    );
12719                } else {
12720                    select_prev_state.done = true;
12721                }
12722            }
12723
12724            self.select_prev_state = Some(select_prev_state);
12725        } else {
12726            let mut only_carets = true;
12727            let mut same_text_selected = true;
12728            let mut selected_text = None;
12729
12730            let mut selections_iter = selections.iter().peekable();
12731            while let Some(selection) = selections_iter.next() {
12732                if selection.start != selection.end {
12733                    only_carets = false;
12734                }
12735
12736                if same_text_selected {
12737                    if selected_text.is_none() {
12738                        selected_text =
12739                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12740                    }
12741
12742                    if let Some(next_selection) = selections_iter.peek() {
12743                        if next_selection.range().len() == selection.range().len() {
12744                            let next_selected_text = buffer
12745                                .text_for_range(next_selection.range())
12746                                .collect::<String>();
12747                            if Some(next_selected_text) != selected_text {
12748                                same_text_selected = false;
12749                                selected_text = None;
12750                            }
12751                        } else {
12752                            same_text_selected = false;
12753                            selected_text = None;
12754                        }
12755                    }
12756                }
12757            }
12758
12759            if only_carets {
12760                for selection in &mut selections {
12761                    let word_range = movement::surrounding_word(
12762                        &display_map,
12763                        selection.start.to_display_point(&display_map),
12764                    );
12765                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12766                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12767                    selection.goal = SelectionGoal::None;
12768                    selection.reversed = false;
12769                    self.select_match_ranges(
12770                        selection.start..selection.end,
12771                        selection.reversed,
12772                        action.replace_newest,
12773                        Some(Autoscroll::newest()),
12774                        window,
12775                        cx,
12776                    );
12777                }
12778                if selections.len() == 1 {
12779                    let selection = selections
12780                        .last()
12781                        .expect("ensured that there's only one selection");
12782                    let query = buffer
12783                        .text_for_range(selection.start..selection.end)
12784                        .collect::<String>();
12785                    let is_empty = query.is_empty();
12786                    let select_state = SelectNextState {
12787                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12788                        wordwise: true,
12789                        done: is_empty,
12790                    };
12791                    self.select_prev_state = Some(select_state);
12792                } else {
12793                    self.select_prev_state = None;
12794                }
12795            } else if let Some(selected_text) = selected_text {
12796                self.select_prev_state = Some(SelectNextState {
12797                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12798                    wordwise: false,
12799                    done: false,
12800                });
12801                self.select_previous(action, window, cx)?;
12802            }
12803        }
12804        Ok(())
12805    }
12806
12807    pub fn find_next_match(
12808        &mut self,
12809        _: &FindNextMatch,
12810        window: &mut Window,
12811        cx: &mut Context<Self>,
12812    ) -> Result<()> {
12813        let selections = self.selections.disjoint_anchors();
12814        match selections.first() {
12815            Some(first) if selections.len() >= 2 => {
12816                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12817                    s.select_ranges([first.range()]);
12818                });
12819            }
12820            _ => self.select_next(
12821                &SelectNext {
12822                    replace_newest: true,
12823                },
12824                window,
12825                cx,
12826            )?,
12827        }
12828        Ok(())
12829    }
12830
12831    pub fn find_previous_match(
12832        &mut self,
12833        _: &FindPreviousMatch,
12834        window: &mut Window,
12835        cx: &mut Context<Self>,
12836    ) -> Result<()> {
12837        let selections = self.selections.disjoint_anchors();
12838        match selections.last() {
12839            Some(last) if selections.len() >= 2 => {
12840                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12841                    s.select_ranges([last.range()]);
12842                });
12843            }
12844            _ => self.select_previous(
12845                &SelectPrevious {
12846                    replace_newest: true,
12847                },
12848                window,
12849                cx,
12850            )?,
12851        }
12852        Ok(())
12853    }
12854
12855    pub fn toggle_comments(
12856        &mut self,
12857        action: &ToggleComments,
12858        window: &mut Window,
12859        cx: &mut Context<Self>,
12860    ) {
12861        if self.read_only(cx) {
12862            return;
12863        }
12864        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12865        let text_layout_details = &self.text_layout_details(window);
12866        self.transact(window, cx, |this, window, cx| {
12867            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12868            let mut edits = Vec::new();
12869            let mut selection_edit_ranges = Vec::new();
12870            let mut last_toggled_row = None;
12871            let snapshot = this.buffer.read(cx).read(cx);
12872            let empty_str: Arc<str> = Arc::default();
12873            let mut suffixes_inserted = Vec::new();
12874            let ignore_indent = action.ignore_indent;
12875
12876            fn comment_prefix_range(
12877                snapshot: &MultiBufferSnapshot,
12878                row: MultiBufferRow,
12879                comment_prefix: &str,
12880                comment_prefix_whitespace: &str,
12881                ignore_indent: bool,
12882            ) -> Range<Point> {
12883                let indent_size = if ignore_indent {
12884                    0
12885                } else {
12886                    snapshot.indent_size_for_line(row).len
12887                };
12888
12889                let start = Point::new(row.0, indent_size);
12890
12891                let mut line_bytes = snapshot
12892                    .bytes_in_range(start..snapshot.max_point())
12893                    .flatten()
12894                    .copied();
12895
12896                // If this line currently begins with the line comment prefix, then record
12897                // the range containing the prefix.
12898                if line_bytes
12899                    .by_ref()
12900                    .take(comment_prefix.len())
12901                    .eq(comment_prefix.bytes())
12902                {
12903                    // Include any whitespace that matches the comment prefix.
12904                    let matching_whitespace_len = line_bytes
12905                        .zip(comment_prefix_whitespace.bytes())
12906                        .take_while(|(a, b)| a == b)
12907                        .count() as u32;
12908                    let end = Point::new(
12909                        start.row,
12910                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12911                    );
12912                    start..end
12913                } else {
12914                    start..start
12915                }
12916            }
12917
12918            fn comment_suffix_range(
12919                snapshot: &MultiBufferSnapshot,
12920                row: MultiBufferRow,
12921                comment_suffix: &str,
12922                comment_suffix_has_leading_space: bool,
12923            ) -> Range<Point> {
12924                let end = Point::new(row.0, snapshot.line_len(row));
12925                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12926
12927                let mut line_end_bytes = snapshot
12928                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12929                    .flatten()
12930                    .copied();
12931
12932                let leading_space_len = if suffix_start_column > 0
12933                    && line_end_bytes.next() == Some(b' ')
12934                    && comment_suffix_has_leading_space
12935                {
12936                    1
12937                } else {
12938                    0
12939                };
12940
12941                // If this line currently begins with the line comment prefix, then record
12942                // the range containing the prefix.
12943                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12944                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12945                    start..end
12946                } else {
12947                    end..end
12948                }
12949            }
12950
12951            // TODO: Handle selections that cross excerpts
12952            for selection in &mut selections {
12953                let start_column = snapshot
12954                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12955                    .len;
12956                let language = if let Some(language) =
12957                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12958                {
12959                    language
12960                } else {
12961                    continue;
12962                };
12963
12964                selection_edit_ranges.clear();
12965
12966                // If multiple selections contain a given row, avoid processing that
12967                // row more than once.
12968                let mut start_row = MultiBufferRow(selection.start.row);
12969                if last_toggled_row == Some(start_row) {
12970                    start_row = start_row.next_row();
12971                }
12972                let end_row =
12973                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12974                        MultiBufferRow(selection.end.row - 1)
12975                    } else {
12976                        MultiBufferRow(selection.end.row)
12977                    };
12978                last_toggled_row = Some(end_row);
12979
12980                if start_row > end_row {
12981                    continue;
12982                }
12983
12984                // If the language has line comments, toggle those.
12985                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12986
12987                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12988                if ignore_indent {
12989                    full_comment_prefixes = full_comment_prefixes
12990                        .into_iter()
12991                        .map(|s| Arc::from(s.trim_end()))
12992                        .collect();
12993                }
12994
12995                if !full_comment_prefixes.is_empty() {
12996                    let first_prefix = full_comment_prefixes
12997                        .first()
12998                        .expect("prefixes is non-empty");
12999                    let prefix_trimmed_lengths = full_comment_prefixes
13000                        .iter()
13001                        .map(|p| p.trim_end_matches(' ').len())
13002                        .collect::<SmallVec<[usize; 4]>>();
13003
13004                    let mut all_selection_lines_are_comments = true;
13005
13006                    for row in start_row.0..=end_row.0 {
13007                        let row = MultiBufferRow(row);
13008                        if start_row < end_row && snapshot.is_line_blank(row) {
13009                            continue;
13010                        }
13011
13012                        let prefix_range = full_comment_prefixes
13013                            .iter()
13014                            .zip(prefix_trimmed_lengths.iter().copied())
13015                            .map(|(prefix, trimmed_prefix_len)| {
13016                                comment_prefix_range(
13017                                    snapshot.deref(),
13018                                    row,
13019                                    &prefix[..trimmed_prefix_len],
13020                                    &prefix[trimmed_prefix_len..],
13021                                    ignore_indent,
13022                                )
13023                            })
13024                            .max_by_key(|range| range.end.column - range.start.column)
13025                            .expect("prefixes is non-empty");
13026
13027                        if prefix_range.is_empty() {
13028                            all_selection_lines_are_comments = false;
13029                        }
13030
13031                        selection_edit_ranges.push(prefix_range);
13032                    }
13033
13034                    if all_selection_lines_are_comments {
13035                        edits.extend(
13036                            selection_edit_ranges
13037                                .iter()
13038                                .cloned()
13039                                .map(|range| (range, empty_str.clone())),
13040                        );
13041                    } else {
13042                        let min_column = selection_edit_ranges
13043                            .iter()
13044                            .map(|range| range.start.column)
13045                            .min()
13046                            .unwrap_or(0);
13047                        edits.extend(selection_edit_ranges.iter().map(|range| {
13048                            let position = Point::new(range.start.row, min_column);
13049                            (position..position, first_prefix.clone())
13050                        }));
13051                    }
13052                } else if let Some((full_comment_prefix, comment_suffix)) =
13053                    language.block_comment_delimiters()
13054                {
13055                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13056                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13057                    let prefix_range = comment_prefix_range(
13058                        snapshot.deref(),
13059                        start_row,
13060                        comment_prefix,
13061                        comment_prefix_whitespace,
13062                        ignore_indent,
13063                    );
13064                    let suffix_range = comment_suffix_range(
13065                        snapshot.deref(),
13066                        end_row,
13067                        comment_suffix.trim_start_matches(' '),
13068                        comment_suffix.starts_with(' '),
13069                    );
13070
13071                    if prefix_range.is_empty() || suffix_range.is_empty() {
13072                        edits.push((
13073                            prefix_range.start..prefix_range.start,
13074                            full_comment_prefix.clone(),
13075                        ));
13076                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13077                        suffixes_inserted.push((end_row, comment_suffix.len()));
13078                    } else {
13079                        edits.push((prefix_range, empty_str.clone()));
13080                        edits.push((suffix_range, empty_str.clone()));
13081                    }
13082                } else {
13083                    continue;
13084                }
13085            }
13086
13087            drop(snapshot);
13088            this.buffer.update(cx, |buffer, cx| {
13089                buffer.edit(edits, None, cx);
13090            });
13091
13092            // Adjust selections so that they end before any comment suffixes that
13093            // were inserted.
13094            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13095            let mut selections = this.selections.all::<Point>(cx);
13096            let snapshot = this.buffer.read(cx).read(cx);
13097            for selection in &mut selections {
13098                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13099                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13100                        Ordering::Less => {
13101                            suffixes_inserted.next();
13102                            continue;
13103                        }
13104                        Ordering::Greater => break,
13105                        Ordering::Equal => {
13106                            if selection.end.column == snapshot.line_len(row) {
13107                                if selection.is_empty() {
13108                                    selection.start.column -= suffix_len as u32;
13109                                }
13110                                selection.end.column -= suffix_len as u32;
13111                            }
13112                            break;
13113                        }
13114                    }
13115                }
13116            }
13117
13118            drop(snapshot);
13119            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13120                s.select(selections)
13121            });
13122
13123            let selections = this.selections.all::<Point>(cx);
13124            let selections_on_single_row = selections.windows(2).all(|selections| {
13125                selections[0].start.row == selections[1].start.row
13126                    && selections[0].end.row == selections[1].end.row
13127                    && selections[0].start.row == selections[0].end.row
13128            });
13129            let selections_selecting = selections
13130                .iter()
13131                .any(|selection| selection.start != selection.end);
13132            let advance_downwards = action.advance_downwards
13133                && selections_on_single_row
13134                && !selections_selecting
13135                && !matches!(this.mode, EditorMode::SingleLine { .. });
13136
13137            if advance_downwards {
13138                let snapshot = this.buffer.read(cx).snapshot(cx);
13139
13140                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13141                    s.move_cursors_with(|display_snapshot, display_point, _| {
13142                        let mut point = display_point.to_point(display_snapshot);
13143                        point.row += 1;
13144                        point = snapshot.clip_point(point, Bias::Left);
13145                        let display_point = point.to_display_point(display_snapshot);
13146                        let goal = SelectionGoal::HorizontalPosition(
13147                            display_snapshot
13148                                .x_for_display_point(display_point, text_layout_details)
13149                                .into(),
13150                        );
13151                        (display_point, goal)
13152                    })
13153                });
13154            }
13155        });
13156    }
13157
13158    pub fn select_enclosing_symbol(
13159        &mut self,
13160        _: &SelectEnclosingSymbol,
13161        window: &mut Window,
13162        cx: &mut Context<Self>,
13163    ) {
13164        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13165
13166        let buffer = self.buffer.read(cx).snapshot(cx);
13167        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13168
13169        fn update_selection(
13170            selection: &Selection<usize>,
13171            buffer_snap: &MultiBufferSnapshot,
13172        ) -> Option<Selection<usize>> {
13173            let cursor = selection.head();
13174            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13175            for symbol in symbols.iter().rev() {
13176                let start = symbol.range.start.to_offset(buffer_snap);
13177                let end = symbol.range.end.to_offset(buffer_snap);
13178                let new_range = start..end;
13179                if start < selection.start || end > selection.end {
13180                    return Some(Selection {
13181                        id: selection.id,
13182                        start: new_range.start,
13183                        end: new_range.end,
13184                        goal: SelectionGoal::None,
13185                        reversed: selection.reversed,
13186                    });
13187                }
13188            }
13189            None
13190        }
13191
13192        let mut selected_larger_symbol = false;
13193        let new_selections = old_selections
13194            .iter()
13195            .map(|selection| match update_selection(selection, &buffer) {
13196                Some(new_selection) => {
13197                    if new_selection.range() != selection.range() {
13198                        selected_larger_symbol = true;
13199                    }
13200                    new_selection
13201                }
13202                None => selection.clone(),
13203            })
13204            .collect::<Vec<_>>();
13205
13206        if selected_larger_symbol {
13207            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13208                s.select(new_selections);
13209            });
13210        }
13211    }
13212
13213    pub fn select_larger_syntax_node(
13214        &mut self,
13215        _: &SelectLargerSyntaxNode,
13216        window: &mut Window,
13217        cx: &mut Context<Self>,
13218    ) {
13219        let Some(visible_row_count) = self.visible_row_count() else {
13220            return;
13221        };
13222        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13223        if old_selections.is_empty() {
13224            return;
13225        }
13226
13227        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13228
13229        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13230        let buffer = self.buffer.read(cx).snapshot(cx);
13231
13232        let mut selected_larger_node = false;
13233        let mut new_selections = old_selections
13234            .iter()
13235            .map(|selection| {
13236                let old_range = selection.start..selection.end;
13237
13238                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13239                    // manually select word at selection
13240                    if ["string_content", "inline"].contains(&node.kind()) {
13241                        let word_range = {
13242                            let display_point = buffer
13243                                .offset_to_point(old_range.start)
13244                                .to_display_point(&display_map);
13245                            let Range { start, end } =
13246                                movement::surrounding_word(&display_map, display_point);
13247                            start.to_point(&display_map).to_offset(&buffer)
13248                                ..end.to_point(&display_map).to_offset(&buffer)
13249                        };
13250                        // ignore if word is already selected
13251                        if !word_range.is_empty() && old_range != word_range {
13252                            let last_word_range = {
13253                                let display_point = buffer
13254                                    .offset_to_point(old_range.end)
13255                                    .to_display_point(&display_map);
13256                                let Range { start, end } =
13257                                    movement::surrounding_word(&display_map, display_point);
13258                                start.to_point(&display_map).to_offset(&buffer)
13259                                    ..end.to_point(&display_map).to_offset(&buffer)
13260                            };
13261                            // only select word if start and end point belongs to same word
13262                            if word_range == last_word_range {
13263                                selected_larger_node = true;
13264                                return Selection {
13265                                    id: selection.id,
13266                                    start: word_range.start,
13267                                    end: word_range.end,
13268                                    goal: SelectionGoal::None,
13269                                    reversed: selection.reversed,
13270                                };
13271                            }
13272                        }
13273                    }
13274                }
13275
13276                let mut new_range = old_range.clone();
13277                while let Some((_node, containing_range)) =
13278                    buffer.syntax_ancestor(new_range.clone())
13279                {
13280                    new_range = match containing_range {
13281                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13282                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13283                    };
13284                    if !display_map.intersects_fold(new_range.start)
13285                        && !display_map.intersects_fold(new_range.end)
13286                    {
13287                        break;
13288                    }
13289                }
13290
13291                selected_larger_node |= new_range != old_range;
13292                Selection {
13293                    id: selection.id,
13294                    start: new_range.start,
13295                    end: new_range.end,
13296                    goal: SelectionGoal::None,
13297                    reversed: selection.reversed,
13298                }
13299            })
13300            .collect::<Vec<_>>();
13301
13302        if !selected_larger_node {
13303            return; // don't put this call in the history
13304        }
13305
13306        // scroll based on transformation done to the last selection created by the user
13307        let (last_old, last_new) = old_selections
13308            .last()
13309            .zip(new_selections.last().cloned())
13310            .expect("old_selections isn't empty");
13311
13312        // revert selection
13313        let is_selection_reversed = {
13314            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13315            new_selections.last_mut().expect("checked above").reversed =
13316                should_newest_selection_be_reversed;
13317            should_newest_selection_be_reversed
13318        };
13319
13320        if selected_larger_node {
13321            self.select_syntax_node_history.disable_clearing = true;
13322            self.change_selections(None, window, cx, |s| {
13323                s.select(new_selections.clone());
13324            });
13325            self.select_syntax_node_history.disable_clearing = false;
13326        }
13327
13328        let start_row = last_new.start.to_display_point(&display_map).row().0;
13329        let end_row = last_new.end.to_display_point(&display_map).row().0;
13330        let selection_height = end_row - start_row + 1;
13331        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13332
13333        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13334        let scroll_behavior = if fits_on_the_screen {
13335            self.request_autoscroll(Autoscroll::fit(), cx);
13336            SelectSyntaxNodeScrollBehavior::FitSelection
13337        } else if is_selection_reversed {
13338            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13339            SelectSyntaxNodeScrollBehavior::CursorTop
13340        } else {
13341            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13342            SelectSyntaxNodeScrollBehavior::CursorBottom
13343        };
13344
13345        self.select_syntax_node_history.push((
13346            old_selections,
13347            scroll_behavior,
13348            is_selection_reversed,
13349        ));
13350    }
13351
13352    pub fn select_smaller_syntax_node(
13353        &mut self,
13354        _: &SelectSmallerSyntaxNode,
13355        window: &mut Window,
13356        cx: &mut Context<Self>,
13357    ) {
13358        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13359
13360        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13361            self.select_syntax_node_history.pop()
13362        {
13363            if let Some(selection) = selections.last_mut() {
13364                selection.reversed = is_selection_reversed;
13365            }
13366
13367            self.select_syntax_node_history.disable_clearing = true;
13368            self.change_selections(None, window, cx, |s| {
13369                s.select(selections.to_vec());
13370            });
13371            self.select_syntax_node_history.disable_clearing = false;
13372
13373            match scroll_behavior {
13374                SelectSyntaxNodeScrollBehavior::CursorTop => {
13375                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13376                }
13377                SelectSyntaxNodeScrollBehavior::FitSelection => {
13378                    self.request_autoscroll(Autoscroll::fit(), cx);
13379                }
13380                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13381                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13382                }
13383            }
13384        }
13385    }
13386
13387    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13388        if !EditorSettings::get_global(cx).gutter.runnables {
13389            self.clear_tasks();
13390            return Task::ready(());
13391        }
13392        let project = self.project.as_ref().map(Entity::downgrade);
13393        let task_sources = self.lsp_task_sources(cx);
13394        cx.spawn_in(window, async move |editor, cx| {
13395            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13396            let Some(project) = project.and_then(|p| p.upgrade()) else {
13397                return;
13398            };
13399            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13400                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13401            }) else {
13402                return;
13403            };
13404
13405            let hide_runnables = project
13406                .update(cx, |project, cx| {
13407                    // Do not display any test indicators in non-dev server remote projects.
13408                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13409                })
13410                .unwrap_or(true);
13411            if hide_runnables {
13412                return;
13413            }
13414            let new_rows =
13415                cx.background_spawn({
13416                    let snapshot = display_snapshot.clone();
13417                    async move {
13418                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13419                    }
13420                })
13421                    .await;
13422            let Ok(lsp_tasks) =
13423                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13424            else {
13425                return;
13426            };
13427            let lsp_tasks = lsp_tasks.await;
13428
13429            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13430                lsp_tasks
13431                    .into_iter()
13432                    .flat_map(|(kind, tasks)| {
13433                        tasks.into_iter().filter_map(move |(location, task)| {
13434                            Some((kind.clone(), location?, task))
13435                        })
13436                    })
13437                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13438                        let buffer = location.target.buffer;
13439                        let buffer_snapshot = buffer.read(cx).snapshot();
13440                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13441                            |(excerpt_id, snapshot, _)| {
13442                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13443                                    display_snapshot
13444                                        .buffer_snapshot
13445                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13446                                } else {
13447                                    None
13448                                }
13449                            },
13450                        );
13451                        if let Some(offset) = offset {
13452                            let task_buffer_range =
13453                                location.target.range.to_point(&buffer_snapshot);
13454                            let context_buffer_range =
13455                                task_buffer_range.to_offset(&buffer_snapshot);
13456                            let context_range = BufferOffset(context_buffer_range.start)
13457                                ..BufferOffset(context_buffer_range.end);
13458
13459                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13460                                .or_insert_with(|| RunnableTasks {
13461                                    templates: Vec::new(),
13462                                    offset,
13463                                    column: task_buffer_range.start.column,
13464                                    extra_variables: HashMap::default(),
13465                                    context_range,
13466                                })
13467                                .templates
13468                                .push((kind, task.original_task().clone()));
13469                        }
13470
13471                        acc
13472                    })
13473            }) else {
13474                return;
13475            };
13476
13477            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13478            editor
13479                .update(cx, |editor, _| {
13480                    editor.clear_tasks();
13481                    for (key, mut value) in rows {
13482                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13483                            value.templates.extend(lsp_tasks.templates);
13484                        }
13485
13486                        editor.insert_tasks(key, value);
13487                    }
13488                    for (key, value) in lsp_tasks_by_rows {
13489                        editor.insert_tasks(key, value);
13490                    }
13491                })
13492                .ok();
13493        })
13494    }
13495    fn fetch_runnable_ranges(
13496        snapshot: &DisplaySnapshot,
13497        range: Range<Anchor>,
13498    ) -> Vec<language::RunnableRange> {
13499        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13500    }
13501
13502    fn runnable_rows(
13503        project: Entity<Project>,
13504        snapshot: DisplaySnapshot,
13505        runnable_ranges: Vec<RunnableRange>,
13506        mut cx: AsyncWindowContext,
13507    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13508        runnable_ranges
13509            .into_iter()
13510            .filter_map(|mut runnable| {
13511                let tasks = cx
13512                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13513                    .ok()?;
13514                if tasks.is_empty() {
13515                    return None;
13516                }
13517
13518                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13519
13520                let row = snapshot
13521                    .buffer_snapshot
13522                    .buffer_line_for_row(MultiBufferRow(point.row))?
13523                    .1
13524                    .start
13525                    .row;
13526
13527                let context_range =
13528                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13529                Some((
13530                    (runnable.buffer_id, row),
13531                    RunnableTasks {
13532                        templates: tasks,
13533                        offset: snapshot
13534                            .buffer_snapshot
13535                            .anchor_before(runnable.run_range.start),
13536                        context_range,
13537                        column: point.column,
13538                        extra_variables: runnable.extra_captures,
13539                    },
13540                ))
13541            })
13542            .collect()
13543    }
13544
13545    fn templates_with_tags(
13546        project: &Entity<Project>,
13547        runnable: &mut Runnable,
13548        cx: &mut App,
13549    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13550        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13551            let (worktree_id, file) = project
13552                .buffer_for_id(runnable.buffer, cx)
13553                .and_then(|buffer| buffer.read(cx).file())
13554                .map(|file| (file.worktree_id(cx), file.clone()))
13555                .unzip();
13556
13557            (
13558                project.task_store().read(cx).task_inventory().cloned(),
13559                worktree_id,
13560                file,
13561            )
13562        });
13563
13564        let mut templates_with_tags = mem::take(&mut runnable.tags)
13565            .into_iter()
13566            .flat_map(|RunnableTag(tag)| {
13567                inventory
13568                    .as_ref()
13569                    .into_iter()
13570                    .flat_map(|inventory| {
13571                        inventory.read(cx).list_tasks(
13572                            file.clone(),
13573                            Some(runnable.language.clone()),
13574                            worktree_id,
13575                            cx,
13576                        )
13577                    })
13578                    .filter(move |(_, template)| {
13579                        template.tags.iter().any(|source_tag| source_tag == &tag)
13580                    })
13581            })
13582            .sorted_by_key(|(kind, _)| kind.to_owned())
13583            .collect::<Vec<_>>();
13584        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13585            // Strongest source wins; if we have worktree tag binding, prefer that to
13586            // global and language bindings;
13587            // if we have a global binding, prefer that to language binding.
13588            let first_mismatch = templates_with_tags
13589                .iter()
13590                .position(|(tag_source, _)| tag_source != leading_tag_source);
13591            if let Some(index) = first_mismatch {
13592                templates_with_tags.truncate(index);
13593            }
13594        }
13595
13596        templates_with_tags
13597    }
13598
13599    pub fn move_to_enclosing_bracket(
13600        &mut self,
13601        _: &MoveToEnclosingBracket,
13602        window: &mut Window,
13603        cx: &mut Context<Self>,
13604    ) {
13605        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13606        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13607            s.move_offsets_with(|snapshot, selection| {
13608                let Some(enclosing_bracket_ranges) =
13609                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13610                else {
13611                    return;
13612                };
13613
13614                let mut best_length = usize::MAX;
13615                let mut best_inside = false;
13616                let mut best_in_bracket_range = false;
13617                let mut best_destination = None;
13618                for (open, close) in enclosing_bracket_ranges {
13619                    let close = close.to_inclusive();
13620                    let length = close.end() - open.start;
13621                    let inside = selection.start >= open.end && selection.end <= *close.start();
13622                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13623                        || close.contains(&selection.head());
13624
13625                    // If best is next to a bracket and current isn't, skip
13626                    if !in_bracket_range && best_in_bracket_range {
13627                        continue;
13628                    }
13629
13630                    // Prefer smaller lengths unless best is inside and current isn't
13631                    if length > best_length && (best_inside || !inside) {
13632                        continue;
13633                    }
13634
13635                    best_length = length;
13636                    best_inside = inside;
13637                    best_in_bracket_range = in_bracket_range;
13638                    best_destination = Some(
13639                        if close.contains(&selection.start) && close.contains(&selection.end) {
13640                            if inside { open.end } else { open.start }
13641                        } else if inside {
13642                            *close.start()
13643                        } else {
13644                            *close.end()
13645                        },
13646                    );
13647                }
13648
13649                if let Some(destination) = best_destination {
13650                    selection.collapse_to(destination, SelectionGoal::None);
13651                }
13652            })
13653        });
13654    }
13655
13656    pub fn undo_selection(
13657        &mut self,
13658        _: &UndoSelection,
13659        window: &mut Window,
13660        cx: &mut Context<Self>,
13661    ) {
13662        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13663        self.end_selection(window, cx);
13664        self.selection_history.mode = SelectionHistoryMode::Undoing;
13665        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13666            self.change_selections(None, window, cx, |s| {
13667                s.select_anchors(entry.selections.to_vec())
13668            });
13669            self.select_next_state = entry.select_next_state;
13670            self.select_prev_state = entry.select_prev_state;
13671            self.add_selections_state = entry.add_selections_state;
13672            self.request_autoscroll(Autoscroll::newest(), cx);
13673        }
13674        self.selection_history.mode = SelectionHistoryMode::Normal;
13675    }
13676
13677    pub fn redo_selection(
13678        &mut self,
13679        _: &RedoSelection,
13680        window: &mut Window,
13681        cx: &mut Context<Self>,
13682    ) {
13683        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13684        self.end_selection(window, cx);
13685        self.selection_history.mode = SelectionHistoryMode::Redoing;
13686        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13687            self.change_selections(None, window, cx, |s| {
13688                s.select_anchors(entry.selections.to_vec())
13689            });
13690            self.select_next_state = entry.select_next_state;
13691            self.select_prev_state = entry.select_prev_state;
13692            self.add_selections_state = entry.add_selections_state;
13693            self.request_autoscroll(Autoscroll::newest(), cx);
13694        }
13695        self.selection_history.mode = SelectionHistoryMode::Normal;
13696    }
13697
13698    pub fn expand_excerpts(
13699        &mut self,
13700        action: &ExpandExcerpts,
13701        _: &mut Window,
13702        cx: &mut Context<Self>,
13703    ) {
13704        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13705    }
13706
13707    pub fn expand_excerpts_down(
13708        &mut self,
13709        action: &ExpandExcerptsDown,
13710        _: &mut Window,
13711        cx: &mut Context<Self>,
13712    ) {
13713        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13714    }
13715
13716    pub fn expand_excerpts_up(
13717        &mut self,
13718        action: &ExpandExcerptsUp,
13719        _: &mut Window,
13720        cx: &mut Context<Self>,
13721    ) {
13722        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13723    }
13724
13725    pub fn expand_excerpts_for_direction(
13726        &mut self,
13727        lines: u32,
13728        direction: ExpandExcerptDirection,
13729
13730        cx: &mut Context<Self>,
13731    ) {
13732        let selections = self.selections.disjoint_anchors();
13733
13734        let lines = if lines == 0 {
13735            EditorSettings::get_global(cx).expand_excerpt_lines
13736        } else {
13737            lines
13738        };
13739
13740        self.buffer.update(cx, |buffer, cx| {
13741            let snapshot = buffer.snapshot(cx);
13742            let mut excerpt_ids = selections
13743                .iter()
13744                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13745                .collect::<Vec<_>>();
13746            excerpt_ids.sort();
13747            excerpt_ids.dedup();
13748            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13749        })
13750    }
13751
13752    pub fn expand_excerpt(
13753        &mut self,
13754        excerpt: ExcerptId,
13755        direction: ExpandExcerptDirection,
13756        window: &mut Window,
13757        cx: &mut Context<Self>,
13758    ) {
13759        let current_scroll_position = self.scroll_position(cx);
13760        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13761        let mut should_scroll_up = false;
13762
13763        if direction == ExpandExcerptDirection::Down {
13764            let multi_buffer = self.buffer.read(cx);
13765            let snapshot = multi_buffer.snapshot(cx);
13766            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13767                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13768                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13769                        let buffer_snapshot = buffer.read(cx).snapshot();
13770                        let excerpt_end_row =
13771                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13772                        let last_row = buffer_snapshot.max_point().row;
13773                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13774                        should_scroll_up = lines_below >= lines_to_expand;
13775                    }
13776                }
13777            }
13778        }
13779
13780        self.buffer.update(cx, |buffer, cx| {
13781            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13782        });
13783
13784        if should_scroll_up {
13785            let new_scroll_position =
13786                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13787            self.set_scroll_position(new_scroll_position, window, cx);
13788        }
13789    }
13790
13791    pub fn go_to_singleton_buffer_point(
13792        &mut self,
13793        point: Point,
13794        window: &mut Window,
13795        cx: &mut Context<Self>,
13796    ) {
13797        self.go_to_singleton_buffer_range(point..point, window, cx);
13798    }
13799
13800    pub fn go_to_singleton_buffer_range(
13801        &mut self,
13802        range: Range<Point>,
13803        window: &mut Window,
13804        cx: &mut Context<Self>,
13805    ) {
13806        let multibuffer = self.buffer().read(cx);
13807        let Some(buffer) = multibuffer.as_singleton() else {
13808            return;
13809        };
13810        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13811            return;
13812        };
13813        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13814            return;
13815        };
13816        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13817            s.select_anchor_ranges([start..end])
13818        });
13819    }
13820
13821    pub fn go_to_diagnostic(
13822        &mut self,
13823        _: &GoToDiagnostic,
13824        window: &mut Window,
13825        cx: &mut Context<Self>,
13826    ) {
13827        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13828        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13829    }
13830
13831    pub fn go_to_prev_diagnostic(
13832        &mut self,
13833        _: &GoToPreviousDiagnostic,
13834        window: &mut Window,
13835        cx: &mut Context<Self>,
13836    ) {
13837        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13838        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13839    }
13840
13841    pub fn go_to_diagnostic_impl(
13842        &mut self,
13843        direction: Direction,
13844        window: &mut Window,
13845        cx: &mut Context<Self>,
13846    ) {
13847        let buffer = self.buffer.read(cx).snapshot(cx);
13848        let selection = self.selections.newest::<usize>(cx);
13849
13850        let mut active_group_id = None;
13851        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13852            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13853                active_group_id = Some(active_group.group_id);
13854            }
13855        }
13856
13857        fn filtered(
13858            snapshot: EditorSnapshot,
13859            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13860        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13861            diagnostics
13862                .filter(|entry| entry.range.start != entry.range.end)
13863                .filter(|entry| !entry.diagnostic.is_unnecessary)
13864                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13865        }
13866
13867        let snapshot = self.snapshot(window, cx);
13868        let before = filtered(
13869            snapshot.clone(),
13870            buffer
13871                .diagnostics_in_range(0..selection.start)
13872                .filter(|entry| entry.range.start <= selection.start),
13873        );
13874        let after = filtered(
13875            snapshot,
13876            buffer
13877                .diagnostics_in_range(selection.start..buffer.len())
13878                .filter(|entry| entry.range.start >= selection.start),
13879        );
13880
13881        let mut found: Option<DiagnosticEntry<usize>> = None;
13882        if direction == Direction::Prev {
13883            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13884            {
13885                for diagnostic in prev_diagnostics.into_iter().rev() {
13886                    if diagnostic.range.start != selection.start
13887                        || active_group_id
13888                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13889                    {
13890                        found = Some(diagnostic);
13891                        break 'outer;
13892                    }
13893                }
13894            }
13895        } else {
13896            for diagnostic in after.chain(before) {
13897                if diagnostic.range.start != selection.start
13898                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13899                {
13900                    found = Some(diagnostic);
13901                    break;
13902                }
13903            }
13904        }
13905        let Some(next_diagnostic) = found else {
13906            return;
13907        };
13908
13909        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13910            return;
13911        };
13912        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13913            s.select_ranges(vec![
13914                next_diagnostic.range.start..next_diagnostic.range.start,
13915            ])
13916        });
13917        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13918        self.refresh_inline_completion(false, true, window, cx);
13919    }
13920
13921    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13922        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13923        let snapshot = self.snapshot(window, cx);
13924        let selection = self.selections.newest::<Point>(cx);
13925        self.go_to_hunk_before_or_after_position(
13926            &snapshot,
13927            selection.head(),
13928            Direction::Next,
13929            window,
13930            cx,
13931        );
13932    }
13933
13934    pub fn go_to_hunk_before_or_after_position(
13935        &mut self,
13936        snapshot: &EditorSnapshot,
13937        position: Point,
13938        direction: Direction,
13939        window: &mut Window,
13940        cx: &mut Context<Editor>,
13941    ) {
13942        let row = if direction == Direction::Next {
13943            self.hunk_after_position(snapshot, position)
13944                .map(|hunk| hunk.row_range.start)
13945        } else {
13946            self.hunk_before_position(snapshot, position)
13947        };
13948
13949        if let Some(row) = row {
13950            let destination = Point::new(row.0, 0);
13951            let autoscroll = Autoscroll::center();
13952
13953            self.unfold_ranges(&[destination..destination], false, false, cx);
13954            self.change_selections(Some(autoscroll), window, cx, |s| {
13955                s.select_ranges([destination..destination]);
13956            });
13957        }
13958    }
13959
13960    fn hunk_after_position(
13961        &mut self,
13962        snapshot: &EditorSnapshot,
13963        position: Point,
13964    ) -> Option<MultiBufferDiffHunk> {
13965        snapshot
13966            .buffer_snapshot
13967            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13968            .find(|hunk| hunk.row_range.start.0 > position.row)
13969            .or_else(|| {
13970                snapshot
13971                    .buffer_snapshot
13972                    .diff_hunks_in_range(Point::zero()..position)
13973                    .find(|hunk| hunk.row_range.end.0 < position.row)
13974            })
13975    }
13976
13977    fn go_to_prev_hunk(
13978        &mut self,
13979        _: &GoToPreviousHunk,
13980        window: &mut Window,
13981        cx: &mut Context<Self>,
13982    ) {
13983        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13984        let snapshot = self.snapshot(window, cx);
13985        let selection = self.selections.newest::<Point>(cx);
13986        self.go_to_hunk_before_or_after_position(
13987            &snapshot,
13988            selection.head(),
13989            Direction::Prev,
13990            window,
13991            cx,
13992        );
13993    }
13994
13995    fn hunk_before_position(
13996        &mut self,
13997        snapshot: &EditorSnapshot,
13998        position: Point,
13999    ) -> Option<MultiBufferRow> {
14000        snapshot
14001            .buffer_snapshot
14002            .diff_hunk_before(position)
14003            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14004    }
14005
14006    fn go_to_next_change(
14007        &mut self,
14008        _: &GoToNextChange,
14009        window: &mut Window,
14010        cx: &mut Context<Self>,
14011    ) {
14012        if let Some(selections) = self
14013            .change_list
14014            .next_change(1, Direction::Next)
14015            .map(|s| s.to_vec())
14016        {
14017            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14018                let map = s.display_map();
14019                s.select_display_ranges(selections.iter().map(|a| {
14020                    let point = a.to_display_point(&map);
14021                    point..point
14022                }))
14023            })
14024        }
14025    }
14026
14027    fn go_to_previous_change(
14028        &mut self,
14029        _: &GoToPreviousChange,
14030        window: &mut Window,
14031        cx: &mut Context<Self>,
14032    ) {
14033        if let Some(selections) = self
14034            .change_list
14035            .next_change(1, Direction::Prev)
14036            .map(|s| s.to_vec())
14037        {
14038            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14039                let map = s.display_map();
14040                s.select_display_ranges(selections.iter().map(|a| {
14041                    let point = a.to_display_point(&map);
14042                    point..point
14043                }))
14044            })
14045        }
14046    }
14047
14048    fn go_to_line<T: 'static>(
14049        &mut self,
14050        position: Anchor,
14051        highlight_color: Option<Hsla>,
14052        window: &mut Window,
14053        cx: &mut Context<Self>,
14054    ) {
14055        let snapshot = self.snapshot(window, cx).display_snapshot;
14056        let position = position.to_point(&snapshot.buffer_snapshot);
14057        let start = snapshot
14058            .buffer_snapshot
14059            .clip_point(Point::new(position.row, 0), Bias::Left);
14060        let end = start + Point::new(1, 0);
14061        let start = snapshot.buffer_snapshot.anchor_before(start);
14062        let end = snapshot.buffer_snapshot.anchor_before(end);
14063
14064        self.highlight_rows::<T>(
14065            start..end,
14066            highlight_color
14067                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14068            Default::default(),
14069            cx,
14070        );
14071
14072        if self.buffer.read(cx).is_singleton() {
14073            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14074        }
14075    }
14076
14077    pub fn go_to_definition(
14078        &mut self,
14079        _: &GoToDefinition,
14080        window: &mut Window,
14081        cx: &mut Context<Self>,
14082    ) -> Task<Result<Navigated>> {
14083        let definition =
14084            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14085        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14086        cx.spawn_in(window, async move |editor, cx| {
14087            if definition.await? == Navigated::Yes {
14088                return Ok(Navigated::Yes);
14089            }
14090            match fallback_strategy {
14091                GoToDefinitionFallback::None => Ok(Navigated::No),
14092                GoToDefinitionFallback::FindAllReferences => {
14093                    match editor.update_in(cx, |editor, window, cx| {
14094                        editor.find_all_references(&FindAllReferences, window, cx)
14095                    })? {
14096                        Some(references) => references.await,
14097                        None => Ok(Navigated::No),
14098                    }
14099                }
14100            }
14101        })
14102    }
14103
14104    pub fn go_to_declaration(
14105        &mut self,
14106        _: &GoToDeclaration,
14107        window: &mut Window,
14108        cx: &mut Context<Self>,
14109    ) -> Task<Result<Navigated>> {
14110        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14111    }
14112
14113    pub fn go_to_declaration_split(
14114        &mut self,
14115        _: &GoToDeclaration,
14116        window: &mut Window,
14117        cx: &mut Context<Self>,
14118    ) -> Task<Result<Navigated>> {
14119        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14120    }
14121
14122    pub fn go_to_implementation(
14123        &mut self,
14124        _: &GoToImplementation,
14125        window: &mut Window,
14126        cx: &mut Context<Self>,
14127    ) -> Task<Result<Navigated>> {
14128        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14129    }
14130
14131    pub fn go_to_implementation_split(
14132        &mut self,
14133        _: &GoToImplementationSplit,
14134        window: &mut Window,
14135        cx: &mut Context<Self>,
14136    ) -> Task<Result<Navigated>> {
14137        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14138    }
14139
14140    pub fn go_to_type_definition(
14141        &mut self,
14142        _: &GoToTypeDefinition,
14143        window: &mut Window,
14144        cx: &mut Context<Self>,
14145    ) -> Task<Result<Navigated>> {
14146        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14147    }
14148
14149    pub fn go_to_definition_split(
14150        &mut self,
14151        _: &GoToDefinitionSplit,
14152        window: &mut Window,
14153        cx: &mut Context<Self>,
14154    ) -> Task<Result<Navigated>> {
14155        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14156    }
14157
14158    pub fn go_to_type_definition_split(
14159        &mut self,
14160        _: &GoToTypeDefinitionSplit,
14161        window: &mut Window,
14162        cx: &mut Context<Self>,
14163    ) -> Task<Result<Navigated>> {
14164        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14165    }
14166
14167    fn go_to_definition_of_kind(
14168        &mut self,
14169        kind: GotoDefinitionKind,
14170        split: bool,
14171        window: &mut Window,
14172        cx: &mut Context<Self>,
14173    ) -> Task<Result<Navigated>> {
14174        let Some(provider) = self.semantics_provider.clone() else {
14175            return Task::ready(Ok(Navigated::No));
14176        };
14177        let head = self.selections.newest::<usize>(cx).head();
14178        let buffer = self.buffer.read(cx);
14179        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14180            text_anchor
14181        } else {
14182            return Task::ready(Ok(Navigated::No));
14183        };
14184
14185        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14186            return Task::ready(Ok(Navigated::No));
14187        };
14188
14189        cx.spawn_in(window, async move |editor, cx| {
14190            let definitions = definitions.await?;
14191            let navigated = editor
14192                .update_in(cx, |editor, window, cx| {
14193                    editor.navigate_to_hover_links(
14194                        Some(kind),
14195                        definitions
14196                            .into_iter()
14197                            .filter(|location| {
14198                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14199                            })
14200                            .map(HoverLink::Text)
14201                            .collect::<Vec<_>>(),
14202                        split,
14203                        window,
14204                        cx,
14205                    )
14206                })?
14207                .await?;
14208            anyhow::Ok(navigated)
14209        })
14210    }
14211
14212    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14213        let selection = self.selections.newest_anchor();
14214        let head = selection.head();
14215        let tail = selection.tail();
14216
14217        let Some((buffer, start_position)) =
14218            self.buffer.read(cx).text_anchor_for_position(head, cx)
14219        else {
14220            return;
14221        };
14222
14223        let end_position = if head != tail {
14224            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14225                return;
14226            };
14227            Some(pos)
14228        } else {
14229            None
14230        };
14231
14232        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14233            let url = if let Some(end_pos) = end_position {
14234                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14235            } else {
14236                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14237            };
14238
14239            if let Some(url) = url {
14240                editor.update(cx, |_, cx| {
14241                    cx.open_url(&url);
14242                })
14243            } else {
14244                Ok(())
14245            }
14246        });
14247
14248        url_finder.detach();
14249    }
14250
14251    pub fn open_selected_filename(
14252        &mut self,
14253        _: &OpenSelectedFilename,
14254        window: &mut Window,
14255        cx: &mut Context<Self>,
14256    ) {
14257        let Some(workspace) = self.workspace() else {
14258            return;
14259        };
14260
14261        let position = self.selections.newest_anchor().head();
14262
14263        let Some((buffer, buffer_position)) =
14264            self.buffer.read(cx).text_anchor_for_position(position, cx)
14265        else {
14266            return;
14267        };
14268
14269        let project = self.project.clone();
14270
14271        cx.spawn_in(window, async move |_, cx| {
14272            let result = find_file(&buffer, project, buffer_position, cx).await;
14273
14274            if let Some((_, path)) = result {
14275                workspace
14276                    .update_in(cx, |workspace, window, cx| {
14277                        workspace.open_resolved_path(path, window, cx)
14278                    })?
14279                    .await?;
14280            }
14281            anyhow::Ok(())
14282        })
14283        .detach();
14284    }
14285
14286    pub(crate) fn navigate_to_hover_links(
14287        &mut self,
14288        kind: Option<GotoDefinitionKind>,
14289        mut definitions: Vec<HoverLink>,
14290        split: bool,
14291        window: &mut Window,
14292        cx: &mut Context<Editor>,
14293    ) -> Task<Result<Navigated>> {
14294        // If there is one definition, just open it directly
14295        if definitions.len() == 1 {
14296            let definition = definitions.pop().unwrap();
14297
14298            enum TargetTaskResult {
14299                Location(Option<Location>),
14300                AlreadyNavigated,
14301            }
14302
14303            let target_task = match definition {
14304                HoverLink::Text(link) => {
14305                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14306                }
14307                HoverLink::InlayHint(lsp_location, server_id) => {
14308                    let computation =
14309                        self.compute_target_location(lsp_location, server_id, window, cx);
14310                    cx.background_spawn(async move {
14311                        let location = computation.await?;
14312                        Ok(TargetTaskResult::Location(location))
14313                    })
14314                }
14315                HoverLink::Url(url) => {
14316                    cx.open_url(&url);
14317                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14318                }
14319                HoverLink::File(path) => {
14320                    if let Some(workspace) = self.workspace() {
14321                        cx.spawn_in(window, async move |_, cx| {
14322                            workspace
14323                                .update_in(cx, |workspace, window, cx| {
14324                                    workspace.open_resolved_path(path, window, cx)
14325                                })?
14326                                .await
14327                                .map(|_| TargetTaskResult::AlreadyNavigated)
14328                        })
14329                    } else {
14330                        Task::ready(Ok(TargetTaskResult::Location(None)))
14331                    }
14332                }
14333            };
14334            cx.spawn_in(window, async move |editor, cx| {
14335                let target = match target_task.await.context("target resolution task")? {
14336                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14337                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14338                    TargetTaskResult::Location(Some(target)) => target,
14339                };
14340
14341                editor.update_in(cx, |editor, window, cx| {
14342                    let Some(workspace) = editor.workspace() else {
14343                        return Navigated::No;
14344                    };
14345                    let pane = workspace.read(cx).active_pane().clone();
14346
14347                    let range = target.range.to_point(target.buffer.read(cx));
14348                    let range = editor.range_for_match(&range);
14349                    let range = collapse_multiline_range(range);
14350
14351                    if !split
14352                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14353                    {
14354                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14355                    } else {
14356                        window.defer(cx, move |window, cx| {
14357                            let target_editor: Entity<Self> =
14358                                workspace.update(cx, |workspace, cx| {
14359                                    let pane = if split {
14360                                        workspace.adjacent_pane(window, cx)
14361                                    } else {
14362                                        workspace.active_pane().clone()
14363                                    };
14364
14365                                    workspace.open_project_item(
14366                                        pane,
14367                                        target.buffer.clone(),
14368                                        true,
14369                                        true,
14370                                        window,
14371                                        cx,
14372                                    )
14373                                });
14374                            target_editor.update(cx, |target_editor, cx| {
14375                                // When selecting a definition in a different buffer, disable the nav history
14376                                // to avoid creating a history entry at the previous cursor location.
14377                                pane.update(cx, |pane, _| pane.disable_history());
14378                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14379                                pane.update(cx, |pane, _| pane.enable_history());
14380                            });
14381                        });
14382                    }
14383                    Navigated::Yes
14384                })
14385            })
14386        } else if !definitions.is_empty() {
14387            cx.spawn_in(window, async move |editor, cx| {
14388                let (title, location_tasks, workspace) = editor
14389                    .update_in(cx, |editor, window, cx| {
14390                        let tab_kind = match kind {
14391                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14392                            _ => "Definitions",
14393                        };
14394                        let title = definitions
14395                            .iter()
14396                            .find_map(|definition| match definition {
14397                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14398                                    let buffer = origin.buffer.read(cx);
14399                                    format!(
14400                                        "{} for {}",
14401                                        tab_kind,
14402                                        buffer
14403                                            .text_for_range(origin.range.clone())
14404                                            .collect::<String>()
14405                                    )
14406                                }),
14407                                HoverLink::InlayHint(_, _) => None,
14408                                HoverLink::Url(_) => None,
14409                                HoverLink::File(_) => None,
14410                            })
14411                            .unwrap_or(tab_kind.to_string());
14412                        let location_tasks = definitions
14413                            .into_iter()
14414                            .map(|definition| match definition {
14415                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14416                                HoverLink::InlayHint(lsp_location, server_id) => editor
14417                                    .compute_target_location(lsp_location, server_id, window, cx),
14418                                HoverLink::Url(_) => Task::ready(Ok(None)),
14419                                HoverLink::File(_) => Task::ready(Ok(None)),
14420                            })
14421                            .collect::<Vec<_>>();
14422                        (title, location_tasks, editor.workspace().clone())
14423                    })
14424                    .context("location tasks preparation")?;
14425
14426                let locations = future::join_all(location_tasks)
14427                    .await
14428                    .into_iter()
14429                    .filter_map(|location| location.transpose())
14430                    .collect::<Result<_>>()
14431                    .context("location tasks")?;
14432
14433                let Some(workspace) = workspace else {
14434                    return Ok(Navigated::No);
14435                };
14436                let opened = workspace
14437                    .update_in(cx, |workspace, window, cx| {
14438                        Self::open_locations_in_multibuffer(
14439                            workspace,
14440                            locations,
14441                            title,
14442                            split,
14443                            MultibufferSelectionMode::First,
14444                            window,
14445                            cx,
14446                        )
14447                    })
14448                    .ok();
14449
14450                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14451            })
14452        } else {
14453            Task::ready(Ok(Navigated::No))
14454        }
14455    }
14456
14457    fn compute_target_location(
14458        &self,
14459        lsp_location: lsp::Location,
14460        server_id: LanguageServerId,
14461        window: &mut Window,
14462        cx: &mut Context<Self>,
14463    ) -> Task<anyhow::Result<Option<Location>>> {
14464        let Some(project) = self.project.clone() else {
14465            return Task::ready(Ok(None));
14466        };
14467
14468        cx.spawn_in(window, async move |editor, cx| {
14469            let location_task = editor.update(cx, |_, cx| {
14470                project.update(cx, |project, cx| {
14471                    let language_server_name = project
14472                        .language_server_statuses(cx)
14473                        .find(|(id, _)| server_id == *id)
14474                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14475                    language_server_name.map(|language_server_name| {
14476                        project.open_local_buffer_via_lsp(
14477                            lsp_location.uri.clone(),
14478                            server_id,
14479                            language_server_name,
14480                            cx,
14481                        )
14482                    })
14483                })
14484            })?;
14485            let location = match location_task {
14486                Some(task) => Some({
14487                    let target_buffer_handle = task.await.context("open local buffer")?;
14488                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14489                        let target_start = target_buffer
14490                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14491                        let target_end = target_buffer
14492                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14493                        target_buffer.anchor_after(target_start)
14494                            ..target_buffer.anchor_before(target_end)
14495                    })?;
14496                    Location {
14497                        buffer: target_buffer_handle,
14498                        range,
14499                    }
14500                }),
14501                None => None,
14502            };
14503            Ok(location)
14504        })
14505    }
14506
14507    pub fn find_all_references(
14508        &mut self,
14509        _: &FindAllReferences,
14510        window: &mut Window,
14511        cx: &mut Context<Self>,
14512    ) -> Option<Task<Result<Navigated>>> {
14513        let selection = self.selections.newest::<usize>(cx);
14514        let multi_buffer = self.buffer.read(cx);
14515        let head = selection.head();
14516
14517        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14518        let head_anchor = multi_buffer_snapshot.anchor_at(
14519            head,
14520            if head < selection.tail() {
14521                Bias::Right
14522            } else {
14523                Bias::Left
14524            },
14525        );
14526
14527        match self
14528            .find_all_references_task_sources
14529            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14530        {
14531            Ok(_) => {
14532                log::info!(
14533                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14534                );
14535                return None;
14536            }
14537            Err(i) => {
14538                self.find_all_references_task_sources.insert(i, head_anchor);
14539            }
14540        }
14541
14542        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14543        let workspace = self.workspace()?;
14544        let project = workspace.read(cx).project().clone();
14545        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14546        Some(cx.spawn_in(window, async move |editor, cx| {
14547            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14548                if let Ok(i) = editor
14549                    .find_all_references_task_sources
14550                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14551                {
14552                    editor.find_all_references_task_sources.remove(i);
14553                }
14554            });
14555
14556            let locations = references.await?;
14557            if locations.is_empty() {
14558                return anyhow::Ok(Navigated::No);
14559            }
14560
14561            workspace.update_in(cx, |workspace, window, cx| {
14562                let title = locations
14563                    .first()
14564                    .as_ref()
14565                    .map(|location| {
14566                        let buffer = location.buffer.read(cx);
14567                        format!(
14568                            "References to `{}`",
14569                            buffer
14570                                .text_for_range(location.range.clone())
14571                                .collect::<String>()
14572                        )
14573                    })
14574                    .unwrap();
14575                Self::open_locations_in_multibuffer(
14576                    workspace,
14577                    locations,
14578                    title,
14579                    false,
14580                    MultibufferSelectionMode::First,
14581                    window,
14582                    cx,
14583                );
14584                Navigated::Yes
14585            })
14586        }))
14587    }
14588
14589    /// Opens a multibuffer with the given project locations in it
14590    pub fn open_locations_in_multibuffer(
14591        workspace: &mut Workspace,
14592        mut locations: Vec<Location>,
14593        title: String,
14594        split: bool,
14595        multibuffer_selection_mode: MultibufferSelectionMode,
14596        window: &mut Window,
14597        cx: &mut Context<Workspace>,
14598    ) {
14599        // If there are multiple definitions, open them in a multibuffer
14600        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14601        let mut locations = locations.into_iter().peekable();
14602        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14603        let capability = workspace.project().read(cx).capability();
14604
14605        let excerpt_buffer = cx.new(|cx| {
14606            let mut multibuffer = MultiBuffer::new(capability);
14607            while let Some(location) = locations.next() {
14608                let buffer = location.buffer.read(cx);
14609                let mut ranges_for_buffer = Vec::new();
14610                let range = location.range.to_point(buffer);
14611                ranges_for_buffer.push(range.clone());
14612
14613                while let Some(next_location) = locations.peek() {
14614                    if next_location.buffer == location.buffer {
14615                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14616                        locations.next();
14617                    } else {
14618                        break;
14619                    }
14620                }
14621
14622                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14623                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14624                    PathKey::for_buffer(&location.buffer, cx),
14625                    location.buffer.clone(),
14626                    ranges_for_buffer,
14627                    DEFAULT_MULTIBUFFER_CONTEXT,
14628                    cx,
14629                );
14630                ranges.extend(new_ranges)
14631            }
14632
14633            multibuffer.with_title(title)
14634        });
14635
14636        let editor = cx.new(|cx| {
14637            Editor::for_multibuffer(
14638                excerpt_buffer,
14639                Some(workspace.project().clone()),
14640                window,
14641                cx,
14642            )
14643        });
14644        editor.update(cx, |editor, cx| {
14645            match multibuffer_selection_mode {
14646                MultibufferSelectionMode::First => {
14647                    if let Some(first_range) = ranges.first() {
14648                        editor.change_selections(None, window, cx, |selections| {
14649                            selections.clear_disjoint();
14650                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14651                        });
14652                    }
14653                    editor.highlight_background::<Self>(
14654                        &ranges,
14655                        |theme| theme.editor_highlighted_line_background,
14656                        cx,
14657                    );
14658                }
14659                MultibufferSelectionMode::All => {
14660                    editor.change_selections(None, window, cx, |selections| {
14661                        selections.clear_disjoint();
14662                        selections.select_anchor_ranges(ranges);
14663                    });
14664                }
14665            }
14666            editor.register_buffers_with_language_servers(cx);
14667        });
14668
14669        let item = Box::new(editor);
14670        let item_id = item.item_id();
14671
14672        if split {
14673            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14674        } else {
14675            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14676                let (preview_item_id, preview_item_idx) =
14677                    workspace.active_pane().update(cx, |pane, _| {
14678                        (pane.preview_item_id(), pane.preview_item_idx())
14679                    });
14680
14681                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14682
14683                if let Some(preview_item_id) = preview_item_id {
14684                    workspace.active_pane().update(cx, |pane, cx| {
14685                        pane.remove_item(preview_item_id, false, false, window, cx);
14686                    });
14687                }
14688            } else {
14689                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14690            }
14691        }
14692        workspace.active_pane().update(cx, |pane, cx| {
14693            pane.set_preview_item_id(Some(item_id), cx);
14694        });
14695    }
14696
14697    pub fn rename(
14698        &mut self,
14699        _: &Rename,
14700        window: &mut Window,
14701        cx: &mut Context<Self>,
14702    ) -> Option<Task<Result<()>>> {
14703        use language::ToOffset as _;
14704
14705        let provider = self.semantics_provider.clone()?;
14706        let selection = self.selections.newest_anchor().clone();
14707        let (cursor_buffer, cursor_buffer_position) = self
14708            .buffer
14709            .read(cx)
14710            .text_anchor_for_position(selection.head(), cx)?;
14711        let (tail_buffer, cursor_buffer_position_end) = self
14712            .buffer
14713            .read(cx)
14714            .text_anchor_for_position(selection.tail(), cx)?;
14715        if tail_buffer != cursor_buffer {
14716            return None;
14717        }
14718
14719        let snapshot = cursor_buffer.read(cx).snapshot();
14720        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14721        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14722        let prepare_rename = provider
14723            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14724            .unwrap_or_else(|| Task::ready(Ok(None)));
14725        drop(snapshot);
14726
14727        Some(cx.spawn_in(window, async move |this, cx| {
14728            let rename_range = if let Some(range) = prepare_rename.await? {
14729                Some(range)
14730            } else {
14731                this.update(cx, |this, cx| {
14732                    let buffer = this.buffer.read(cx).snapshot(cx);
14733                    let mut buffer_highlights = this
14734                        .document_highlights_for_position(selection.head(), &buffer)
14735                        .filter(|highlight| {
14736                            highlight.start.excerpt_id == selection.head().excerpt_id
14737                                && highlight.end.excerpt_id == selection.head().excerpt_id
14738                        });
14739                    buffer_highlights
14740                        .next()
14741                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14742                })?
14743            };
14744            if let Some(rename_range) = rename_range {
14745                this.update_in(cx, |this, window, cx| {
14746                    let snapshot = cursor_buffer.read(cx).snapshot();
14747                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14748                    let cursor_offset_in_rename_range =
14749                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14750                    let cursor_offset_in_rename_range_end =
14751                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14752
14753                    this.take_rename(false, window, cx);
14754                    let buffer = this.buffer.read(cx).read(cx);
14755                    let cursor_offset = selection.head().to_offset(&buffer);
14756                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14757                    let rename_end = rename_start + rename_buffer_range.len();
14758                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14759                    let mut old_highlight_id = None;
14760                    let old_name: Arc<str> = buffer
14761                        .chunks(rename_start..rename_end, true)
14762                        .map(|chunk| {
14763                            if old_highlight_id.is_none() {
14764                                old_highlight_id = chunk.syntax_highlight_id;
14765                            }
14766                            chunk.text
14767                        })
14768                        .collect::<String>()
14769                        .into();
14770
14771                    drop(buffer);
14772
14773                    // Position the selection in the rename editor so that it matches the current selection.
14774                    this.show_local_selections = false;
14775                    let rename_editor = cx.new(|cx| {
14776                        let mut editor = Editor::single_line(window, cx);
14777                        editor.buffer.update(cx, |buffer, cx| {
14778                            buffer.edit([(0..0, old_name.clone())], None, cx)
14779                        });
14780                        let rename_selection_range = match cursor_offset_in_rename_range
14781                            .cmp(&cursor_offset_in_rename_range_end)
14782                        {
14783                            Ordering::Equal => {
14784                                editor.select_all(&SelectAll, window, cx);
14785                                return editor;
14786                            }
14787                            Ordering::Less => {
14788                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14789                            }
14790                            Ordering::Greater => {
14791                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14792                            }
14793                        };
14794                        if rename_selection_range.end > old_name.len() {
14795                            editor.select_all(&SelectAll, window, cx);
14796                        } else {
14797                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14798                                s.select_ranges([rename_selection_range]);
14799                            });
14800                        }
14801                        editor
14802                    });
14803                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14804                        if e == &EditorEvent::Focused {
14805                            cx.emit(EditorEvent::FocusedIn)
14806                        }
14807                    })
14808                    .detach();
14809
14810                    let write_highlights =
14811                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14812                    let read_highlights =
14813                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14814                    let ranges = write_highlights
14815                        .iter()
14816                        .flat_map(|(_, ranges)| ranges.iter())
14817                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14818                        .cloned()
14819                        .collect();
14820
14821                    this.highlight_text::<Rename>(
14822                        ranges,
14823                        HighlightStyle {
14824                            fade_out: Some(0.6),
14825                            ..Default::default()
14826                        },
14827                        cx,
14828                    );
14829                    let rename_focus_handle = rename_editor.focus_handle(cx);
14830                    window.focus(&rename_focus_handle);
14831                    let block_id = this.insert_blocks(
14832                        [BlockProperties {
14833                            style: BlockStyle::Flex,
14834                            placement: BlockPlacement::Below(range.start),
14835                            height: Some(1),
14836                            render: Arc::new({
14837                                let rename_editor = rename_editor.clone();
14838                                move |cx: &mut BlockContext| {
14839                                    let mut text_style = cx.editor_style.text.clone();
14840                                    if let Some(highlight_style) = old_highlight_id
14841                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14842                                    {
14843                                        text_style = text_style.highlight(highlight_style);
14844                                    }
14845                                    div()
14846                                        .block_mouse_down()
14847                                        .pl(cx.anchor_x)
14848                                        .child(EditorElement::new(
14849                                            &rename_editor,
14850                                            EditorStyle {
14851                                                background: cx.theme().system().transparent,
14852                                                local_player: cx.editor_style.local_player,
14853                                                text: text_style,
14854                                                scrollbar_width: cx.editor_style.scrollbar_width,
14855                                                syntax: cx.editor_style.syntax.clone(),
14856                                                status: cx.editor_style.status.clone(),
14857                                                inlay_hints_style: HighlightStyle {
14858                                                    font_weight: Some(FontWeight::BOLD),
14859                                                    ..make_inlay_hints_style(cx.app)
14860                                                },
14861                                                inline_completion_styles: make_suggestion_styles(
14862                                                    cx.app,
14863                                                ),
14864                                                ..EditorStyle::default()
14865                                            },
14866                                        ))
14867                                        .into_any_element()
14868                                }
14869                            }),
14870                            priority: 0,
14871                            render_in_minimap: true,
14872                        }],
14873                        Some(Autoscroll::fit()),
14874                        cx,
14875                    )[0];
14876                    this.pending_rename = Some(RenameState {
14877                        range,
14878                        old_name,
14879                        editor: rename_editor,
14880                        block_id,
14881                    });
14882                })?;
14883            }
14884
14885            Ok(())
14886        }))
14887    }
14888
14889    pub fn confirm_rename(
14890        &mut self,
14891        _: &ConfirmRename,
14892        window: &mut Window,
14893        cx: &mut Context<Self>,
14894    ) -> Option<Task<Result<()>>> {
14895        let rename = self.take_rename(false, window, cx)?;
14896        let workspace = self.workspace()?.downgrade();
14897        let (buffer, start) = self
14898            .buffer
14899            .read(cx)
14900            .text_anchor_for_position(rename.range.start, cx)?;
14901        let (end_buffer, _) = self
14902            .buffer
14903            .read(cx)
14904            .text_anchor_for_position(rename.range.end, cx)?;
14905        if buffer != end_buffer {
14906            return None;
14907        }
14908
14909        let old_name = rename.old_name;
14910        let new_name = rename.editor.read(cx).text(cx);
14911
14912        let rename = self.semantics_provider.as_ref()?.perform_rename(
14913            &buffer,
14914            start,
14915            new_name.clone(),
14916            cx,
14917        )?;
14918
14919        Some(cx.spawn_in(window, async move |editor, cx| {
14920            let project_transaction = rename.await?;
14921            Self::open_project_transaction(
14922                &editor,
14923                workspace,
14924                project_transaction,
14925                format!("Rename: {}{}", old_name, new_name),
14926                cx,
14927            )
14928            .await?;
14929
14930            editor.update(cx, |editor, cx| {
14931                editor.refresh_document_highlights(cx);
14932            })?;
14933            Ok(())
14934        }))
14935    }
14936
14937    fn take_rename(
14938        &mut self,
14939        moving_cursor: bool,
14940        window: &mut Window,
14941        cx: &mut Context<Self>,
14942    ) -> Option<RenameState> {
14943        let rename = self.pending_rename.take()?;
14944        if rename.editor.focus_handle(cx).is_focused(window) {
14945            window.focus(&self.focus_handle);
14946        }
14947
14948        self.remove_blocks(
14949            [rename.block_id].into_iter().collect(),
14950            Some(Autoscroll::fit()),
14951            cx,
14952        );
14953        self.clear_highlights::<Rename>(cx);
14954        self.show_local_selections = true;
14955
14956        if moving_cursor {
14957            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14958                editor.selections.newest::<usize>(cx).head()
14959            });
14960
14961            // Update the selection to match the position of the selection inside
14962            // the rename editor.
14963            let snapshot = self.buffer.read(cx).read(cx);
14964            let rename_range = rename.range.to_offset(&snapshot);
14965            let cursor_in_editor = snapshot
14966                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14967                .min(rename_range.end);
14968            drop(snapshot);
14969
14970            self.change_selections(None, window, cx, |s| {
14971                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14972            });
14973        } else {
14974            self.refresh_document_highlights(cx);
14975        }
14976
14977        Some(rename)
14978    }
14979
14980    pub fn pending_rename(&self) -> Option<&RenameState> {
14981        self.pending_rename.as_ref()
14982    }
14983
14984    fn format(
14985        &mut self,
14986        _: &Format,
14987        window: &mut Window,
14988        cx: &mut Context<Self>,
14989    ) -> Option<Task<Result<()>>> {
14990        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14991
14992        let project = match &self.project {
14993            Some(project) => project.clone(),
14994            None => return None,
14995        };
14996
14997        Some(self.perform_format(
14998            project,
14999            FormatTrigger::Manual,
15000            FormatTarget::Buffers,
15001            window,
15002            cx,
15003        ))
15004    }
15005
15006    fn format_selections(
15007        &mut self,
15008        _: &FormatSelections,
15009        window: &mut Window,
15010        cx: &mut Context<Self>,
15011    ) -> Option<Task<Result<()>>> {
15012        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15013
15014        let project = match &self.project {
15015            Some(project) => project.clone(),
15016            None => return None,
15017        };
15018
15019        let ranges = self
15020            .selections
15021            .all_adjusted(cx)
15022            .into_iter()
15023            .map(|selection| selection.range())
15024            .collect_vec();
15025
15026        Some(self.perform_format(
15027            project,
15028            FormatTrigger::Manual,
15029            FormatTarget::Ranges(ranges),
15030            window,
15031            cx,
15032        ))
15033    }
15034
15035    fn perform_format(
15036        &mut self,
15037        project: Entity<Project>,
15038        trigger: FormatTrigger,
15039        target: FormatTarget,
15040        window: &mut Window,
15041        cx: &mut Context<Self>,
15042    ) -> Task<Result<()>> {
15043        let buffer = self.buffer.clone();
15044        let (buffers, target) = match target {
15045            FormatTarget::Buffers => {
15046                let mut buffers = buffer.read(cx).all_buffers();
15047                if trigger == FormatTrigger::Save {
15048                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15049                }
15050                (buffers, LspFormatTarget::Buffers)
15051            }
15052            FormatTarget::Ranges(selection_ranges) => {
15053                let multi_buffer = buffer.read(cx);
15054                let snapshot = multi_buffer.read(cx);
15055                let mut buffers = HashSet::default();
15056                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15057                    BTreeMap::new();
15058                for selection_range in selection_ranges {
15059                    for (buffer, buffer_range, _) in
15060                        snapshot.range_to_buffer_ranges(selection_range)
15061                    {
15062                        let buffer_id = buffer.remote_id();
15063                        let start = buffer.anchor_before(buffer_range.start);
15064                        let end = buffer.anchor_after(buffer_range.end);
15065                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15066                        buffer_id_to_ranges
15067                            .entry(buffer_id)
15068                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15069                            .or_insert_with(|| vec![start..end]);
15070                    }
15071                }
15072                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15073            }
15074        };
15075
15076        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15077        let selections_prev = transaction_id_prev
15078            .and_then(|transaction_id_prev| {
15079                // default to selections as they were after the last edit, if we have them,
15080                // instead of how they are now.
15081                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15082                // will take you back to where you made the last edit, instead of staying where you scrolled
15083                self.selection_history
15084                    .transaction(transaction_id_prev)
15085                    .map(|t| t.0.clone())
15086            })
15087            .unwrap_or_else(|| {
15088                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15089                self.selections.disjoint_anchors()
15090            });
15091
15092        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15093        let format = project.update(cx, |project, cx| {
15094            project.format(buffers, target, true, trigger, cx)
15095        });
15096
15097        cx.spawn_in(window, async move |editor, cx| {
15098            let transaction = futures::select_biased! {
15099                transaction = format.log_err().fuse() => transaction,
15100                () = timeout => {
15101                    log::warn!("timed out waiting for formatting");
15102                    None
15103                }
15104            };
15105
15106            buffer
15107                .update(cx, |buffer, cx| {
15108                    if let Some(transaction) = transaction {
15109                        if !buffer.is_singleton() {
15110                            buffer.push_transaction(&transaction.0, cx);
15111                        }
15112                    }
15113                    cx.notify();
15114                })
15115                .ok();
15116
15117            if let Some(transaction_id_now) =
15118                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15119            {
15120                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15121                if has_new_transaction {
15122                    _ = editor.update(cx, |editor, _| {
15123                        editor
15124                            .selection_history
15125                            .insert_transaction(transaction_id_now, selections_prev);
15126                    });
15127                }
15128            }
15129
15130            Ok(())
15131        })
15132    }
15133
15134    fn organize_imports(
15135        &mut self,
15136        _: &OrganizeImports,
15137        window: &mut Window,
15138        cx: &mut Context<Self>,
15139    ) -> Option<Task<Result<()>>> {
15140        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15141        let project = match &self.project {
15142            Some(project) => project.clone(),
15143            None => return None,
15144        };
15145        Some(self.perform_code_action_kind(
15146            project,
15147            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15148            window,
15149            cx,
15150        ))
15151    }
15152
15153    fn perform_code_action_kind(
15154        &mut self,
15155        project: Entity<Project>,
15156        kind: CodeActionKind,
15157        window: &mut Window,
15158        cx: &mut Context<Self>,
15159    ) -> Task<Result<()>> {
15160        let buffer = self.buffer.clone();
15161        let buffers = buffer.read(cx).all_buffers();
15162        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15163        let apply_action = project.update(cx, |project, cx| {
15164            project.apply_code_action_kind(buffers, kind, true, cx)
15165        });
15166        cx.spawn_in(window, async move |_, cx| {
15167            let transaction = futures::select_biased! {
15168                () = timeout => {
15169                    log::warn!("timed out waiting for executing code action");
15170                    None
15171                }
15172                transaction = apply_action.log_err().fuse() => transaction,
15173            };
15174            buffer
15175                .update(cx, |buffer, cx| {
15176                    // check if we need this
15177                    if let Some(transaction) = transaction {
15178                        if !buffer.is_singleton() {
15179                            buffer.push_transaction(&transaction.0, cx);
15180                        }
15181                    }
15182                    cx.notify();
15183                })
15184                .ok();
15185            Ok(())
15186        })
15187    }
15188
15189    fn restart_language_server(
15190        &mut self,
15191        _: &RestartLanguageServer,
15192        _: &mut Window,
15193        cx: &mut Context<Self>,
15194    ) {
15195        if let Some(project) = self.project.clone() {
15196            self.buffer.update(cx, |multi_buffer, cx| {
15197                project.update(cx, |project, cx| {
15198                    project.restart_language_servers_for_buffers(
15199                        multi_buffer.all_buffers().into_iter().collect(),
15200                        cx,
15201                    );
15202                });
15203            })
15204        }
15205    }
15206
15207    fn stop_language_server(
15208        &mut self,
15209        _: &StopLanguageServer,
15210        _: &mut Window,
15211        cx: &mut Context<Self>,
15212    ) {
15213        if let Some(project) = self.project.clone() {
15214            self.buffer.update(cx, |multi_buffer, cx| {
15215                project.update(cx, |project, cx| {
15216                    project.stop_language_servers_for_buffers(
15217                        multi_buffer.all_buffers().into_iter().collect(),
15218                        cx,
15219                    );
15220                    cx.emit(project::Event::RefreshInlayHints);
15221                });
15222            });
15223        }
15224    }
15225
15226    fn cancel_language_server_work(
15227        workspace: &mut Workspace,
15228        _: &actions::CancelLanguageServerWork,
15229        _: &mut Window,
15230        cx: &mut Context<Workspace>,
15231    ) {
15232        let project = workspace.project();
15233        let buffers = workspace
15234            .active_item(cx)
15235            .and_then(|item| item.act_as::<Editor>(cx))
15236            .map_or(HashSet::default(), |editor| {
15237                editor.read(cx).buffer.read(cx).all_buffers()
15238            });
15239        project.update(cx, |project, cx| {
15240            project.cancel_language_server_work_for_buffers(buffers, cx);
15241        });
15242    }
15243
15244    fn show_character_palette(
15245        &mut self,
15246        _: &ShowCharacterPalette,
15247        window: &mut Window,
15248        _: &mut Context<Self>,
15249    ) {
15250        window.show_character_palette();
15251    }
15252
15253    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15254        if self.mode.is_minimap() {
15255            return;
15256        }
15257
15258        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15259            let buffer = self.buffer.read(cx).snapshot(cx);
15260            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15261            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15262            let is_valid = buffer
15263                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15264                .any(|entry| {
15265                    entry.diagnostic.is_primary
15266                        && !entry.range.is_empty()
15267                        && entry.range.start == primary_range_start
15268                        && entry.diagnostic.message == active_diagnostics.active_message
15269                });
15270
15271            if !is_valid {
15272                self.dismiss_diagnostics(cx);
15273            }
15274        }
15275    }
15276
15277    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15278        match &self.active_diagnostics {
15279            ActiveDiagnostic::Group(group) => Some(group),
15280            _ => None,
15281        }
15282    }
15283
15284    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15285        self.dismiss_diagnostics(cx);
15286        self.active_diagnostics = ActiveDiagnostic::All;
15287    }
15288
15289    fn activate_diagnostics(
15290        &mut self,
15291        buffer_id: BufferId,
15292        diagnostic: DiagnosticEntry<usize>,
15293        window: &mut Window,
15294        cx: &mut Context<Self>,
15295    ) {
15296        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15297            return;
15298        }
15299        self.dismiss_diagnostics(cx);
15300        let snapshot = self.snapshot(window, cx);
15301        let buffer = self.buffer.read(cx).snapshot(cx);
15302        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15303            return;
15304        };
15305
15306        let diagnostic_group = buffer
15307            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15308            .collect::<Vec<_>>();
15309
15310        let blocks =
15311            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15312
15313        let blocks = self.display_map.update(cx, |display_map, cx| {
15314            display_map.insert_blocks(blocks, cx).into_iter().collect()
15315        });
15316        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15317            active_range: buffer.anchor_before(diagnostic.range.start)
15318                ..buffer.anchor_after(diagnostic.range.end),
15319            active_message: diagnostic.diagnostic.message.clone(),
15320            group_id: diagnostic.diagnostic.group_id,
15321            blocks,
15322        });
15323        cx.notify();
15324    }
15325
15326    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15327        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15328            return;
15329        };
15330
15331        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15332        if let ActiveDiagnostic::Group(group) = prev {
15333            self.display_map.update(cx, |display_map, cx| {
15334                display_map.remove_blocks(group.blocks, cx);
15335            });
15336            cx.notify();
15337        }
15338    }
15339
15340    /// Disable inline diagnostics rendering for this editor.
15341    pub fn disable_inline_diagnostics(&mut self) {
15342        self.inline_diagnostics_enabled = false;
15343        self.inline_diagnostics_update = Task::ready(());
15344        self.inline_diagnostics.clear();
15345    }
15346
15347    pub fn diagnostics_enabled(&self) -> bool {
15348        self.mode.is_full()
15349    }
15350
15351    pub fn inline_diagnostics_enabled(&self) -> bool {
15352        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15353    }
15354
15355    pub fn show_inline_diagnostics(&self) -> bool {
15356        self.show_inline_diagnostics
15357    }
15358
15359    pub fn toggle_inline_diagnostics(
15360        &mut self,
15361        _: &ToggleInlineDiagnostics,
15362        window: &mut Window,
15363        cx: &mut Context<Editor>,
15364    ) {
15365        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15366        self.refresh_inline_diagnostics(false, window, cx);
15367    }
15368
15369    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15370        self.diagnostics_max_severity = severity;
15371        self.display_map.update(cx, |display_map, _| {
15372            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15373        });
15374    }
15375
15376    pub fn toggle_diagnostics(
15377        &mut self,
15378        _: &ToggleDiagnostics,
15379        window: &mut Window,
15380        cx: &mut Context<Editor>,
15381    ) {
15382        if !self.diagnostics_enabled() {
15383            return;
15384        }
15385
15386        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15387            EditorSettings::get_global(cx)
15388                .diagnostics_max_severity
15389                .filter(|severity| severity != &DiagnosticSeverity::Off)
15390                .unwrap_or(DiagnosticSeverity::Hint)
15391        } else {
15392            DiagnosticSeverity::Off
15393        };
15394        self.set_max_diagnostics_severity(new_severity, cx);
15395        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15396            self.active_diagnostics = ActiveDiagnostic::None;
15397            self.inline_diagnostics_update = Task::ready(());
15398            self.inline_diagnostics.clear();
15399        } else {
15400            self.refresh_inline_diagnostics(false, window, cx);
15401        }
15402
15403        cx.notify();
15404    }
15405
15406    pub fn toggle_minimap(
15407        &mut self,
15408        _: &ToggleMinimap,
15409        window: &mut Window,
15410        cx: &mut Context<Editor>,
15411    ) {
15412        if self.supports_minimap(cx) {
15413            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15414        }
15415    }
15416
15417    fn refresh_inline_diagnostics(
15418        &mut self,
15419        debounce: bool,
15420        window: &mut Window,
15421        cx: &mut Context<Self>,
15422    ) {
15423        let max_severity = ProjectSettings::get_global(cx)
15424            .diagnostics
15425            .inline
15426            .max_severity
15427            .unwrap_or(self.diagnostics_max_severity);
15428
15429        if self.mode.is_minimap()
15430            || !self.inline_diagnostics_enabled()
15431            || !self.show_inline_diagnostics
15432            || max_severity == DiagnosticSeverity::Off
15433        {
15434            self.inline_diagnostics_update = Task::ready(());
15435            self.inline_diagnostics.clear();
15436            return;
15437        }
15438
15439        let debounce_ms = ProjectSettings::get_global(cx)
15440            .diagnostics
15441            .inline
15442            .update_debounce_ms;
15443        let debounce = if debounce && debounce_ms > 0 {
15444            Some(Duration::from_millis(debounce_ms))
15445        } else {
15446            None
15447        };
15448        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15449            let editor = editor.upgrade().unwrap();
15450
15451            if let Some(debounce) = debounce {
15452                cx.background_executor().timer(debounce).await;
15453            }
15454            let Some(snapshot) = editor
15455                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15456                .ok()
15457            else {
15458                return;
15459            };
15460
15461            let new_inline_diagnostics = cx
15462                .background_spawn(async move {
15463                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15464                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15465                        let message = diagnostic_entry
15466                            .diagnostic
15467                            .message
15468                            .split_once('\n')
15469                            .map(|(line, _)| line)
15470                            .map(SharedString::new)
15471                            .unwrap_or_else(|| {
15472                                SharedString::from(diagnostic_entry.diagnostic.message)
15473                            });
15474                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15475                        let (Ok(i) | Err(i)) = inline_diagnostics
15476                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15477                        inline_diagnostics.insert(
15478                            i,
15479                            (
15480                                start_anchor,
15481                                InlineDiagnostic {
15482                                    message,
15483                                    group_id: diagnostic_entry.diagnostic.group_id,
15484                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15485                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15486                                    severity: diagnostic_entry.diagnostic.severity,
15487                                },
15488                            ),
15489                        );
15490                    }
15491                    inline_diagnostics
15492                })
15493                .await;
15494
15495            editor
15496                .update(cx, |editor, cx| {
15497                    editor.inline_diagnostics = new_inline_diagnostics;
15498                    cx.notify();
15499                })
15500                .ok();
15501        });
15502    }
15503
15504    pub fn set_selections_from_remote(
15505        &mut self,
15506        selections: Vec<Selection<Anchor>>,
15507        pending_selection: Option<Selection<Anchor>>,
15508        window: &mut Window,
15509        cx: &mut Context<Self>,
15510    ) {
15511        let old_cursor_position = self.selections.newest_anchor().head();
15512        self.selections.change_with(cx, |s| {
15513            s.select_anchors(selections);
15514            if let Some(pending_selection) = pending_selection {
15515                s.set_pending(pending_selection, SelectMode::Character);
15516            } else {
15517                s.clear_pending();
15518            }
15519        });
15520        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15521    }
15522
15523    fn push_to_selection_history(&mut self) {
15524        self.selection_history.push(SelectionHistoryEntry {
15525            selections: self.selections.disjoint_anchors(),
15526            select_next_state: self.select_next_state.clone(),
15527            select_prev_state: self.select_prev_state.clone(),
15528            add_selections_state: self.add_selections_state.clone(),
15529        });
15530    }
15531
15532    pub fn transact(
15533        &mut self,
15534        window: &mut Window,
15535        cx: &mut Context<Self>,
15536        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15537    ) -> Option<TransactionId> {
15538        self.start_transaction_at(Instant::now(), window, cx);
15539        update(self, window, cx);
15540        self.end_transaction_at(Instant::now(), cx)
15541    }
15542
15543    pub fn start_transaction_at(
15544        &mut self,
15545        now: Instant,
15546        window: &mut Window,
15547        cx: &mut Context<Self>,
15548    ) {
15549        self.end_selection(window, cx);
15550        if let Some(tx_id) = self
15551            .buffer
15552            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15553        {
15554            self.selection_history
15555                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15556            cx.emit(EditorEvent::TransactionBegun {
15557                transaction_id: tx_id,
15558            })
15559        }
15560    }
15561
15562    pub fn end_transaction_at(
15563        &mut self,
15564        now: Instant,
15565        cx: &mut Context<Self>,
15566    ) -> Option<TransactionId> {
15567        if let Some(transaction_id) = self
15568            .buffer
15569            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15570        {
15571            if let Some((_, end_selections)) =
15572                self.selection_history.transaction_mut(transaction_id)
15573            {
15574                *end_selections = Some(self.selections.disjoint_anchors());
15575            } else {
15576                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15577            }
15578
15579            cx.emit(EditorEvent::Edited { transaction_id });
15580            Some(transaction_id)
15581        } else {
15582            None
15583        }
15584    }
15585
15586    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15587        if self.selection_mark_mode {
15588            self.change_selections(None, window, cx, |s| {
15589                s.move_with(|_, sel| {
15590                    sel.collapse_to(sel.head(), SelectionGoal::None);
15591                });
15592            })
15593        }
15594        self.selection_mark_mode = true;
15595        cx.notify();
15596    }
15597
15598    pub fn swap_selection_ends(
15599        &mut self,
15600        _: &actions::SwapSelectionEnds,
15601        window: &mut Window,
15602        cx: &mut Context<Self>,
15603    ) {
15604        self.change_selections(None, window, cx, |s| {
15605            s.move_with(|_, sel| {
15606                if sel.start != sel.end {
15607                    sel.reversed = !sel.reversed
15608                }
15609            });
15610        });
15611        self.request_autoscroll(Autoscroll::newest(), cx);
15612        cx.notify();
15613    }
15614
15615    pub fn toggle_fold(
15616        &mut self,
15617        _: &actions::ToggleFold,
15618        window: &mut Window,
15619        cx: &mut Context<Self>,
15620    ) {
15621        if self.is_singleton(cx) {
15622            let selection = self.selections.newest::<Point>(cx);
15623
15624            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15625            let range = if selection.is_empty() {
15626                let point = selection.head().to_display_point(&display_map);
15627                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15628                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15629                    .to_point(&display_map);
15630                start..end
15631            } else {
15632                selection.range()
15633            };
15634            if display_map.folds_in_range(range).next().is_some() {
15635                self.unfold_lines(&Default::default(), window, cx)
15636            } else {
15637                self.fold(&Default::default(), window, cx)
15638            }
15639        } else {
15640            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15641            let buffer_ids: HashSet<_> = self
15642                .selections
15643                .disjoint_anchor_ranges()
15644                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15645                .collect();
15646
15647            let should_unfold = buffer_ids
15648                .iter()
15649                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15650
15651            for buffer_id in buffer_ids {
15652                if should_unfold {
15653                    self.unfold_buffer(buffer_id, cx);
15654                } else {
15655                    self.fold_buffer(buffer_id, cx);
15656                }
15657            }
15658        }
15659    }
15660
15661    pub fn toggle_fold_recursive(
15662        &mut self,
15663        _: &actions::ToggleFoldRecursive,
15664        window: &mut Window,
15665        cx: &mut Context<Self>,
15666    ) {
15667        let selection = self.selections.newest::<Point>(cx);
15668
15669        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15670        let range = if selection.is_empty() {
15671            let point = selection.head().to_display_point(&display_map);
15672            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15673            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15674                .to_point(&display_map);
15675            start..end
15676        } else {
15677            selection.range()
15678        };
15679        if display_map.folds_in_range(range).next().is_some() {
15680            self.unfold_recursive(&Default::default(), window, cx)
15681        } else {
15682            self.fold_recursive(&Default::default(), window, cx)
15683        }
15684    }
15685
15686    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15687        if self.is_singleton(cx) {
15688            let mut to_fold = Vec::new();
15689            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15690            let selections = self.selections.all_adjusted(cx);
15691
15692            for selection in selections {
15693                let range = selection.range().sorted();
15694                let buffer_start_row = range.start.row;
15695
15696                if range.start.row != range.end.row {
15697                    let mut found = false;
15698                    let mut row = range.start.row;
15699                    while row <= range.end.row {
15700                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15701                        {
15702                            found = true;
15703                            row = crease.range().end.row + 1;
15704                            to_fold.push(crease);
15705                        } else {
15706                            row += 1
15707                        }
15708                    }
15709                    if found {
15710                        continue;
15711                    }
15712                }
15713
15714                for row in (0..=range.start.row).rev() {
15715                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15716                        if crease.range().end.row >= buffer_start_row {
15717                            to_fold.push(crease);
15718                            if row <= range.start.row {
15719                                break;
15720                            }
15721                        }
15722                    }
15723                }
15724            }
15725
15726            self.fold_creases(to_fold, true, window, cx);
15727        } else {
15728            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15729            let buffer_ids = self
15730                .selections
15731                .disjoint_anchor_ranges()
15732                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15733                .collect::<HashSet<_>>();
15734            for buffer_id in buffer_ids {
15735                self.fold_buffer(buffer_id, cx);
15736            }
15737        }
15738    }
15739
15740    fn fold_at_level(
15741        &mut self,
15742        fold_at: &FoldAtLevel,
15743        window: &mut Window,
15744        cx: &mut Context<Self>,
15745    ) {
15746        if !self.buffer.read(cx).is_singleton() {
15747            return;
15748        }
15749
15750        let fold_at_level = fold_at.0;
15751        let snapshot = self.buffer.read(cx).snapshot(cx);
15752        let mut to_fold = Vec::new();
15753        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15754
15755        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15756            while start_row < end_row {
15757                match self
15758                    .snapshot(window, cx)
15759                    .crease_for_buffer_row(MultiBufferRow(start_row))
15760                {
15761                    Some(crease) => {
15762                        let nested_start_row = crease.range().start.row + 1;
15763                        let nested_end_row = crease.range().end.row;
15764
15765                        if current_level < fold_at_level {
15766                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15767                        } else if current_level == fold_at_level {
15768                            to_fold.push(crease);
15769                        }
15770
15771                        start_row = nested_end_row + 1;
15772                    }
15773                    None => start_row += 1,
15774                }
15775            }
15776        }
15777
15778        self.fold_creases(to_fold, true, window, cx);
15779    }
15780
15781    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15782        if self.buffer.read(cx).is_singleton() {
15783            let mut fold_ranges = Vec::new();
15784            let snapshot = self.buffer.read(cx).snapshot(cx);
15785
15786            for row in 0..snapshot.max_row().0 {
15787                if let Some(foldable_range) = self
15788                    .snapshot(window, cx)
15789                    .crease_for_buffer_row(MultiBufferRow(row))
15790                {
15791                    fold_ranges.push(foldable_range);
15792                }
15793            }
15794
15795            self.fold_creases(fold_ranges, true, window, cx);
15796        } else {
15797            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15798                editor
15799                    .update_in(cx, |editor, _, cx| {
15800                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15801                            editor.fold_buffer(buffer_id, cx);
15802                        }
15803                    })
15804                    .ok();
15805            });
15806        }
15807    }
15808
15809    pub fn fold_function_bodies(
15810        &mut self,
15811        _: &actions::FoldFunctionBodies,
15812        window: &mut Window,
15813        cx: &mut Context<Self>,
15814    ) {
15815        let snapshot = self.buffer.read(cx).snapshot(cx);
15816
15817        let ranges = snapshot
15818            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15819            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15820            .collect::<Vec<_>>();
15821
15822        let creases = ranges
15823            .into_iter()
15824            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15825            .collect();
15826
15827        self.fold_creases(creases, true, window, cx);
15828    }
15829
15830    pub fn fold_recursive(
15831        &mut self,
15832        _: &actions::FoldRecursive,
15833        window: &mut Window,
15834        cx: &mut Context<Self>,
15835    ) {
15836        let mut to_fold = Vec::new();
15837        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15838        let selections = self.selections.all_adjusted(cx);
15839
15840        for selection in selections {
15841            let range = selection.range().sorted();
15842            let buffer_start_row = range.start.row;
15843
15844            if range.start.row != range.end.row {
15845                let mut found = false;
15846                for row in range.start.row..=range.end.row {
15847                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15848                        found = true;
15849                        to_fold.push(crease);
15850                    }
15851                }
15852                if found {
15853                    continue;
15854                }
15855            }
15856
15857            for row in (0..=range.start.row).rev() {
15858                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15859                    if crease.range().end.row >= buffer_start_row {
15860                        to_fold.push(crease);
15861                    } else {
15862                        break;
15863                    }
15864                }
15865            }
15866        }
15867
15868        self.fold_creases(to_fold, true, window, cx);
15869    }
15870
15871    pub fn fold_at(
15872        &mut self,
15873        buffer_row: MultiBufferRow,
15874        window: &mut Window,
15875        cx: &mut Context<Self>,
15876    ) {
15877        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15878
15879        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15880            let autoscroll = self
15881                .selections
15882                .all::<Point>(cx)
15883                .iter()
15884                .any(|selection| crease.range().overlaps(&selection.range()));
15885
15886            self.fold_creases(vec![crease], autoscroll, window, cx);
15887        }
15888    }
15889
15890    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15891        if self.is_singleton(cx) {
15892            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15893            let buffer = &display_map.buffer_snapshot;
15894            let selections = self.selections.all::<Point>(cx);
15895            let ranges = selections
15896                .iter()
15897                .map(|s| {
15898                    let range = s.display_range(&display_map).sorted();
15899                    let mut start = range.start.to_point(&display_map);
15900                    let mut end = range.end.to_point(&display_map);
15901                    start.column = 0;
15902                    end.column = buffer.line_len(MultiBufferRow(end.row));
15903                    start..end
15904                })
15905                .collect::<Vec<_>>();
15906
15907            self.unfold_ranges(&ranges, true, true, cx);
15908        } else {
15909            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15910            let buffer_ids = self
15911                .selections
15912                .disjoint_anchor_ranges()
15913                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15914                .collect::<HashSet<_>>();
15915            for buffer_id in buffer_ids {
15916                self.unfold_buffer(buffer_id, cx);
15917            }
15918        }
15919    }
15920
15921    pub fn unfold_recursive(
15922        &mut self,
15923        _: &UnfoldRecursive,
15924        _window: &mut Window,
15925        cx: &mut Context<Self>,
15926    ) {
15927        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15928        let selections = self.selections.all::<Point>(cx);
15929        let ranges = selections
15930            .iter()
15931            .map(|s| {
15932                let mut range = s.display_range(&display_map).sorted();
15933                *range.start.column_mut() = 0;
15934                *range.end.column_mut() = display_map.line_len(range.end.row());
15935                let start = range.start.to_point(&display_map);
15936                let end = range.end.to_point(&display_map);
15937                start..end
15938            })
15939            .collect::<Vec<_>>();
15940
15941        self.unfold_ranges(&ranges, true, true, cx);
15942    }
15943
15944    pub fn unfold_at(
15945        &mut self,
15946        buffer_row: MultiBufferRow,
15947        _window: &mut Window,
15948        cx: &mut Context<Self>,
15949    ) {
15950        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15951
15952        let intersection_range = Point::new(buffer_row.0, 0)
15953            ..Point::new(
15954                buffer_row.0,
15955                display_map.buffer_snapshot.line_len(buffer_row),
15956            );
15957
15958        let autoscroll = self
15959            .selections
15960            .all::<Point>(cx)
15961            .iter()
15962            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15963
15964        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15965    }
15966
15967    pub fn unfold_all(
15968        &mut self,
15969        _: &actions::UnfoldAll,
15970        _window: &mut Window,
15971        cx: &mut Context<Self>,
15972    ) {
15973        if self.buffer.read(cx).is_singleton() {
15974            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15975            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15976        } else {
15977            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15978                editor
15979                    .update(cx, |editor, cx| {
15980                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15981                            editor.unfold_buffer(buffer_id, cx);
15982                        }
15983                    })
15984                    .ok();
15985            });
15986        }
15987    }
15988
15989    pub fn fold_selected_ranges(
15990        &mut self,
15991        _: &FoldSelectedRanges,
15992        window: &mut Window,
15993        cx: &mut Context<Self>,
15994    ) {
15995        let selections = self.selections.all_adjusted(cx);
15996        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15997        let ranges = selections
15998            .into_iter()
15999            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16000            .collect::<Vec<_>>();
16001        self.fold_creases(ranges, true, window, cx);
16002    }
16003
16004    pub fn fold_ranges<T: ToOffset + Clone>(
16005        &mut self,
16006        ranges: Vec<Range<T>>,
16007        auto_scroll: bool,
16008        window: &mut Window,
16009        cx: &mut Context<Self>,
16010    ) {
16011        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16012        let ranges = ranges
16013            .into_iter()
16014            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16015            .collect::<Vec<_>>();
16016        self.fold_creases(ranges, auto_scroll, window, cx);
16017    }
16018
16019    pub fn fold_creases<T: ToOffset + Clone>(
16020        &mut self,
16021        creases: Vec<Crease<T>>,
16022        auto_scroll: bool,
16023        _window: &mut Window,
16024        cx: &mut Context<Self>,
16025    ) {
16026        if creases.is_empty() {
16027            return;
16028        }
16029
16030        let mut buffers_affected = HashSet::default();
16031        let multi_buffer = self.buffer().read(cx);
16032        for crease in &creases {
16033            if let Some((_, buffer, _)) =
16034                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16035            {
16036                buffers_affected.insert(buffer.read(cx).remote_id());
16037            };
16038        }
16039
16040        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16041
16042        if auto_scroll {
16043            self.request_autoscroll(Autoscroll::fit(), cx);
16044        }
16045
16046        cx.notify();
16047
16048        self.scrollbar_marker_state.dirty = true;
16049        self.folds_did_change(cx);
16050    }
16051
16052    /// Removes any folds whose ranges intersect any of the given ranges.
16053    pub fn unfold_ranges<T: ToOffset + Clone>(
16054        &mut self,
16055        ranges: &[Range<T>],
16056        inclusive: bool,
16057        auto_scroll: bool,
16058        cx: &mut Context<Self>,
16059    ) {
16060        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16061            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16062        });
16063        self.folds_did_change(cx);
16064    }
16065
16066    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16067        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16068            return;
16069        }
16070        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16071        self.display_map.update(cx, |display_map, cx| {
16072            display_map.fold_buffers([buffer_id], cx)
16073        });
16074        cx.emit(EditorEvent::BufferFoldToggled {
16075            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16076            folded: true,
16077        });
16078        cx.notify();
16079    }
16080
16081    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16082        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16083            return;
16084        }
16085        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16086        self.display_map.update(cx, |display_map, cx| {
16087            display_map.unfold_buffers([buffer_id], cx);
16088        });
16089        cx.emit(EditorEvent::BufferFoldToggled {
16090            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16091            folded: false,
16092        });
16093        cx.notify();
16094    }
16095
16096    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16097        self.display_map.read(cx).is_buffer_folded(buffer)
16098    }
16099
16100    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16101        self.display_map.read(cx).folded_buffers()
16102    }
16103
16104    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16105        self.display_map.update(cx, |display_map, cx| {
16106            display_map.disable_header_for_buffer(buffer_id, cx);
16107        });
16108        cx.notify();
16109    }
16110
16111    /// Removes any folds with the given ranges.
16112    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16113        &mut self,
16114        ranges: &[Range<T>],
16115        type_id: TypeId,
16116        auto_scroll: bool,
16117        cx: &mut Context<Self>,
16118    ) {
16119        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16120            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16121        });
16122        self.folds_did_change(cx);
16123    }
16124
16125    fn remove_folds_with<T: ToOffset + Clone>(
16126        &mut self,
16127        ranges: &[Range<T>],
16128        auto_scroll: bool,
16129        cx: &mut Context<Self>,
16130        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16131    ) {
16132        if ranges.is_empty() {
16133            return;
16134        }
16135
16136        let mut buffers_affected = HashSet::default();
16137        let multi_buffer = self.buffer().read(cx);
16138        for range in ranges {
16139            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16140                buffers_affected.insert(buffer.read(cx).remote_id());
16141            };
16142        }
16143
16144        self.display_map.update(cx, update);
16145
16146        if auto_scroll {
16147            self.request_autoscroll(Autoscroll::fit(), cx);
16148        }
16149
16150        cx.notify();
16151        self.scrollbar_marker_state.dirty = true;
16152        self.active_indent_guides_state.dirty = true;
16153    }
16154
16155    pub fn update_fold_widths(
16156        &mut self,
16157        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16158        cx: &mut Context<Self>,
16159    ) -> bool {
16160        self.display_map
16161            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16162    }
16163
16164    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16165        self.display_map.read(cx).fold_placeholder.clone()
16166    }
16167
16168    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16169        self.buffer.update(cx, |buffer, cx| {
16170            buffer.set_all_diff_hunks_expanded(cx);
16171        });
16172    }
16173
16174    pub fn expand_all_diff_hunks(
16175        &mut self,
16176        _: &ExpandAllDiffHunks,
16177        _window: &mut Window,
16178        cx: &mut Context<Self>,
16179    ) {
16180        self.buffer.update(cx, |buffer, cx| {
16181            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16182        });
16183    }
16184
16185    pub fn toggle_selected_diff_hunks(
16186        &mut self,
16187        _: &ToggleSelectedDiffHunks,
16188        _window: &mut Window,
16189        cx: &mut Context<Self>,
16190    ) {
16191        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16192        self.toggle_diff_hunks_in_ranges(ranges, cx);
16193    }
16194
16195    pub fn diff_hunks_in_ranges<'a>(
16196        &'a self,
16197        ranges: &'a [Range<Anchor>],
16198        buffer: &'a MultiBufferSnapshot,
16199    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16200        ranges.iter().flat_map(move |range| {
16201            let end_excerpt_id = range.end.excerpt_id;
16202            let range = range.to_point(buffer);
16203            let mut peek_end = range.end;
16204            if range.end.row < buffer.max_row().0 {
16205                peek_end = Point::new(range.end.row + 1, 0);
16206            }
16207            buffer
16208                .diff_hunks_in_range(range.start..peek_end)
16209                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16210        })
16211    }
16212
16213    pub fn has_stageable_diff_hunks_in_ranges(
16214        &self,
16215        ranges: &[Range<Anchor>],
16216        snapshot: &MultiBufferSnapshot,
16217    ) -> bool {
16218        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16219        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16220    }
16221
16222    pub fn toggle_staged_selected_diff_hunks(
16223        &mut self,
16224        _: &::git::ToggleStaged,
16225        _: &mut Window,
16226        cx: &mut Context<Self>,
16227    ) {
16228        let snapshot = self.buffer.read(cx).snapshot(cx);
16229        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16230        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16231        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16232    }
16233
16234    pub fn set_render_diff_hunk_controls(
16235        &mut self,
16236        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16237        cx: &mut Context<Self>,
16238    ) {
16239        self.render_diff_hunk_controls = render_diff_hunk_controls;
16240        cx.notify();
16241    }
16242
16243    pub fn stage_and_next(
16244        &mut self,
16245        _: &::git::StageAndNext,
16246        window: &mut Window,
16247        cx: &mut Context<Self>,
16248    ) {
16249        self.do_stage_or_unstage_and_next(true, window, cx);
16250    }
16251
16252    pub fn unstage_and_next(
16253        &mut self,
16254        _: &::git::UnstageAndNext,
16255        window: &mut Window,
16256        cx: &mut Context<Self>,
16257    ) {
16258        self.do_stage_or_unstage_and_next(false, window, cx);
16259    }
16260
16261    pub fn stage_or_unstage_diff_hunks(
16262        &mut self,
16263        stage: bool,
16264        ranges: Vec<Range<Anchor>>,
16265        cx: &mut Context<Self>,
16266    ) {
16267        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16268        cx.spawn(async move |this, cx| {
16269            task.await?;
16270            this.update(cx, |this, cx| {
16271                let snapshot = this.buffer.read(cx).snapshot(cx);
16272                let chunk_by = this
16273                    .diff_hunks_in_ranges(&ranges, &snapshot)
16274                    .chunk_by(|hunk| hunk.buffer_id);
16275                for (buffer_id, hunks) in &chunk_by {
16276                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16277                }
16278            })
16279        })
16280        .detach_and_log_err(cx);
16281    }
16282
16283    fn save_buffers_for_ranges_if_needed(
16284        &mut self,
16285        ranges: &[Range<Anchor>],
16286        cx: &mut Context<Editor>,
16287    ) -> Task<Result<()>> {
16288        let multibuffer = self.buffer.read(cx);
16289        let snapshot = multibuffer.read(cx);
16290        let buffer_ids: HashSet<_> = ranges
16291            .iter()
16292            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16293            .collect();
16294        drop(snapshot);
16295
16296        let mut buffers = HashSet::default();
16297        for buffer_id in buffer_ids {
16298            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16299                let buffer = buffer_entity.read(cx);
16300                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16301                {
16302                    buffers.insert(buffer_entity);
16303                }
16304            }
16305        }
16306
16307        if let Some(project) = &self.project {
16308            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16309        } else {
16310            Task::ready(Ok(()))
16311        }
16312    }
16313
16314    fn do_stage_or_unstage_and_next(
16315        &mut self,
16316        stage: bool,
16317        window: &mut Window,
16318        cx: &mut Context<Self>,
16319    ) {
16320        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16321
16322        if ranges.iter().any(|range| range.start != range.end) {
16323            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16324            return;
16325        }
16326
16327        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16328        let snapshot = self.snapshot(window, cx);
16329        let position = self.selections.newest::<Point>(cx).head();
16330        let mut row = snapshot
16331            .buffer_snapshot
16332            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16333            .find(|hunk| hunk.row_range.start.0 > position.row)
16334            .map(|hunk| hunk.row_range.start);
16335
16336        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16337        // Outside of the project diff editor, wrap around to the beginning.
16338        if !all_diff_hunks_expanded {
16339            row = row.or_else(|| {
16340                snapshot
16341                    .buffer_snapshot
16342                    .diff_hunks_in_range(Point::zero()..position)
16343                    .find(|hunk| hunk.row_range.end.0 < position.row)
16344                    .map(|hunk| hunk.row_range.start)
16345            });
16346        }
16347
16348        if let Some(row) = row {
16349            let destination = Point::new(row.0, 0);
16350            let autoscroll = Autoscroll::center();
16351
16352            self.unfold_ranges(&[destination..destination], false, false, cx);
16353            self.change_selections(Some(autoscroll), window, cx, |s| {
16354                s.select_ranges([destination..destination]);
16355            });
16356        }
16357    }
16358
16359    fn do_stage_or_unstage(
16360        &self,
16361        stage: bool,
16362        buffer_id: BufferId,
16363        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16364        cx: &mut App,
16365    ) -> Option<()> {
16366        let project = self.project.as_ref()?;
16367        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16368        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16369        let buffer_snapshot = buffer.read(cx).snapshot();
16370        let file_exists = buffer_snapshot
16371            .file()
16372            .is_some_and(|file| file.disk_state().exists());
16373        diff.update(cx, |diff, cx| {
16374            diff.stage_or_unstage_hunks(
16375                stage,
16376                &hunks
16377                    .map(|hunk| buffer_diff::DiffHunk {
16378                        buffer_range: hunk.buffer_range,
16379                        diff_base_byte_range: hunk.diff_base_byte_range,
16380                        secondary_status: hunk.secondary_status,
16381                        range: Point::zero()..Point::zero(), // unused
16382                    })
16383                    .collect::<Vec<_>>(),
16384                &buffer_snapshot,
16385                file_exists,
16386                cx,
16387            )
16388        });
16389        None
16390    }
16391
16392    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16393        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16394        self.buffer
16395            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16396    }
16397
16398    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16399        self.buffer.update(cx, |buffer, cx| {
16400            let ranges = vec![Anchor::min()..Anchor::max()];
16401            if !buffer.all_diff_hunks_expanded()
16402                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16403            {
16404                buffer.collapse_diff_hunks(ranges, cx);
16405                true
16406            } else {
16407                false
16408            }
16409        })
16410    }
16411
16412    fn toggle_diff_hunks_in_ranges(
16413        &mut self,
16414        ranges: Vec<Range<Anchor>>,
16415        cx: &mut Context<Editor>,
16416    ) {
16417        self.buffer.update(cx, |buffer, cx| {
16418            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16419            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16420        })
16421    }
16422
16423    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16424        self.buffer.update(cx, |buffer, cx| {
16425            let snapshot = buffer.snapshot(cx);
16426            let excerpt_id = range.end.excerpt_id;
16427            let point_range = range.to_point(&snapshot);
16428            let expand = !buffer.single_hunk_is_expanded(range, cx);
16429            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16430        })
16431    }
16432
16433    pub(crate) fn apply_all_diff_hunks(
16434        &mut self,
16435        _: &ApplyAllDiffHunks,
16436        window: &mut Window,
16437        cx: &mut Context<Self>,
16438    ) {
16439        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16440
16441        let buffers = self.buffer.read(cx).all_buffers();
16442        for branch_buffer in buffers {
16443            branch_buffer.update(cx, |branch_buffer, cx| {
16444                branch_buffer.merge_into_base(Vec::new(), cx);
16445            });
16446        }
16447
16448        if let Some(project) = self.project.clone() {
16449            self.save(true, project, window, cx).detach_and_log_err(cx);
16450        }
16451    }
16452
16453    pub(crate) fn apply_selected_diff_hunks(
16454        &mut self,
16455        _: &ApplyDiffHunk,
16456        window: &mut Window,
16457        cx: &mut Context<Self>,
16458    ) {
16459        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16460        let snapshot = self.snapshot(window, cx);
16461        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16462        let mut ranges_by_buffer = HashMap::default();
16463        self.transact(window, cx, |editor, _window, cx| {
16464            for hunk in hunks {
16465                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16466                    ranges_by_buffer
16467                        .entry(buffer.clone())
16468                        .or_insert_with(Vec::new)
16469                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16470                }
16471            }
16472
16473            for (buffer, ranges) in ranges_by_buffer {
16474                buffer.update(cx, |buffer, cx| {
16475                    buffer.merge_into_base(ranges, cx);
16476                });
16477            }
16478        });
16479
16480        if let Some(project) = self.project.clone() {
16481            self.save(true, project, window, cx).detach_and_log_err(cx);
16482        }
16483    }
16484
16485    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16486        if hovered != self.gutter_hovered {
16487            self.gutter_hovered = hovered;
16488            cx.notify();
16489        }
16490    }
16491
16492    pub fn insert_blocks(
16493        &mut self,
16494        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16495        autoscroll: Option<Autoscroll>,
16496        cx: &mut Context<Self>,
16497    ) -> Vec<CustomBlockId> {
16498        let blocks = self
16499            .display_map
16500            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16501        if let Some(autoscroll) = autoscroll {
16502            self.request_autoscroll(autoscroll, cx);
16503        }
16504        cx.notify();
16505        blocks
16506    }
16507
16508    pub fn resize_blocks(
16509        &mut self,
16510        heights: HashMap<CustomBlockId, u32>,
16511        autoscroll: Option<Autoscroll>,
16512        cx: &mut Context<Self>,
16513    ) {
16514        self.display_map
16515            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16516        if let Some(autoscroll) = autoscroll {
16517            self.request_autoscroll(autoscroll, cx);
16518        }
16519        cx.notify();
16520    }
16521
16522    pub fn replace_blocks(
16523        &mut self,
16524        renderers: HashMap<CustomBlockId, RenderBlock>,
16525        autoscroll: Option<Autoscroll>,
16526        cx: &mut Context<Self>,
16527    ) {
16528        self.display_map
16529            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16530        if let Some(autoscroll) = autoscroll {
16531            self.request_autoscroll(autoscroll, cx);
16532        }
16533        cx.notify();
16534    }
16535
16536    pub fn remove_blocks(
16537        &mut self,
16538        block_ids: HashSet<CustomBlockId>,
16539        autoscroll: Option<Autoscroll>,
16540        cx: &mut Context<Self>,
16541    ) {
16542        self.display_map.update(cx, |display_map, cx| {
16543            display_map.remove_blocks(block_ids, cx)
16544        });
16545        if let Some(autoscroll) = autoscroll {
16546            self.request_autoscroll(autoscroll, cx);
16547        }
16548        cx.notify();
16549    }
16550
16551    pub fn row_for_block(
16552        &self,
16553        block_id: CustomBlockId,
16554        cx: &mut Context<Self>,
16555    ) -> Option<DisplayRow> {
16556        self.display_map
16557            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16558    }
16559
16560    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16561        self.focused_block = Some(focused_block);
16562    }
16563
16564    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16565        self.focused_block.take()
16566    }
16567
16568    pub fn insert_creases(
16569        &mut self,
16570        creases: impl IntoIterator<Item = Crease<Anchor>>,
16571        cx: &mut Context<Self>,
16572    ) -> Vec<CreaseId> {
16573        self.display_map
16574            .update(cx, |map, cx| map.insert_creases(creases, cx))
16575    }
16576
16577    pub fn remove_creases(
16578        &mut self,
16579        ids: impl IntoIterator<Item = CreaseId>,
16580        cx: &mut Context<Self>,
16581    ) -> Vec<(CreaseId, Range<Anchor>)> {
16582        self.display_map
16583            .update(cx, |map, cx| map.remove_creases(ids, cx))
16584    }
16585
16586    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16587        self.display_map
16588            .update(cx, |map, cx| map.snapshot(cx))
16589            .longest_row()
16590    }
16591
16592    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16593        self.display_map
16594            .update(cx, |map, cx| map.snapshot(cx))
16595            .max_point()
16596    }
16597
16598    pub fn text(&self, cx: &App) -> String {
16599        self.buffer.read(cx).read(cx).text()
16600    }
16601
16602    pub fn is_empty(&self, cx: &App) -> bool {
16603        self.buffer.read(cx).read(cx).is_empty()
16604    }
16605
16606    pub fn text_option(&self, cx: &App) -> Option<String> {
16607        let text = self.text(cx);
16608        let text = text.trim();
16609
16610        if text.is_empty() {
16611            return None;
16612        }
16613
16614        Some(text.to_string())
16615    }
16616
16617    pub fn set_text(
16618        &mut self,
16619        text: impl Into<Arc<str>>,
16620        window: &mut Window,
16621        cx: &mut Context<Self>,
16622    ) {
16623        self.transact(window, cx, |this, _, cx| {
16624            this.buffer
16625                .read(cx)
16626                .as_singleton()
16627                .expect("you can only call set_text on editors for singleton buffers")
16628                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16629        });
16630    }
16631
16632    pub fn display_text(&self, cx: &mut App) -> String {
16633        self.display_map
16634            .update(cx, |map, cx| map.snapshot(cx))
16635            .text()
16636    }
16637
16638    fn create_minimap(
16639        &self,
16640        minimap_settings: MinimapSettings,
16641        window: &mut Window,
16642        cx: &mut Context<Self>,
16643    ) -> Option<Entity<Self>> {
16644        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16645            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16646    }
16647
16648    fn initialize_new_minimap(
16649        &self,
16650        minimap_settings: MinimapSettings,
16651        window: &mut Window,
16652        cx: &mut Context<Self>,
16653    ) -> Entity<Self> {
16654        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16655
16656        let mut minimap = Editor::new_internal(
16657            EditorMode::Minimap {
16658                parent: cx.weak_entity(),
16659            },
16660            self.buffer.clone(),
16661            self.project.clone(),
16662            Some(self.display_map.clone()),
16663            window,
16664            cx,
16665        );
16666        minimap.scroll_manager.clone_state(&self.scroll_manager);
16667        minimap.set_text_style_refinement(TextStyleRefinement {
16668            font_size: Some(MINIMAP_FONT_SIZE),
16669            font_weight: Some(MINIMAP_FONT_WEIGHT),
16670            ..Default::default()
16671        });
16672        minimap.update_minimap_configuration(minimap_settings, cx);
16673        cx.new(|_| minimap)
16674    }
16675
16676    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16677        let current_line_highlight = minimap_settings
16678            .current_line_highlight
16679            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16680        self.set_current_line_highlight(Some(current_line_highlight));
16681    }
16682
16683    pub fn minimap(&self) -> Option<&Entity<Self>> {
16684        self.minimap
16685            .as_ref()
16686            .filter(|_| self.minimap_visibility.visible())
16687    }
16688
16689    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16690        let mut wrap_guides = smallvec::smallvec![];
16691
16692        if self.show_wrap_guides == Some(false) {
16693            return wrap_guides;
16694        }
16695
16696        let settings = self.buffer.read(cx).language_settings(cx);
16697        if settings.show_wrap_guides {
16698            match self.soft_wrap_mode(cx) {
16699                SoftWrap::Column(soft_wrap) => {
16700                    wrap_guides.push((soft_wrap as usize, true));
16701                }
16702                SoftWrap::Bounded(soft_wrap) => {
16703                    wrap_guides.push((soft_wrap as usize, true));
16704                }
16705                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16706            }
16707            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16708        }
16709
16710        wrap_guides
16711    }
16712
16713    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16714        let settings = self.buffer.read(cx).language_settings(cx);
16715        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16716        match mode {
16717            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16718                SoftWrap::None
16719            }
16720            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16721            language_settings::SoftWrap::PreferredLineLength => {
16722                SoftWrap::Column(settings.preferred_line_length)
16723            }
16724            language_settings::SoftWrap::Bounded => {
16725                SoftWrap::Bounded(settings.preferred_line_length)
16726            }
16727        }
16728    }
16729
16730    pub fn set_soft_wrap_mode(
16731        &mut self,
16732        mode: language_settings::SoftWrap,
16733
16734        cx: &mut Context<Self>,
16735    ) {
16736        self.soft_wrap_mode_override = Some(mode);
16737        cx.notify();
16738    }
16739
16740    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16741        self.hard_wrap = hard_wrap;
16742        cx.notify();
16743    }
16744
16745    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16746        self.text_style_refinement = Some(style);
16747    }
16748
16749    /// called by the Element so we know what style we were most recently rendered with.
16750    pub(crate) fn set_style(
16751        &mut self,
16752        style: EditorStyle,
16753        window: &mut Window,
16754        cx: &mut Context<Self>,
16755    ) {
16756        // We intentionally do not inform the display map about the minimap style
16757        // so that wrapping is not recalculated and stays consistent for the editor
16758        // and its linked minimap.
16759        if !self.mode.is_minimap() {
16760            let rem_size = window.rem_size();
16761            self.display_map.update(cx, |map, cx| {
16762                map.set_font(
16763                    style.text.font(),
16764                    style.text.font_size.to_pixels(rem_size),
16765                    cx,
16766                )
16767            });
16768        }
16769        self.style = Some(style);
16770    }
16771
16772    pub fn style(&self) -> Option<&EditorStyle> {
16773        self.style.as_ref()
16774    }
16775
16776    // Called by the element. This method is not designed to be called outside of the editor
16777    // element's layout code because it does not notify when rewrapping is computed synchronously.
16778    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16779        self.display_map
16780            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16781    }
16782
16783    pub fn set_soft_wrap(&mut self) {
16784        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16785    }
16786
16787    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16788        if self.soft_wrap_mode_override.is_some() {
16789            self.soft_wrap_mode_override.take();
16790        } else {
16791            let soft_wrap = match self.soft_wrap_mode(cx) {
16792                SoftWrap::GitDiff => return,
16793                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16794                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16795                    language_settings::SoftWrap::None
16796                }
16797            };
16798            self.soft_wrap_mode_override = Some(soft_wrap);
16799        }
16800        cx.notify();
16801    }
16802
16803    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16804        let Some(workspace) = self.workspace() else {
16805            return;
16806        };
16807        let fs = workspace.read(cx).app_state().fs.clone();
16808        let current_show = TabBarSettings::get_global(cx).show;
16809        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16810            setting.show = Some(!current_show);
16811        });
16812    }
16813
16814    pub fn toggle_indent_guides(
16815        &mut self,
16816        _: &ToggleIndentGuides,
16817        _: &mut Window,
16818        cx: &mut Context<Self>,
16819    ) {
16820        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16821            self.buffer
16822                .read(cx)
16823                .language_settings(cx)
16824                .indent_guides
16825                .enabled
16826        });
16827        self.show_indent_guides = Some(!currently_enabled);
16828        cx.notify();
16829    }
16830
16831    fn should_show_indent_guides(&self) -> Option<bool> {
16832        self.show_indent_guides
16833    }
16834
16835    pub fn toggle_line_numbers(
16836        &mut self,
16837        _: &ToggleLineNumbers,
16838        _: &mut Window,
16839        cx: &mut Context<Self>,
16840    ) {
16841        let mut editor_settings = EditorSettings::get_global(cx).clone();
16842        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16843        EditorSettings::override_global(editor_settings, cx);
16844    }
16845
16846    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16847        if let Some(show_line_numbers) = self.show_line_numbers {
16848            return show_line_numbers;
16849        }
16850        EditorSettings::get_global(cx).gutter.line_numbers
16851    }
16852
16853    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16854        self.use_relative_line_numbers
16855            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16856    }
16857
16858    pub fn toggle_relative_line_numbers(
16859        &mut self,
16860        _: &ToggleRelativeLineNumbers,
16861        _: &mut Window,
16862        cx: &mut Context<Self>,
16863    ) {
16864        let is_relative = self.should_use_relative_line_numbers(cx);
16865        self.set_relative_line_number(Some(!is_relative), cx)
16866    }
16867
16868    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16869        self.use_relative_line_numbers = is_relative;
16870        cx.notify();
16871    }
16872
16873    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16874        self.show_gutter = show_gutter;
16875        cx.notify();
16876    }
16877
16878    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16879        self.show_scrollbars = show_scrollbars;
16880        cx.notify();
16881    }
16882
16883    pub fn set_minimap_visibility(
16884        &mut self,
16885        minimap_visibility: MinimapVisibility,
16886        window: &mut Window,
16887        cx: &mut Context<Self>,
16888    ) {
16889        if self.minimap_visibility != minimap_visibility {
16890            if minimap_visibility.visible() && self.minimap.is_none() {
16891                let minimap_settings = EditorSettings::get_global(cx).minimap;
16892                self.minimap =
16893                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16894            }
16895            self.minimap_visibility = minimap_visibility;
16896            cx.notify();
16897        }
16898    }
16899
16900    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16901        self.set_show_scrollbars(false, cx);
16902        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16903    }
16904
16905    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16906        self.show_line_numbers = Some(show_line_numbers);
16907        cx.notify();
16908    }
16909
16910    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16911        self.disable_expand_excerpt_buttons = true;
16912        cx.notify();
16913    }
16914
16915    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16916        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16917        cx.notify();
16918    }
16919
16920    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16921        self.show_code_actions = Some(show_code_actions);
16922        cx.notify();
16923    }
16924
16925    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16926        self.show_runnables = Some(show_runnables);
16927        cx.notify();
16928    }
16929
16930    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16931        self.show_breakpoints = Some(show_breakpoints);
16932        cx.notify();
16933    }
16934
16935    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16936        if self.display_map.read(cx).masked != masked {
16937            self.display_map.update(cx, |map, _| map.masked = masked);
16938        }
16939        cx.notify()
16940    }
16941
16942    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16943        self.show_wrap_guides = Some(show_wrap_guides);
16944        cx.notify();
16945    }
16946
16947    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16948        self.show_indent_guides = Some(show_indent_guides);
16949        cx.notify();
16950    }
16951
16952    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16953        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16954            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16955                if let Some(dir) = file.abs_path(cx).parent() {
16956                    return Some(dir.to_owned());
16957                }
16958            }
16959
16960            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16961                return Some(project_path.path.to_path_buf());
16962            }
16963        }
16964
16965        None
16966    }
16967
16968    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16969        self.active_excerpt(cx)?
16970            .1
16971            .read(cx)
16972            .file()
16973            .and_then(|f| f.as_local())
16974    }
16975
16976    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16977        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16978            let buffer = buffer.read(cx);
16979            if let Some(project_path) = buffer.project_path(cx) {
16980                let project = self.project.as_ref()?.read(cx);
16981                project.absolute_path(&project_path, cx)
16982            } else {
16983                buffer
16984                    .file()
16985                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16986            }
16987        })
16988    }
16989
16990    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16991        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16992            let project_path = buffer.read(cx).project_path(cx)?;
16993            let project = self.project.as_ref()?.read(cx);
16994            let entry = project.entry_for_path(&project_path, cx)?;
16995            let path = entry.path.to_path_buf();
16996            Some(path)
16997        })
16998    }
16999
17000    pub fn reveal_in_finder(
17001        &mut self,
17002        _: &RevealInFileManager,
17003        _window: &mut Window,
17004        cx: &mut Context<Self>,
17005    ) {
17006        if let Some(target) = self.target_file(cx) {
17007            cx.reveal_path(&target.abs_path(cx));
17008        }
17009    }
17010
17011    pub fn copy_path(
17012        &mut self,
17013        _: &zed_actions::workspace::CopyPath,
17014        _window: &mut Window,
17015        cx: &mut Context<Self>,
17016    ) {
17017        if let Some(path) = self.target_file_abs_path(cx) {
17018            if let Some(path) = path.to_str() {
17019                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17020            }
17021        }
17022    }
17023
17024    pub fn copy_relative_path(
17025        &mut self,
17026        _: &zed_actions::workspace::CopyRelativePath,
17027        _window: &mut Window,
17028        cx: &mut Context<Self>,
17029    ) {
17030        if let Some(path) = self.target_file_path(cx) {
17031            if let Some(path) = path.to_str() {
17032                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17033            }
17034        }
17035    }
17036
17037    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17038        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17039            buffer.read(cx).project_path(cx)
17040        } else {
17041            None
17042        }
17043    }
17044
17045    // Returns true if the editor handled a go-to-line request
17046    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17047        maybe!({
17048            let breakpoint_store = self.breakpoint_store.as_ref()?;
17049
17050            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17051            else {
17052                self.clear_row_highlights::<ActiveDebugLine>();
17053                return None;
17054            };
17055
17056            let position = active_stack_frame.position;
17057            let buffer_id = position.buffer_id?;
17058            let snapshot = self
17059                .project
17060                .as_ref()?
17061                .read(cx)
17062                .buffer_for_id(buffer_id, cx)?
17063                .read(cx)
17064                .snapshot();
17065
17066            let mut handled = false;
17067            for (id, ExcerptRange { context, .. }) in
17068                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17069            {
17070                if context.start.cmp(&position, &snapshot).is_ge()
17071                    || context.end.cmp(&position, &snapshot).is_lt()
17072                {
17073                    continue;
17074                }
17075                let snapshot = self.buffer.read(cx).snapshot(cx);
17076                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17077
17078                handled = true;
17079                self.clear_row_highlights::<ActiveDebugLine>();
17080
17081                self.go_to_line::<ActiveDebugLine>(
17082                    multibuffer_anchor,
17083                    Some(cx.theme().colors().editor_debugger_active_line_background),
17084                    window,
17085                    cx,
17086                );
17087
17088                cx.notify();
17089            }
17090
17091            handled.then_some(())
17092        })
17093        .is_some()
17094    }
17095
17096    pub fn copy_file_name_without_extension(
17097        &mut self,
17098        _: &CopyFileNameWithoutExtension,
17099        _: &mut Window,
17100        cx: &mut Context<Self>,
17101    ) {
17102        if let Some(file) = self.target_file(cx) {
17103            if let Some(file_stem) = file.path().file_stem() {
17104                if let Some(name) = file_stem.to_str() {
17105                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17106                }
17107            }
17108        }
17109    }
17110
17111    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17112        if let Some(file) = self.target_file(cx) {
17113            if let Some(file_name) = file.path().file_name() {
17114                if let Some(name) = file_name.to_str() {
17115                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17116                }
17117            }
17118        }
17119    }
17120
17121    pub fn toggle_git_blame(
17122        &mut self,
17123        _: &::git::Blame,
17124        window: &mut Window,
17125        cx: &mut Context<Self>,
17126    ) {
17127        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17128
17129        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17130            self.start_git_blame(true, window, cx);
17131        }
17132
17133        cx.notify();
17134    }
17135
17136    pub fn toggle_git_blame_inline(
17137        &mut self,
17138        _: &ToggleGitBlameInline,
17139        window: &mut Window,
17140        cx: &mut Context<Self>,
17141    ) {
17142        self.toggle_git_blame_inline_internal(true, window, cx);
17143        cx.notify();
17144    }
17145
17146    pub fn open_git_blame_commit(
17147        &mut self,
17148        _: &OpenGitBlameCommit,
17149        window: &mut Window,
17150        cx: &mut Context<Self>,
17151    ) {
17152        self.open_git_blame_commit_internal(window, cx);
17153    }
17154
17155    fn open_git_blame_commit_internal(
17156        &mut self,
17157        window: &mut Window,
17158        cx: &mut Context<Self>,
17159    ) -> Option<()> {
17160        let blame = self.blame.as_ref()?;
17161        let snapshot = self.snapshot(window, cx);
17162        let cursor = self.selections.newest::<Point>(cx).head();
17163        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17164        let blame_entry = blame
17165            .update(cx, |blame, cx| {
17166                blame
17167                    .blame_for_rows(
17168                        &[RowInfo {
17169                            buffer_id: Some(buffer.remote_id()),
17170                            buffer_row: Some(point.row),
17171                            ..Default::default()
17172                        }],
17173                        cx,
17174                    )
17175                    .next()
17176            })
17177            .flatten()?;
17178        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17179        let repo = blame.read(cx).repository(cx)?;
17180        let workspace = self.workspace()?.downgrade();
17181        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17182        None
17183    }
17184
17185    pub fn git_blame_inline_enabled(&self) -> bool {
17186        self.git_blame_inline_enabled
17187    }
17188
17189    pub fn toggle_selection_menu(
17190        &mut self,
17191        _: &ToggleSelectionMenu,
17192        _: &mut Window,
17193        cx: &mut Context<Self>,
17194    ) {
17195        self.show_selection_menu = self
17196            .show_selection_menu
17197            .map(|show_selections_menu| !show_selections_menu)
17198            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17199
17200        cx.notify();
17201    }
17202
17203    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17204        self.show_selection_menu
17205            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17206    }
17207
17208    fn start_git_blame(
17209        &mut self,
17210        user_triggered: bool,
17211        window: &mut Window,
17212        cx: &mut Context<Self>,
17213    ) {
17214        if let Some(project) = self.project.as_ref() {
17215            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17216                return;
17217            };
17218
17219            if buffer.read(cx).file().is_none() {
17220                return;
17221            }
17222
17223            let focused = self.focus_handle(cx).contains_focused(window, cx);
17224
17225            let project = project.clone();
17226            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17227            self.blame_subscription =
17228                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17229            self.blame = Some(blame);
17230        }
17231    }
17232
17233    fn toggle_git_blame_inline_internal(
17234        &mut self,
17235        user_triggered: bool,
17236        window: &mut Window,
17237        cx: &mut Context<Self>,
17238    ) {
17239        if self.git_blame_inline_enabled {
17240            self.git_blame_inline_enabled = false;
17241            self.show_git_blame_inline = false;
17242            self.show_git_blame_inline_delay_task.take();
17243        } else {
17244            self.git_blame_inline_enabled = true;
17245            self.start_git_blame_inline(user_triggered, window, cx);
17246        }
17247
17248        cx.notify();
17249    }
17250
17251    fn start_git_blame_inline(
17252        &mut self,
17253        user_triggered: bool,
17254        window: &mut Window,
17255        cx: &mut Context<Self>,
17256    ) {
17257        self.start_git_blame(user_triggered, window, cx);
17258
17259        if ProjectSettings::get_global(cx)
17260            .git
17261            .inline_blame_delay()
17262            .is_some()
17263        {
17264            self.start_inline_blame_timer(window, cx);
17265        } else {
17266            self.show_git_blame_inline = true
17267        }
17268    }
17269
17270    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17271        self.blame.as_ref()
17272    }
17273
17274    pub fn show_git_blame_gutter(&self) -> bool {
17275        self.show_git_blame_gutter
17276    }
17277
17278    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17279        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17280    }
17281
17282    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17283        self.show_git_blame_inline
17284            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17285            && !self.newest_selection_head_on_empty_line(cx)
17286            && self.has_blame_entries(cx)
17287    }
17288
17289    fn has_blame_entries(&self, cx: &App) -> bool {
17290        self.blame()
17291            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17292    }
17293
17294    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17295        let cursor_anchor = self.selections.newest_anchor().head();
17296
17297        let snapshot = self.buffer.read(cx).snapshot(cx);
17298        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17299
17300        snapshot.line_len(buffer_row) == 0
17301    }
17302
17303    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17304        let buffer_and_selection = maybe!({
17305            let selection = self.selections.newest::<Point>(cx);
17306            let selection_range = selection.range();
17307
17308            let multi_buffer = self.buffer().read(cx);
17309            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17310            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17311
17312            let (buffer, range, _) = if selection.reversed {
17313                buffer_ranges.first()
17314            } else {
17315                buffer_ranges.last()
17316            }?;
17317
17318            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17319                ..text::ToPoint::to_point(&range.end, &buffer).row;
17320            Some((
17321                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17322                selection,
17323            ))
17324        });
17325
17326        let Some((buffer, selection)) = buffer_and_selection else {
17327            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17328        };
17329
17330        let Some(project) = self.project.as_ref() else {
17331            return Task::ready(Err(anyhow!("editor does not have project")));
17332        };
17333
17334        project.update(cx, |project, cx| {
17335            project.get_permalink_to_line(&buffer, selection, cx)
17336        })
17337    }
17338
17339    pub fn copy_permalink_to_line(
17340        &mut self,
17341        _: &CopyPermalinkToLine,
17342        window: &mut Window,
17343        cx: &mut Context<Self>,
17344    ) {
17345        let permalink_task = self.get_permalink_to_line(cx);
17346        let workspace = self.workspace();
17347
17348        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17349            Ok(permalink) => {
17350                cx.update(|_, cx| {
17351                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17352                })
17353                .ok();
17354            }
17355            Err(err) => {
17356                let message = format!("Failed to copy permalink: {err}");
17357
17358                anyhow::Result::<()>::Err(err).log_err();
17359
17360                if let Some(workspace) = workspace {
17361                    workspace
17362                        .update_in(cx, |workspace, _, cx| {
17363                            struct CopyPermalinkToLine;
17364
17365                            workspace.show_toast(
17366                                Toast::new(
17367                                    NotificationId::unique::<CopyPermalinkToLine>(),
17368                                    message,
17369                                ),
17370                                cx,
17371                            )
17372                        })
17373                        .ok();
17374                }
17375            }
17376        })
17377        .detach();
17378    }
17379
17380    pub fn copy_file_location(
17381        &mut self,
17382        _: &CopyFileLocation,
17383        _: &mut Window,
17384        cx: &mut Context<Self>,
17385    ) {
17386        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17387        if let Some(file) = self.target_file(cx) {
17388            if let Some(path) = file.path().to_str() {
17389                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17390            }
17391        }
17392    }
17393
17394    pub fn open_permalink_to_line(
17395        &mut self,
17396        _: &OpenPermalinkToLine,
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.open_url(permalink.as_ref());
17407                })
17408                .ok();
17409            }
17410            Err(err) => {
17411                let message = format!("Failed to open permalink: {err}");
17412
17413                anyhow::Result::<()>::Err(err).log_err();
17414
17415                if let Some(workspace) = workspace {
17416                    workspace
17417                        .update(cx, |workspace, cx| {
17418                            struct OpenPermalinkToLine;
17419
17420                            workspace.show_toast(
17421                                Toast::new(
17422                                    NotificationId::unique::<OpenPermalinkToLine>(),
17423                                    message,
17424                                ),
17425                                cx,
17426                            )
17427                        })
17428                        .ok();
17429                }
17430            }
17431        })
17432        .detach();
17433    }
17434
17435    pub fn insert_uuid_v4(
17436        &mut self,
17437        _: &InsertUuidV4,
17438        window: &mut Window,
17439        cx: &mut Context<Self>,
17440    ) {
17441        self.insert_uuid(UuidVersion::V4, window, cx);
17442    }
17443
17444    pub fn insert_uuid_v7(
17445        &mut self,
17446        _: &InsertUuidV7,
17447        window: &mut Window,
17448        cx: &mut Context<Self>,
17449    ) {
17450        self.insert_uuid(UuidVersion::V7, window, cx);
17451    }
17452
17453    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17454        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17455        self.transact(window, cx, |this, window, cx| {
17456            let edits = this
17457                .selections
17458                .all::<Point>(cx)
17459                .into_iter()
17460                .map(|selection| {
17461                    let uuid = match version {
17462                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17463                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17464                    };
17465
17466                    (selection.range(), uuid.to_string())
17467                });
17468            this.edit(edits, cx);
17469            this.refresh_inline_completion(true, false, window, cx);
17470        });
17471    }
17472
17473    pub fn open_selections_in_multibuffer(
17474        &mut self,
17475        _: &OpenSelectionsInMultibuffer,
17476        window: &mut Window,
17477        cx: &mut Context<Self>,
17478    ) {
17479        let multibuffer = self.buffer.read(cx);
17480
17481        let Some(buffer) = multibuffer.as_singleton() else {
17482            return;
17483        };
17484
17485        let Some(workspace) = self.workspace() else {
17486            return;
17487        };
17488
17489        let locations = self
17490            .selections
17491            .disjoint_anchors()
17492            .iter()
17493            .map(|range| Location {
17494                buffer: buffer.clone(),
17495                range: range.start.text_anchor..range.end.text_anchor,
17496            })
17497            .collect::<Vec<_>>();
17498
17499        let title = multibuffer.title(cx).to_string();
17500
17501        cx.spawn_in(window, async move |_, cx| {
17502            workspace.update_in(cx, |workspace, window, cx| {
17503                Self::open_locations_in_multibuffer(
17504                    workspace,
17505                    locations,
17506                    format!("Selections for '{title}'"),
17507                    false,
17508                    MultibufferSelectionMode::All,
17509                    window,
17510                    cx,
17511                );
17512            })
17513        })
17514        .detach();
17515    }
17516
17517    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17518    /// last highlight added will be used.
17519    ///
17520    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17521    pub fn highlight_rows<T: 'static>(
17522        &mut self,
17523        range: Range<Anchor>,
17524        color: Hsla,
17525        options: RowHighlightOptions,
17526        cx: &mut Context<Self>,
17527    ) {
17528        let snapshot = self.buffer().read(cx).snapshot(cx);
17529        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17530        let ix = row_highlights.binary_search_by(|highlight| {
17531            Ordering::Equal
17532                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17533                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17534        });
17535
17536        if let Err(mut ix) = ix {
17537            let index = post_inc(&mut self.highlight_order);
17538
17539            // If this range intersects with the preceding highlight, then merge it with
17540            // the preceding highlight. Otherwise insert a new highlight.
17541            let mut merged = false;
17542            if ix > 0 {
17543                let prev_highlight = &mut row_highlights[ix - 1];
17544                if prev_highlight
17545                    .range
17546                    .end
17547                    .cmp(&range.start, &snapshot)
17548                    .is_ge()
17549                {
17550                    ix -= 1;
17551                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17552                        prev_highlight.range.end = range.end;
17553                    }
17554                    merged = true;
17555                    prev_highlight.index = index;
17556                    prev_highlight.color = color;
17557                    prev_highlight.options = options;
17558                }
17559            }
17560
17561            if !merged {
17562                row_highlights.insert(
17563                    ix,
17564                    RowHighlight {
17565                        range: range.clone(),
17566                        index,
17567                        color,
17568                        options,
17569                        type_id: TypeId::of::<T>(),
17570                    },
17571                );
17572            }
17573
17574            // If any of the following highlights intersect with this one, merge them.
17575            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17576                let highlight = &row_highlights[ix];
17577                if next_highlight
17578                    .range
17579                    .start
17580                    .cmp(&highlight.range.end, &snapshot)
17581                    .is_le()
17582                {
17583                    if next_highlight
17584                        .range
17585                        .end
17586                        .cmp(&highlight.range.end, &snapshot)
17587                        .is_gt()
17588                    {
17589                        row_highlights[ix].range.end = next_highlight.range.end;
17590                    }
17591                    row_highlights.remove(ix + 1);
17592                } else {
17593                    break;
17594                }
17595            }
17596        }
17597    }
17598
17599    /// Remove any highlighted row ranges of the given type that intersect the
17600    /// given ranges.
17601    pub fn remove_highlighted_rows<T: 'static>(
17602        &mut self,
17603        ranges_to_remove: Vec<Range<Anchor>>,
17604        cx: &mut Context<Self>,
17605    ) {
17606        let snapshot = self.buffer().read(cx).snapshot(cx);
17607        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17608        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17609        row_highlights.retain(|highlight| {
17610            while let Some(range_to_remove) = ranges_to_remove.peek() {
17611                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17612                    Ordering::Less | Ordering::Equal => {
17613                        ranges_to_remove.next();
17614                    }
17615                    Ordering::Greater => {
17616                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17617                            Ordering::Less | Ordering::Equal => {
17618                                return false;
17619                            }
17620                            Ordering::Greater => break,
17621                        }
17622                    }
17623                }
17624            }
17625
17626            true
17627        })
17628    }
17629
17630    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17631    pub fn clear_row_highlights<T: 'static>(&mut self) {
17632        self.highlighted_rows.remove(&TypeId::of::<T>());
17633    }
17634
17635    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17636    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17637        self.highlighted_rows
17638            .get(&TypeId::of::<T>())
17639            .map_or(&[] as &[_], |vec| vec.as_slice())
17640            .iter()
17641            .map(|highlight| (highlight.range.clone(), highlight.color))
17642    }
17643
17644    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17645    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17646    /// Allows to ignore certain kinds of highlights.
17647    pub fn highlighted_display_rows(
17648        &self,
17649        window: &mut Window,
17650        cx: &mut App,
17651    ) -> BTreeMap<DisplayRow, LineHighlight> {
17652        let snapshot = self.snapshot(window, cx);
17653        let mut used_highlight_orders = HashMap::default();
17654        self.highlighted_rows
17655            .iter()
17656            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17657            .fold(
17658                BTreeMap::<DisplayRow, LineHighlight>::new(),
17659                |mut unique_rows, highlight| {
17660                    let start = highlight.range.start.to_display_point(&snapshot);
17661                    let end = highlight.range.end.to_display_point(&snapshot);
17662                    let start_row = start.row().0;
17663                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17664                        && end.column() == 0
17665                    {
17666                        end.row().0.saturating_sub(1)
17667                    } else {
17668                        end.row().0
17669                    };
17670                    for row in start_row..=end_row {
17671                        let used_index =
17672                            used_highlight_orders.entry(row).or_insert(highlight.index);
17673                        if highlight.index >= *used_index {
17674                            *used_index = highlight.index;
17675                            unique_rows.insert(
17676                                DisplayRow(row),
17677                                LineHighlight {
17678                                    include_gutter: highlight.options.include_gutter,
17679                                    border: None,
17680                                    background: highlight.color.into(),
17681                                    type_id: Some(highlight.type_id),
17682                                },
17683                            );
17684                        }
17685                    }
17686                    unique_rows
17687                },
17688            )
17689    }
17690
17691    pub fn highlighted_display_row_for_autoscroll(
17692        &self,
17693        snapshot: &DisplaySnapshot,
17694    ) -> Option<DisplayRow> {
17695        self.highlighted_rows
17696            .values()
17697            .flat_map(|highlighted_rows| highlighted_rows.iter())
17698            .filter_map(|highlight| {
17699                if highlight.options.autoscroll {
17700                    Some(highlight.range.start.to_display_point(snapshot).row())
17701                } else {
17702                    None
17703                }
17704            })
17705            .min()
17706    }
17707
17708    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17709        self.highlight_background::<SearchWithinRange>(
17710            ranges,
17711            |colors| colors.editor_document_highlight_read_background,
17712            cx,
17713        )
17714    }
17715
17716    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17717        self.breadcrumb_header = Some(new_header);
17718    }
17719
17720    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17721        self.clear_background_highlights::<SearchWithinRange>(cx);
17722    }
17723
17724    pub fn highlight_background<T: 'static>(
17725        &mut self,
17726        ranges: &[Range<Anchor>],
17727        color_fetcher: fn(&ThemeColors) -> Hsla,
17728        cx: &mut Context<Self>,
17729    ) {
17730        self.background_highlights
17731            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17732        self.scrollbar_marker_state.dirty = true;
17733        cx.notify();
17734    }
17735
17736    pub fn clear_background_highlights<T: 'static>(
17737        &mut self,
17738        cx: &mut Context<Self>,
17739    ) -> Option<BackgroundHighlight> {
17740        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17741        if !text_highlights.1.is_empty() {
17742            self.scrollbar_marker_state.dirty = true;
17743            cx.notify();
17744        }
17745        Some(text_highlights)
17746    }
17747
17748    pub fn highlight_gutter<T: 'static>(
17749        &mut self,
17750        ranges: &[Range<Anchor>],
17751        color_fetcher: fn(&App) -> Hsla,
17752        cx: &mut Context<Self>,
17753    ) {
17754        self.gutter_highlights
17755            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17756        cx.notify();
17757    }
17758
17759    pub fn clear_gutter_highlights<T: 'static>(
17760        &mut self,
17761        cx: &mut Context<Self>,
17762    ) -> Option<GutterHighlight> {
17763        cx.notify();
17764        self.gutter_highlights.remove(&TypeId::of::<T>())
17765    }
17766
17767    #[cfg(feature = "test-support")]
17768    pub fn all_text_background_highlights(
17769        &self,
17770        window: &mut Window,
17771        cx: &mut Context<Self>,
17772    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17773        let snapshot = self.snapshot(window, cx);
17774        let buffer = &snapshot.buffer_snapshot;
17775        let start = buffer.anchor_before(0);
17776        let end = buffer.anchor_after(buffer.len());
17777        let theme = cx.theme().colors();
17778        self.background_highlights_in_range(start..end, &snapshot, theme)
17779    }
17780
17781    #[cfg(feature = "test-support")]
17782    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17783        let snapshot = self.buffer().read(cx).snapshot(cx);
17784
17785        let highlights = self
17786            .background_highlights
17787            .get(&TypeId::of::<items::BufferSearchHighlights>());
17788
17789        if let Some((_color, ranges)) = highlights {
17790            ranges
17791                .iter()
17792                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17793                .collect_vec()
17794        } else {
17795            vec![]
17796        }
17797    }
17798
17799    fn document_highlights_for_position<'a>(
17800        &'a self,
17801        position: Anchor,
17802        buffer: &'a MultiBufferSnapshot,
17803    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17804        let read_highlights = self
17805            .background_highlights
17806            .get(&TypeId::of::<DocumentHighlightRead>())
17807            .map(|h| &h.1);
17808        let write_highlights = self
17809            .background_highlights
17810            .get(&TypeId::of::<DocumentHighlightWrite>())
17811            .map(|h| &h.1);
17812        let left_position = position.bias_left(buffer);
17813        let right_position = position.bias_right(buffer);
17814        read_highlights
17815            .into_iter()
17816            .chain(write_highlights)
17817            .flat_map(move |ranges| {
17818                let start_ix = match ranges.binary_search_by(|probe| {
17819                    let cmp = probe.end.cmp(&left_position, buffer);
17820                    if cmp.is_ge() {
17821                        Ordering::Greater
17822                    } else {
17823                        Ordering::Less
17824                    }
17825                }) {
17826                    Ok(i) | Err(i) => i,
17827                };
17828
17829                ranges[start_ix..]
17830                    .iter()
17831                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17832            })
17833    }
17834
17835    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17836        self.background_highlights
17837            .get(&TypeId::of::<T>())
17838            .map_or(false, |(_, highlights)| !highlights.is_empty())
17839    }
17840
17841    pub fn background_highlights_in_range(
17842        &self,
17843        search_range: Range<Anchor>,
17844        display_snapshot: &DisplaySnapshot,
17845        theme: &ThemeColors,
17846    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17847        let mut results = Vec::new();
17848        for (color_fetcher, ranges) in self.background_highlights.values() {
17849            let color = color_fetcher(theme);
17850            let start_ix = match ranges.binary_search_by(|probe| {
17851                let cmp = probe
17852                    .end
17853                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17854                if cmp.is_gt() {
17855                    Ordering::Greater
17856                } else {
17857                    Ordering::Less
17858                }
17859            }) {
17860                Ok(i) | Err(i) => i,
17861            };
17862            for range in &ranges[start_ix..] {
17863                if range
17864                    .start
17865                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17866                    .is_ge()
17867                {
17868                    break;
17869                }
17870
17871                let start = range.start.to_display_point(display_snapshot);
17872                let end = range.end.to_display_point(display_snapshot);
17873                results.push((start..end, color))
17874            }
17875        }
17876        results
17877    }
17878
17879    pub fn background_highlight_row_ranges<T: 'static>(
17880        &self,
17881        search_range: Range<Anchor>,
17882        display_snapshot: &DisplaySnapshot,
17883        count: usize,
17884    ) -> Vec<RangeInclusive<DisplayPoint>> {
17885        let mut results = Vec::new();
17886        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17887            return vec![];
17888        };
17889
17890        let start_ix = match ranges.binary_search_by(|probe| {
17891            let cmp = probe
17892                .end
17893                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17894            if cmp.is_gt() {
17895                Ordering::Greater
17896            } else {
17897                Ordering::Less
17898            }
17899        }) {
17900            Ok(i) | Err(i) => i,
17901        };
17902        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17903            if let (Some(start_display), Some(end_display)) = (start, end) {
17904                results.push(
17905                    start_display.to_display_point(display_snapshot)
17906                        ..=end_display.to_display_point(display_snapshot),
17907                );
17908            }
17909        };
17910        let mut start_row: Option<Point> = None;
17911        let mut end_row: Option<Point> = None;
17912        if ranges.len() > count {
17913            return Vec::new();
17914        }
17915        for range in &ranges[start_ix..] {
17916            if range
17917                .start
17918                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17919                .is_ge()
17920            {
17921                break;
17922            }
17923            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17924            if let Some(current_row) = &end_row {
17925                if end.row == current_row.row {
17926                    continue;
17927                }
17928            }
17929            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17930            if start_row.is_none() {
17931                assert_eq!(end_row, None);
17932                start_row = Some(start);
17933                end_row = Some(end);
17934                continue;
17935            }
17936            if let Some(current_end) = end_row.as_mut() {
17937                if start.row > current_end.row + 1 {
17938                    push_region(start_row, end_row);
17939                    start_row = Some(start);
17940                    end_row = Some(end);
17941                } else {
17942                    // Merge two hunks.
17943                    *current_end = end;
17944                }
17945            } else {
17946                unreachable!();
17947            }
17948        }
17949        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17950        push_region(start_row, end_row);
17951        results
17952    }
17953
17954    pub fn gutter_highlights_in_range(
17955        &self,
17956        search_range: Range<Anchor>,
17957        display_snapshot: &DisplaySnapshot,
17958        cx: &App,
17959    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17960        let mut results = Vec::new();
17961        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17962            let color = color_fetcher(cx);
17963            let start_ix = match ranges.binary_search_by(|probe| {
17964                let cmp = probe
17965                    .end
17966                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17967                if cmp.is_gt() {
17968                    Ordering::Greater
17969                } else {
17970                    Ordering::Less
17971                }
17972            }) {
17973                Ok(i) | Err(i) => i,
17974            };
17975            for range in &ranges[start_ix..] {
17976                if range
17977                    .start
17978                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17979                    .is_ge()
17980                {
17981                    break;
17982                }
17983
17984                let start = range.start.to_display_point(display_snapshot);
17985                let end = range.end.to_display_point(display_snapshot);
17986                results.push((start..end, color))
17987            }
17988        }
17989        results
17990    }
17991
17992    /// Get the text ranges corresponding to the redaction query
17993    pub fn redacted_ranges(
17994        &self,
17995        search_range: Range<Anchor>,
17996        display_snapshot: &DisplaySnapshot,
17997        cx: &App,
17998    ) -> Vec<Range<DisplayPoint>> {
17999        display_snapshot
18000            .buffer_snapshot
18001            .redacted_ranges(search_range, |file| {
18002                if let Some(file) = file {
18003                    file.is_private()
18004                        && EditorSettings::get(
18005                            Some(SettingsLocation {
18006                                worktree_id: file.worktree_id(cx),
18007                                path: file.path().as_ref(),
18008                            }),
18009                            cx,
18010                        )
18011                        .redact_private_values
18012                } else {
18013                    false
18014                }
18015            })
18016            .map(|range| {
18017                range.start.to_display_point(display_snapshot)
18018                    ..range.end.to_display_point(display_snapshot)
18019            })
18020            .collect()
18021    }
18022
18023    pub fn highlight_text<T: 'static>(
18024        &mut self,
18025        ranges: Vec<Range<Anchor>>,
18026        style: HighlightStyle,
18027        cx: &mut Context<Self>,
18028    ) {
18029        self.display_map.update(cx, |map, _| {
18030            map.highlight_text(TypeId::of::<T>(), ranges, style)
18031        });
18032        cx.notify();
18033    }
18034
18035    pub(crate) fn highlight_inlays<T: 'static>(
18036        &mut self,
18037        highlights: Vec<InlayHighlight>,
18038        style: HighlightStyle,
18039        cx: &mut Context<Self>,
18040    ) {
18041        self.display_map.update(cx, |map, _| {
18042            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18043        });
18044        cx.notify();
18045    }
18046
18047    pub fn text_highlights<'a, T: 'static>(
18048        &'a self,
18049        cx: &'a App,
18050    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18051        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18052    }
18053
18054    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18055        let cleared = self
18056            .display_map
18057            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18058        if cleared {
18059            cx.notify();
18060        }
18061    }
18062
18063    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18064        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18065            && self.focus_handle.is_focused(window)
18066    }
18067
18068    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18069        self.show_cursor_when_unfocused = is_enabled;
18070        cx.notify();
18071    }
18072
18073    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18074        cx.notify();
18075    }
18076
18077    fn on_debug_session_event(
18078        &mut self,
18079        _session: Entity<Session>,
18080        event: &SessionEvent,
18081        cx: &mut Context<Self>,
18082    ) {
18083        match event {
18084            SessionEvent::InvalidateInlineValue => {
18085                self.refresh_inline_values(cx);
18086            }
18087            _ => {}
18088        }
18089    }
18090
18091    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18092        let Some(project) = self.project.clone() else {
18093            return;
18094        };
18095
18096        if !self.inline_value_cache.enabled {
18097            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18098            self.splice_inlays(&inlays, Vec::new(), cx);
18099            return;
18100        }
18101
18102        let current_execution_position = self
18103            .highlighted_rows
18104            .get(&TypeId::of::<ActiveDebugLine>())
18105            .and_then(|lines| lines.last().map(|line| line.range.start));
18106
18107        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18108            let inline_values = editor
18109                .update(cx, |editor, cx| {
18110                    let Some(current_execution_position) = current_execution_position else {
18111                        return Some(Task::ready(Ok(Vec::new())));
18112                    };
18113
18114                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18115                        let snapshot = buffer.snapshot(cx);
18116
18117                        let excerpt = snapshot.excerpt_containing(
18118                            current_execution_position..current_execution_position,
18119                        )?;
18120
18121                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18122                    })?;
18123
18124                    let range =
18125                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18126
18127                    project.inline_values(buffer, range, cx)
18128                })
18129                .ok()
18130                .flatten()?
18131                .await
18132                .context("refreshing debugger inlays")
18133                .log_err()?;
18134
18135            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18136
18137            for (buffer_id, inline_value) in inline_values
18138                .into_iter()
18139                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18140            {
18141                buffer_inline_values
18142                    .entry(buffer_id)
18143                    .or_default()
18144                    .push(inline_value);
18145            }
18146
18147            editor
18148                .update(cx, |editor, cx| {
18149                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18150                    let mut new_inlays = Vec::default();
18151
18152                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18153                        let buffer_id = buffer_snapshot.remote_id();
18154                        buffer_inline_values
18155                            .get(&buffer_id)
18156                            .into_iter()
18157                            .flatten()
18158                            .for_each(|hint| {
18159                                let inlay = Inlay::debugger_hint(
18160                                    post_inc(&mut editor.next_inlay_id),
18161                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18162                                    hint.text(),
18163                                );
18164
18165                                new_inlays.push(inlay);
18166                            });
18167                    }
18168
18169                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18170                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18171
18172                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18173                })
18174                .ok()?;
18175            Some(())
18176        });
18177    }
18178
18179    fn on_buffer_event(
18180        &mut self,
18181        multibuffer: &Entity<MultiBuffer>,
18182        event: &multi_buffer::Event,
18183        window: &mut Window,
18184        cx: &mut Context<Self>,
18185    ) {
18186        match event {
18187            multi_buffer::Event::Edited {
18188                singleton_buffer_edited,
18189                edited_buffer: buffer_edited,
18190            } => {
18191                self.scrollbar_marker_state.dirty = true;
18192                self.active_indent_guides_state.dirty = true;
18193                self.refresh_active_diagnostics(cx);
18194                self.refresh_code_actions(window, cx);
18195                self.refresh_selected_text_highlights(true, window, cx);
18196                refresh_matching_bracket_highlights(self, window, cx);
18197                if self.has_active_inline_completion() {
18198                    self.update_visible_inline_completion(window, cx);
18199                }
18200                if let Some(buffer) = buffer_edited {
18201                    let buffer_id = buffer.read(cx).remote_id();
18202                    if !self.registered_buffers.contains_key(&buffer_id) {
18203                        if let Some(project) = self.project.as_ref() {
18204                            project.update(cx, |project, cx| {
18205                                self.registered_buffers.insert(
18206                                    buffer_id,
18207                                    project.register_buffer_with_language_servers(&buffer, cx),
18208                                );
18209                            })
18210                        }
18211                    }
18212                }
18213                cx.emit(EditorEvent::BufferEdited);
18214                cx.emit(SearchEvent::MatchesInvalidated);
18215                if *singleton_buffer_edited {
18216                    if let Some(project) = &self.project {
18217                        #[allow(clippy::mutable_key_type)]
18218                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18219                            multibuffer
18220                                .all_buffers()
18221                                .into_iter()
18222                                .filter_map(|buffer| {
18223                                    buffer.update(cx, |buffer, cx| {
18224                                        let language = buffer.language()?;
18225                                        let should_discard = project.update(cx, |project, cx| {
18226                                            project.is_local()
18227                                                && !project.has_language_servers_for(buffer, cx)
18228                                        });
18229                                        should_discard.not().then_some(language.clone())
18230                                    })
18231                                })
18232                                .collect::<HashSet<_>>()
18233                        });
18234                        if !languages_affected.is_empty() {
18235                            self.refresh_inlay_hints(
18236                                InlayHintRefreshReason::BufferEdited(languages_affected),
18237                                cx,
18238                            );
18239                        }
18240                    }
18241                }
18242
18243                let Some(project) = &self.project else { return };
18244                let (telemetry, is_via_ssh) = {
18245                    let project = project.read(cx);
18246                    let telemetry = project.client().telemetry().clone();
18247                    let is_via_ssh = project.is_via_ssh();
18248                    (telemetry, is_via_ssh)
18249                };
18250                refresh_linked_ranges(self, window, cx);
18251                telemetry.log_edit_event("editor", is_via_ssh);
18252            }
18253            multi_buffer::Event::ExcerptsAdded {
18254                buffer,
18255                predecessor,
18256                excerpts,
18257            } => {
18258                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18259                let buffer_id = buffer.read(cx).remote_id();
18260                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18261                    if let Some(project) = &self.project {
18262                        update_uncommitted_diff_for_buffer(
18263                            cx.entity(),
18264                            project,
18265                            [buffer.clone()],
18266                            self.buffer.clone(),
18267                            cx,
18268                        )
18269                        .detach();
18270                    }
18271                }
18272                cx.emit(EditorEvent::ExcerptsAdded {
18273                    buffer: buffer.clone(),
18274                    predecessor: *predecessor,
18275                    excerpts: excerpts.clone(),
18276                });
18277                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18278            }
18279            multi_buffer::Event::ExcerptsRemoved {
18280                ids,
18281                removed_buffer_ids,
18282            } => {
18283                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18284                let buffer = self.buffer.read(cx);
18285                self.registered_buffers
18286                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18287                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18288                cx.emit(EditorEvent::ExcerptsRemoved {
18289                    ids: ids.clone(),
18290                    removed_buffer_ids: removed_buffer_ids.clone(),
18291                })
18292            }
18293            multi_buffer::Event::ExcerptsEdited {
18294                excerpt_ids,
18295                buffer_ids,
18296            } => {
18297                self.display_map.update(cx, |map, cx| {
18298                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18299                });
18300                cx.emit(EditorEvent::ExcerptsEdited {
18301                    ids: excerpt_ids.clone(),
18302                })
18303            }
18304            multi_buffer::Event::ExcerptsExpanded { ids } => {
18305                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18306                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18307            }
18308            multi_buffer::Event::Reparsed(buffer_id) => {
18309                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18310                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18311
18312                cx.emit(EditorEvent::Reparsed(*buffer_id));
18313            }
18314            multi_buffer::Event::DiffHunksToggled => {
18315                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18316            }
18317            multi_buffer::Event::LanguageChanged(buffer_id) => {
18318                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18319                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18320                cx.emit(EditorEvent::Reparsed(*buffer_id));
18321                cx.notify();
18322            }
18323            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18324            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18325            multi_buffer::Event::FileHandleChanged
18326            | multi_buffer::Event::Reloaded
18327            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18328            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18329            multi_buffer::Event::DiagnosticsUpdated => {
18330                self.refresh_active_diagnostics(cx);
18331                self.refresh_inline_diagnostics(true, window, cx);
18332                self.scrollbar_marker_state.dirty = true;
18333                cx.notify();
18334            }
18335            _ => {}
18336        };
18337    }
18338
18339    pub fn start_temporary_diff_override(&mut self) {
18340        self.load_diff_task.take();
18341        self.temporary_diff_override = true;
18342    }
18343
18344    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18345        self.temporary_diff_override = false;
18346        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18347        self.buffer.update(cx, |buffer, cx| {
18348            buffer.set_all_diff_hunks_collapsed(cx);
18349        });
18350
18351        if let Some(project) = self.project.clone() {
18352            self.load_diff_task = Some(
18353                update_uncommitted_diff_for_buffer(
18354                    cx.entity(),
18355                    &project,
18356                    self.buffer.read(cx).all_buffers(),
18357                    self.buffer.clone(),
18358                    cx,
18359                )
18360                .shared(),
18361            );
18362        }
18363    }
18364
18365    fn on_display_map_changed(
18366        &mut self,
18367        _: Entity<DisplayMap>,
18368        _: &mut Window,
18369        cx: &mut Context<Self>,
18370    ) {
18371        cx.notify();
18372    }
18373
18374    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18375        let new_severity = if self.diagnostics_enabled() {
18376            EditorSettings::get_global(cx)
18377                .diagnostics_max_severity
18378                .unwrap_or(DiagnosticSeverity::Hint)
18379        } else {
18380            DiagnosticSeverity::Off
18381        };
18382        self.set_max_diagnostics_severity(new_severity, cx);
18383        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18384        self.update_edit_prediction_settings(cx);
18385        self.refresh_inline_completion(true, false, window, cx);
18386        self.refresh_inlay_hints(
18387            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18388                self.selections.newest_anchor().head(),
18389                &self.buffer.read(cx).snapshot(cx),
18390                cx,
18391            )),
18392            cx,
18393        );
18394
18395        let old_cursor_shape = self.cursor_shape;
18396
18397        {
18398            let editor_settings = EditorSettings::get_global(cx);
18399            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18400            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18401            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18402            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18403        }
18404
18405        if old_cursor_shape != self.cursor_shape {
18406            cx.emit(EditorEvent::CursorShapeChanged);
18407        }
18408
18409        let project_settings = ProjectSettings::get_global(cx);
18410        self.serialize_dirty_buffers =
18411            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18412
18413        if self.mode.is_full() {
18414            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18415            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18416            if self.show_inline_diagnostics != show_inline_diagnostics {
18417                self.show_inline_diagnostics = show_inline_diagnostics;
18418                self.refresh_inline_diagnostics(false, window, cx);
18419            }
18420
18421            if self.git_blame_inline_enabled != inline_blame_enabled {
18422                self.toggle_git_blame_inline_internal(false, window, cx);
18423            }
18424
18425            let minimap_settings = EditorSettings::get_global(cx).minimap;
18426            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18427                self.set_minimap_visibility(
18428                    self.minimap_visibility.toggle_visibility(),
18429                    window,
18430                    cx,
18431                );
18432            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18433                minimap_entity.update(cx, |minimap_editor, cx| {
18434                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18435                })
18436            }
18437        }
18438
18439        cx.notify();
18440    }
18441
18442    pub fn set_searchable(&mut self, searchable: bool) {
18443        self.searchable = searchable;
18444    }
18445
18446    pub fn searchable(&self) -> bool {
18447        self.searchable
18448    }
18449
18450    fn open_proposed_changes_editor(
18451        &mut self,
18452        _: &OpenProposedChangesEditor,
18453        window: &mut Window,
18454        cx: &mut Context<Self>,
18455    ) {
18456        let Some(workspace) = self.workspace() else {
18457            cx.propagate();
18458            return;
18459        };
18460
18461        let selections = self.selections.all::<usize>(cx);
18462        let multi_buffer = self.buffer.read(cx);
18463        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18464        let mut new_selections_by_buffer = HashMap::default();
18465        for selection in selections {
18466            for (buffer, range, _) in
18467                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18468            {
18469                let mut range = range.to_point(buffer);
18470                range.start.column = 0;
18471                range.end.column = buffer.line_len(range.end.row);
18472                new_selections_by_buffer
18473                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18474                    .or_insert(Vec::new())
18475                    .push(range)
18476            }
18477        }
18478
18479        let proposed_changes_buffers = new_selections_by_buffer
18480            .into_iter()
18481            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18482            .collect::<Vec<_>>();
18483        let proposed_changes_editor = cx.new(|cx| {
18484            ProposedChangesEditor::new(
18485                "Proposed changes",
18486                proposed_changes_buffers,
18487                self.project.clone(),
18488                window,
18489                cx,
18490            )
18491        });
18492
18493        window.defer(cx, move |window, cx| {
18494            workspace.update(cx, |workspace, cx| {
18495                workspace.active_pane().update(cx, |pane, cx| {
18496                    pane.add_item(
18497                        Box::new(proposed_changes_editor),
18498                        true,
18499                        true,
18500                        None,
18501                        window,
18502                        cx,
18503                    );
18504                });
18505            });
18506        });
18507    }
18508
18509    pub fn open_excerpts_in_split(
18510        &mut self,
18511        _: &OpenExcerptsSplit,
18512        window: &mut Window,
18513        cx: &mut Context<Self>,
18514    ) {
18515        self.open_excerpts_common(None, true, window, cx)
18516    }
18517
18518    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18519        self.open_excerpts_common(None, false, window, cx)
18520    }
18521
18522    fn open_excerpts_common(
18523        &mut self,
18524        jump_data: Option<JumpData>,
18525        split: bool,
18526        window: &mut Window,
18527        cx: &mut Context<Self>,
18528    ) {
18529        let Some(workspace) = self.workspace() else {
18530            cx.propagate();
18531            return;
18532        };
18533
18534        if self.buffer.read(cx).is_singleton() {
18535            cx.propagate();
18536            return;
18537        }
18538
18539        let mut new_selections_by_buffer = HashMap::default();
18540        match &jump_data {
18541            Some(JumpData::MultiBufferPoint {
18542                excerpt_id,
18543                position,
18544                anchor,
18545                line_offset_from_top,
18546            }) => {
18547                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18548                if let Some(buffer) = multi_buffer_snapshot
18549                    .buffer_id_for_excerpt(*excerpt_id)
18550                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18551                {
18552                    let buffer_snapshot = buffer.read(cx).snapshot();
18553                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18554                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18555                    } else {
18556                        buffer_snapshot.clip_point(*position, Bias::Left)
18557                    };
18558                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18559                    new_selections_by_buffer.insert(
18560                        buffer,
18561                        (
18562                            vec![jump_to_offset..jump_to_offset],
18563                            Some(*line_offset_from_top),
18564                        ),
18565                    );
18566                }
18567            }
18568            Some(JumpData::MultiBufferRow {
18569                row,
18570                line_offset_from_top,
18571            }) => {
18572                let point = MultiBufferPoint::new(row.0, 0);
18573                if let Some((buffer, buffer_point, _)) =
18574                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18575                {
18576                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18577                    new_selections_by_buffer
18578                        .entry(buffer)
18579                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18580                        .0
18581                        .push(buffer_offset..buffer_offset)
18582                }
18583            }
18584            None => {
18585                let selections = self.selections.all::<usize>(cx);
18586                let multi_buffer = self.buffer.read(cx);
18587                for selection in selections {
18588                    for (snapshot, range, _, anchor) in multi_buffer
18589                        .snapshot(cx)
18590                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18591                    {
18592                        if let Some(anchor) = anchor {
18593                            // selection is in a deleted hunk
18594                            let Some(buffer_id) = anchor.buffer_id else {
18595                                continue;
18596                            };
18597                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18598                                continue;
18599                            };
18600                            let offset = text::ToOffset::to_offset(
18601                                &anchor.text_anchor,
18602                                &buffer_handle.read(cx).snapshot(),
18603                            );
18604                            let range = offset..offset;
18605                            new_selections_by_buffer
18606                                .entry(buffer_handle)
18607                                .or_insert((Vec::new(), None))
18608                                .0
18609                                .push(range)
18610                        } else {
18611                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18612                            else {
18613                                continue;
18614                            };
18615                            new_selections_by_buffer
18616                                .entry(buffer_handle)
18617                                .or_insert((Vec::new(), None))
18618                                .0
18619                                .push(range)
18620                        }
18621                    }
18622                }
18623            }
18624        }
18625
18626        new_selections_by_buffer
18627            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18628
18629        if new_selections_by_buffer.is_empty() {
18630            return;
18631        }
18632
18633        // We defer the pane interaction because we ourselves are a workspace item
18634        // and activating a new item causes the pane to call a method on us reentrantly,
18635        // which panics if we're on the stack.
18636        window.defer(cx, move |window, cx| {
18637            workspace.update(cx, |workspace, cx| {
18638                let pane = if split {
18639                    workspace.adjacent_pane(window, cx)
18640                } else {
18641                    workspace.active_pane().clone()
18642                };
18643
18644                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18645                    let editor = buffer
18646                        .read(cx)
18647                        .file()
18648                        .is_none()
18649                        .then(|| {
18650                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18651                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18652                            // Instead, we try to activate the existing editor in the pane first.
18653                            let (editor, pane_item_index) =
18654                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18655                                    let editor = item.downcast::<Editor>()?;
18656                                    let singleton_buffer =
18657                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18658                                    if singleton_buffer == buffer {
18659                                        Some((editor, i))
18660                                    } else {
18661                                        None
18662                                    }
18663                                })?;
18664                            pane.update(cx, |pane, cx| {
18665                                pane.activate_item(pane_item_index, true, true, window, cx)
18666                            });
18667                            Some(editor)
18668                        })
18669                        .flatten()
18670                        .unwrap_or_else(|| {
18671                            workspace.open_project_item::<Self>(
18672                                pane.clone(),
18673                                buffer,
18674                                true,
18675                                true,
18676                                window,
18677                                cx,
18678                            )
18679                        });
18680
18681                    editor.update(cx, |editor, cx| {
18682                        let autoscroll = match scroll_offset {
18683                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18684                            None => Autoscroll::newest(),
18685                        };
18686                        let nav_history = editor.nav_history.take();
18687                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18688                            s.select_ranges(ranges);
18689                        });
18690                        editor.nav_history = nav_history;
18691                    });
18692                }
18693            })
18694        });
18695    }
18696
18697    // For now, don't allow opening excerpts in buffers that aren't backed by
18698    // regular project files.
18699    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18700        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18701    }
18702
18703    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18704        let snapshot = self.buffer.read(cx).read(cx);
18705        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18706        Some(
18707            ranges
18708                .iter()
18709                .map(move |range| {
18710                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18711                })
18712                .collect(),
18713        )
18714    }
18715
18716    fn selection_replacement_ranges(
18717        &self,
18718        range: Range<OffsetUtf16>,
18719        cx: &mut App,
18720    ) -> Vec<Range<OffsetUtf16>> {
18721        let selections = self.selections.all::<OffsetUtf16>(cx);
18722        let newest_selection = selections
18723            .iter()
18724            .max_by_key(|selection| selection.id)
18725            .unwrap();
18726        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18727        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18728        let snapshot = self.buffer.read(cx).read(cx);
18729        selections
18730            .into_iter()
18731            .map(|mut selection| {
18732                selection.start.0 =
18733                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18734                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18735                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18736                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18737            })
18738            .collect()
18739    }
18740
18741    fn report_editor_event(
18742        &self,
18743        event_type: &'static str,
18744        file_extension: Option<String>,
18745        cx: &App,
18746    ) {
18747        if cfg!(any(test, feature = "test-support")) {
18748            return;
18749        }
18750
18751        let Some(project) = &self.project else { return };
18752
18753        // If None, we are in a file without an extension
18754        let file = self
18755            .buffer
18756            .read(cx)
18757            .as_singleton()
18758            .and_then(|b| b.read(cx).file());
18759        let file_extension = file_extension.or(file
18760            .as_ref()
18761            .and_then(|file| Path::new(file.file_name(cx)).extension())
18762            .and_then(|e| e.to_str())
18763            .map(|a| a.to_string()));
18764
18765        let vim_mode = vim_enabled(cx);
18766
18767        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18768        let copilot_enabled = edit_predictions_provider
18769            == language::language_settings::EditPredictionProvider::Copilot;
18770        let copilot_enabled_for_language = self
18771            .buffer
18772            .read(cx)
18773            .language_settings(cx)
18774            .show_edit_predictions;
18775
18776        let project = project.read(cx);
18777        telemetry::event!(
18778            event_type,
18779            file_extension,
18780            vim_mode,
18781            copilot_enabled,
18782            copilot_enabled_for_language,
18783            edit_predictions_provider,
18784            is_via_ssh = project.is_via_ssh(),
18785        );
18786    }
18787
18788    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18789    /// with each line being an array of {text, highlight} objects.
18790    fn copy_highlight_json(
18791        &mut self,
18792        _: &CopyHighlightJson,
18793        window: &mut Window,
18794        cx: &mut Context<Self>,
18795    ) {
18796        #[derive(Serialize)]
18797        struct Chunk<'a> {
18798            text: String,
18799            highlight: Option<&'a str>,
18800        }
18801
18802        let snapshot = self.buffer.read(cx).snapshot(cx);
18803        let range = self
18804            .selected_text_range(false, window, cx)
18805            .and_then(|selection| {
18806                if selection.range.is_empty() {
18807                    None
18808                } else {
18809                    Some(selection.range)
18810                }
18811            })
18812            .unwrap_or_else(|| 0..snapshot.len());
18813
18814        let chunks = snapshot.chunks(range, true);
18815        let mut lines = Vec::new();
18816        let mut line: VecDeque<Chunk> = VecDeque::new();
18817
18818        let Some(style) = self.style.as_ref() else {
18819            return;
18820        };
18821
18822        for chunk in chunks {
18823            let highlight = chunk
18824                .syntax_highlight_id
18825                .and_then(|id| id.name(&style.syntax));
18826            let mut chunk_lines = chunk.text.split('\n').peekable();
18827            while let Some(text) = chunk_lines.next() {
18828                let mut merged_with_last_token = false;
18829                if let Some(last_token) = line.back_mut() {
18830                    if last_token.highlight == highlight {
18831                        last_token.text.push_str(text);
18832                        merged_with_last_token = true;
18833                    }
18834                }
18835
18836                if !merged_with_last_token {
18837                    line.push_back(Chunk {
18838                        text: text.into(),
18839                        highlight,
18840                    });
18841                }
18842
18843                if chunk_lines.peek().is_some() {
18844                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18845                        line.pop_front();
18846                    }
18847                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18848                        line.pop_back();
18849                    }
18850
18851                    lines.push(mem::take(&mut line));
18852                }
18853            }
18854        }
18855
18856        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18857            return;
18858        };
18859        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18860    }
18861
18862    pub fn open_context_menu(
18863        &mut self,
18864        _: &OpenContextMenu,
18865        window: &mut Window,
18866        cx: &mut Context<Self>,
18867    ) {
18868        self.request_autoscroll(Autoscroll::newest(), cx);
18869        let position = self.selections.newest_display(cx).start;
18870        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18871    }
18872
18873    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18874        &self.inlay_hint_cache
18875    }
18876
18877    pub fn replay_insert_event(
18878        &mut self,
18879        text: &str,
18880        relative_utf16_range: Option<Range<isize>>,
18881        window: &mut Window,
18882        cx: &mut Context<Self>,
18883    ) {
18884        if !self.input_enabled {
18885            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18886            return;
18887        }
18888        if let Some(relative_utf16_range) = relative_utf16_range {
18889            let selections = self.selections.all::<OffsetUtf16>(cx);
18890            self.change_selections(None, window, cx, |s| {
18891                let new_ranges = selections.into_iter().map(|range| {
18892                    let start = OffsetUtf16(
18893                        range
18894                            .head()
18895                            .0
18896                            .saturating_add_signed(relative_utf16_range.start),
18897                    );
18898                    let end = OffsetUtf16(
18899                        range
18900                            .head()
18901                            .0
18902                            .saturating_add_signed(relative_utf16_range.end),
18903                    );
18904                    start..end
18905                });
18906                s.select_ranges(new_ranges);
18907            });
18908        }
18909
18910        self.handle_input(text, window, cx);
18911    }
18912
18913    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18914        let Some(provider) = self.semantics_provider.as_ref() else {
18915            return false;
18916        };
18917
18918        let mut supports = false;
18919        self.buffer().update(cx, |this, cx| {
18920            this.for_each_buffer(|buffer| {
18921                supports |= provider.supports_inlay_hints(buffer, cx);
18922            });
18923        });
18924
18925        supports
18926    }
18927
18928    pub fn is_focused(&self, window: &Window) -> bool {
18929        self.focus_handle.is_focused(window)
18930    }
18931
18932    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18933        cx.emit(EditorEvent::Focused);
18934
18935        if let Some(descendant) = self
18936            .last_focused_descendant
18937            .take()
18938            .and_then(|descendant| descendant.upgrade())
18939        {
18940            window.focus(&descendant);
18941        } else {
18942            if let Some(blame) = self.blame.as_ref() {
18943                blame.update(cx, GitBlame::focus)
18944            }
18945
18946            self.blink_manager.update(cx, BlinkManager::enable);
18947            self.show_cursor_names(window, cx);
18948            self.buffer.update(cx, |buffer, cx| {
18949                buffer.finalize_last_transaction(cx);
18950                if self.leader_id.is_none() {
18951                    buffer.set_active_selections(
18952                        &self.selections.disjoint_anchors(),
18953                        self.selections.line_mode,
18954                        self.cursor_shape,
18955                        cx,
18956                    );
18957                }
18958            });
18959        }
18960    }
18961
18962    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18963        cx.emit(EditorEvent::FocusedIn)
18964    }
18965
18966    fn handle_focus_out(
18967        &mut self,
18968        event: FocusOutEvent,
18969        _window: &mut Window,
18970        cx: &mut Context<Self>,
18971    ) {
18972        if event.blurred != self.focus_handle {
18973            self.last_focused_descendant = Some(event.blurred);
18974        }
18975        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18976    }
18977
18978    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18979        self.blink_manager.update(cx, BlinkManager::disable);
18980        self.buffer
18981            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18982
18983        if let Some(blame) = self.blame.as_ref() {
18984            blame.update(cx, GitBlame::blur)
18985        }
18986        if !self.hover_state.focused(window, cx) {
18987            hide_hover(self, cx);
18988        }
18989        if !self
18990            .context_menu
18991            .borrow()
18992            .as_ref()
18993            .is_some_and(|context_menu| context_menu.focused(window, cx))
18994        {
18995            self.hide_context_menu(window, cx);
18996        }
18997        self.discard_inline_completion(false, cx);
18998        cx.emit(EditorEvent::Blurred);
18999        cx.notify();
19000    }
19001
19002    pub fn register_action<A: Action>(
19003        &mut self,
19004        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19005    ) -> Subscription {
19006        let id = self.next_editor_action_id.post_inc();
19007        let listener = Arc::new(listener);
19008        self.editor_actions.borrow_mut().insert(
19009            id,
19010            Box::new(move |window, _| {
19011                let listener = listener.clone();
19012                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19013                    let action = action.downcast_ref().unwrap();
19014                    if phase == DispatchPhase::Bubble {
19015                        listener(action, window, cx)
19016                    }
19017                })
19018            }),
19019        );
19020
19021        let editor_actions = self.editor_actions.clone();
19022        Subscription::new(move || {
19023            editor_actions.borrow_mut().remove(&id);
19024        })
19025    }
19026
19027    pub fn file_header_size(&self) -> u32 {
19028        FILE_HEADER_HEIGHT
19029    }
19030
19031    pub fn restore(
19032        &mut self,
19033        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19034        window: &mut Window,
19035        cx: &mut Context<Self>,
19036    ) {
19037        let workspace = self.workspace();
19038        let project = self.project.as_ref();
19039        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19040            let mut tasks = Vec::new();
19041            for (buffer_id, changes) in revert_changes {
19042                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19043                    buffer.update(cx, |buffer, cx| {
19044                        buffer.edit(
19045                            changes
19046                                .into_iter()
19047                                .map(|(range, text)| (range, text.to_string())),
19048                            None,
19049                            cx,
19050                        );
19051                    });
19052
19053                    if let Some(project) =
19054                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19055                    {
19056                        project.update(cx, |project, cx| {
19057                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19058                        })
19059                    }
19060                }
19061            }
19062            tasks
19063        });
19064        cx.spawn_in(window, async move |_, cx| {
19065            for (buffer, task) in save_tasks {
19066                let result = task.await;
19067                if result.is_err() {
19068                    let Some(path) = buffer
19069                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19070                        .ok()
19071                    else {
19072                        continue;
19073                    };
19074                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19075                        let Some(task) = cx
19076                            .update_window_entity(&workspace, |workspace, window, cx| {
19077                                workspace
19078                                    .open_path_preview(path, None, false, false, false, window, cx)
19079                            })
19080                            .ok()
19081                        else {
19082                            continue;
19083                        };
19084                        task.await.log_err();
19085                    }
19086                }
19087            }
19088        })
19089        .detach();
19090        self.change_selections(None, window, cx, |selections| selections.refresh());
19091    }
19092
19093    pub fn to_pixel_point(
19094        &self,
19095        source: multi_buffer::Anchor,
19096        editor_snapshot: &EditorSnapshot,
19097        window: &mut Window,
19098    ) -> Option<gpui::Point<Pixels>> {
19099        let source_point = source.to_display_point(editor_snapshot);
19100        self.display_to_pixel_point(source_point, editor_snapshot, window)
19101    }
19102
19103    pub fn display_to_pixel_point(
19104        &self,
19105        source: DisplayPoint,
19106        editor_snapshot: &EditorSnapshot,
19107        window: &mut Window,
19108    ) -> Option<gpui::Point<Pixels>> {
19109        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19110        let text_layout_details = self.text_layout_details(window);
19111        let scroll_top = text_layout_details
19112            .scroll_anchor
19113            .scroll_position(editor_snapshot)
19114            .y;
19115
19116        if source.row().as_f32() < scroll_top.floor() {
19117            return None;
19118        }
19119        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19120        let source_y = line_height * (source.row().as_f32() - scroll_top);
19121        Some(gpui::Point::new(source_x, source_y))
19122    }
19123
19124    pub fn has_visible_completions_menu(&self) -> bool {
19125        !self.edit_prediction_preview_is_active()
19126            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19127                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19128            })
19129    }
19130
19131    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19132        if self.mode.is_minimap() {
19133            return;
19134        }
19135        self.addons
19136            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19137    }
19138
19139    pub fn unregister_addon<T: Addon>(&mut self) {
19140        self.addons.remove(&std::any::TypeId::of::<T>());
19141    }
19142
19143    pub fn addon<T: Addon>(&self) -> Option<&T> {
19144        let type_id = std::any::TypeId::of::<T>();
19145        self.addons
19146            .get(&type_id)
19147            .and_then(|item| item.to_any().downcast_ref::<T>())
19148    }
19149
19150    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19151        let type_id = std::any::TypeId::of::<T>();
19152        self.addons
19153            .get_mut(&type_id)
19154            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19155    }
19156
19157    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19158        let text_layout_details = self.text_layout_details(window);
19159        let style = &text_layout_details.editor_style;
19160        let font_id = window.text_system().resolve_font(&style.text.font());
19161        let font_size = style.text.font_size.to_pixels(window.rem_size());
19162        let line_height = style.text.line_height_in_pixels(window.rem_size());
19163        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19164
19165        gpui::Size::new(em_width, line_height)
19166    }
19167
19168    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19169        self.load_diff_task.clone()
19170    }
19171
19172    fn read_metadata_from_db(
19173        &mut self,
19174        item_id: u64,
19175        workspace_id: WorkspaceId,
19176        window: &mut Window,
19177        cx: &mut Context<Editor>,
19178    ) {
19179        if self.is_singleton(cx)
19180            && !self.mode.is_minimap()
19181            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19182        {
19183            let buffer_snapshot = OnceCell::new();
19184
19185            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19186                if !folds.is_empty() {
19187                    let snapshot =
19188                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19189                    self.fold_ranges(
19190                        folds
19191                            .into_iter()
19192                            .map(|(start, end)| {
19193                                snapshot.clip_offset(start, Bias::Left)
19194                                    ..snapshot.clip_offset(end, Bias::Right)
19195                            })
19196                            .collect(),
19197                        false,
19198                        window,
19199                        cx,
19200                    );
19201                }
19202            }
19203
19204            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19205                if !selections.is_empty() {
19206                    let snapshot =
19207                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19208                    self.change_selections(None, window, cx, |s| {
19209                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19210                            snapshot.clip_offset(start, Bias::Left)
19211                                ..snapshot.clip_offset(end, Bias::Right)
19212                        }));
19213                    });
19214                }
19215            };
19216        }
19217
19218        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19219    }
19220}
19221
19222fn vim_enabled(cx: &App) -> bool {
19223    cx.global::<SettingsStore>()
19224        .raw_user_settings()
19225        .get("vim_mode")
19226        == Some(&serde_json::Value::Bool(true))
19227}
19228
19229// Consider user intent and default settings
19230fn choose_completion_range(
19231    completion: &Completion,
19232    intent: CompletionIntent,
19233    buffer: &Entity<Buffer>,
19234    cx: &mut Context<Editor>,
19235) -> Range<usize> {
19236    fn should_replace(
19237        completion: &Completion,
19238        insert_range: &Range<text::Anchor>,
19239        intent: CompletionIntent,
19240        completion_mode_setting: LspInsertMode,
19241        buffer: &Buffer,
19242    ) -> bool {
19243        // specific actions take precedence over settings
19244        match intent {
19245            CompletionIntent::CompleteWithInsert => return false,
19246            CompletionIntent::CompleteWithReplace => return true,
19247            CompletionIntent::Complete | CompletionIntent::Compose => {}
19248        }
19249
19250        match completion_mode_setting {
19251            LspInsertMode::Insert => false,
19252            LspInsertMode::Replace => true,
19253            LspInsertMode::ReplaceSubsequence => {
19254                let mut text_to_replace = buffer.chars_for_range(
19255                    buffer.anchor_before(completion.replace_range.start)
19256                        ..buffer.anchor_after(completion.replace_range.end),
19257                );
19258                let mut completion_text = completion.new_text.chars();
19259
19260                // is `text_to_replace` a subsequence of `completion_text`
19261                text_to_replace
19262                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19263            }
19264            LspInsertMode::ReplaceSuffix => {
19265                let range_after_cursor = insert_range.end..completion.replace_range.end;
19266
19267                let text_after_cursor = buffer
19268                    .text_for_range(
19269                        buffer.anchor_before(range_after_cursor.start)
19270                            ..buffer.anchor_after(range_after_cursor.end),
19271                    )
19272                    .collect::<String>();
19273                completion.new_text.ends_with(&text_after_cursor)
19274            }
19275        }
19276    }
19277
19278    let buffer = buffer.read(cx);
19279
19280    if let CompletionSource::Lsp {
19281        insert_range: Some(insert_range),
19282        ..
19283    } = &completion.source
19284    {
19285        let completion_mode_setting =
19286            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19287                .completions
19288                .lsp_insert_mode;
19289
19290        if !should_replace(
19291            completion,
19292            &insert_range,
19293            intent,
19294            completion_mode_setting,
19295            buffer,
19296        ) {
19297            return insert_range.to_offset(buffer);
19298        }
19299    }
19300
19301    completion.replace_range.to_offset(buffer)
19302}
19303
19304fn insert_extra_newline_brackets(
19305    buffer: &MultiBufferSnapshot,
19306    range: Range<usize>,
19307    language: &language::LanguageScope,
19308) -> bool {
19309    let leading_whitespace_len = buffer
19310        .reversed_chars_at(range.start)
19311        .take_while(|c| c.is_whitespace() && *c != '\n')
19312        .map(|c| c.len_utf8())
19313        .sum::<usize>();
19314    let trailing_whitespace_len = buffer
19315        .chars_at(range.end)
19316        .take_while(|c| c.is_whitespace() && *c != '\n')
19317        .map(|c| c.len_utf8())
19318        .sum::<usize>();
19319    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19320
19321    language.brackets().any(|(pair, enabled)| {
19322        let pair_start = pair.start.trim_end();
19323        let pair_end = pair.end.trim_start();
19324
19325        enabled
19326            && pair.newline
19327            && buffer.contains_str_at(range.end, pair_end)
19328            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19329    })
19330}
19331
19332fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19333    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19334        [(buffer, range, _)] => (*buffer, range.clone()),
19335        _ => return false,
19336    };
19337    let pair = {
19338        let mut result: Option<BracketMatch> = None;
19339
19340        for pair in buffer
19341            .all_bracket_ranges(range.clone())
19342            .filter(move |pair| {
19343                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19344            })
19345        {
19346            let len = pair.close_range.end - pair.open_range.start;
19347
19348            if let Some(existing) = &result {
19349                let existing_len = existing.close_range.end - existing.open_range.start;
19350                if len > existing_len {
19351                    continue;
19352                }
19353            }
19354
19355            result = Some(pair);
19356        }
19357
19358        result
19359    };
19360    let Some(pair) = pair else {
19361        return false;
19362    };
19363    pair.newline_only
19364        && buffer
19365            .chars_for_range(pair.open_range.end..range.start)
19366            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19367            .all(|c| c.is_whitespace() && c != '\n')
19368}
19369
19370fn update_uncommitted_diff_for_buffer(
19371    editor: Entity<Editor>,
19372    project: &Entity<Project>,
19373    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19374    buffer: Entity<MultiBuffer>,
19375    cx: &mut App,
19376) -> Task<()> {
19377    let mut tasks = Vec::new();
19378    project.update(cx, |project, cx| {
19379        for buffer in buffers {
19380            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19381                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19382            }
19383        }
19384    });
19385    cx.spawn(async move |cx| {
19386        let diffs = future::join_all(tasks).await;
19387        if editor
19388            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19389            .unwrap_or(false)
19390        {
19391            return;
19392        }
19393
19394        buffer
19395            .update(cx, |buffer, cx| {
19396                for diff in diffs.into_iter().flatten() {
19397                    buffer.add_diff(diff, cx);
19398                }
19399            })
19400            .ok();
19401    })
19402}
19403
19404fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19405    let tab_size = tab_size.get() as usize;
19406    let mut width = offset;
19407
19408    for ch in text.chars() {
19409        width += if ch == '\t' {
19410            tab_size - (width % tab_size)
19411        } else {
19412            1
19413        };
19414    }
19415
19416    width - offset
19417}
19418
19419#[cfg(test)]
19420mod tests {
19421    use super::*;
19422
19423    #[test]
19424    fn test_string_size_with_expanded_tabs() {
19425        let nz = |val| NonZeroU32::new(val).unwrap();
19426        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19427        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19428        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19429        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19430        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19431        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19432        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19433        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19434    }
19435}
19436
19437/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19438struct WordBreakingTokenizer<'a> {
19439    input: &'a str,
19440}
19441
19442impl<'a> WordBreakingTokenizer<'a> {
19443    fn new(input: &'a str) -> Self {
19444        Self { input }
19445    }
19446}
19447
19448fn is_char_ideographic(ch: char) -> bool {
19449    use unicode_script::Script::*;
19450    use unicode_script::UnicodeScript;
19451    matches!(ch.script(), Han | Tangut | Yi)
19452}
19453
19454fn is_grapheme_ideographic(text: &str) -> bool {
19455    text.chars().any(is_char_ideographic)
19456}
19457
19458fn is_grapheme_whitespace(text: &str) -> bool {
19459    text.chars().any(|x| x.is_whitespace())
19460}
19461
19462fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19463    text.chars().next().map_or(false, |ch| {
19464        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19465    })
19466}
19467
19468#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19469enum WordBreakToken<'a> {
19470    Word { token: &'a str, grapheme_len: usize },
19471    InlineWhitespace { token: &'a str, grapheme_len: usize },
19472    Newline,
19473}
19474
19475impl<'a> Iterator for WordBreakingTokenizer<'a> {
19476    /// Yields a span, the count of graphemes in the token, and whether it was
19477    /// whitespace. Note that it also breaks at word boundaries.
19478    type Item = WordBreakToken<'a>;
19479
19480    fn next(&mut self) -> Option<Self::Item> {
19481        use unicode_segmentation::UnicodeSegmentation;
19482        if self.input.is_empty() {
19483            return None;
19484        }
19485
19486        let mut iter = self.input.graphemes(true).peekable();
19487        let mut offset = 0;
19488        let mut grapheme_len = 0;
19489        if let Some(first_grapheme) = iter.next() {
19490            let is_newline = first_grapheme == "\n";
19491            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19492            offset += first_grapheme.len();
19493            grapheme_len += 1;
19494            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19495                if let Some(grapheme) = iter.peek().copied() {
19496                    if should_stay_with_preceding_ideograph(grapheme) {
19497                        offset += grapheme.len();
19498                        grapheme_len += 1;
19499                    }
19500                }
19501            } else {
19502                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19503                let mut next_word_bound = words.peek().copied();
19504                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19505                    next_word_bound = words.next();
19506                }
19507                while let Some(grapheme) = iter.peek().copied() {
19508                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19509                        break;
19510                    };
19511                    if is_grapheme_whitespace(grapheme) != is_whitespace
19512                        || (grapheme == "\n") != is_newline
19513                    {
19514                        break;
19515                    };
19516                    offset += grapheme.len();
19517                    grapheme_len += 1;
19518                    iter.next();
19519                }
19520            }
19521            let token = &self.input[..offset];
19522            self.input = &self.input[offset..];
19523            if token == "\n" {
19524                Some(WordBreakToken::Newline)
19525            } else if is_whitespace {
19526                Some(WordBreakToken::InlineWhitespace {
19527                    token,
19528                    grapheme_len,
19529                })
19530            } else {
19531                Some(WordBreakToken::Word {
19532                    token,
19533                    grapheme_len,
19534                })
19535            }
19536        } else {
19537            None
19538        }
19539    }
19540}
19541
19542#[test]
19543fn test_word_breaking_tokenizer() {
19544    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19545        ("", &[]),
19546        ("  ", &[whitespace("  ", 2)]),
19547        ("Ʒ", &[word("Ʒ", 1)]),
19548        ("Ǽ", &[word("Ǽ", 1)]),
19549        ("", &[word("", 1)]),
19550        ("⋑⋑", &[word("⋑⋑", 2)]),
19551        (
19552            "原理,进而",
19553            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19554        ),
19555        (
19556            "hello world",
19557            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19558        ),
19559        (
19560            "hello, world",
19561            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19562        ),
19563        (
19564            "  hello world",
19565            &[
19566                whitespace("  ", 2),
19567                word("hello", 5),
19568                whitespace(" ", 1),
19569                word("world", 5),
19570            ],
19571        ),
19572        (
19573            "这是什么 \n 钢笔",
19574            &[
19575                word("", 1),
19576                word("", 1),
19577                word("", 1),
19578                word("", 1),
19579                whitespace(" ", 1),
19580                newline(),
19581                whitespace(" ", 1),
19582                word("", 1),
19583                word("", 1),
19584            ],
19585        ),
19586        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19587    ];
19588
19589    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19590        WordBreakToken::Word {
19591            token,
19592            grapheme_len,
19593        }
19594    }
19595
19596    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19597        WordBreakToken::InlineWhitespace {
19598            token,
19599            grapheme_len,
19600        }
19601    }
19602
19603    fn newline() -> WordBreakToken<'static> {
19604        WordBreakToken::Newline
19605    }
19606
19607    for (input, result) in tests {
19608        assert_eq!(
19609            WordBreakingTokenizer::new(input)
19610                .collect::<Vec<_>>()
19611                .as_slice(),
19612            *result,
19613        );
19614    }
19615}
19616
19617fn wrap_with_prefix(
19618    line_prefix: String,
19619    unwrapped_text: String,
19620    wrap_column: usize,
19621    tab_size: NonZeroU32,
19622    preserve_existing_whitespace: bool,
19623) -> String {
19624    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19625    let mut wrapped_text = String::new();
19626    let mut current_line = line_prefix.clone();
19627
19628    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19629    let mut current_line_len = line_prefix_len;
19630    let mut in_whitespace = false;
19631    for token in tokenizer {
19632        let have_preceding_whitespace = in_whitespace;
19633        match token {
19634            WordBreakToken::Word {
19635                token,
19636                grapheme_len,
19637            } => {
19638                in_whitespace = false;
19639                if current_line_len + grapheme_len > wrap_column
19640                    && current_line_len != line_prefix_len
19641                {
19642                    wrapped_text.push_str(current_line.trim_end());
19643                    wrapped_text.push('\n');
19644                    current_line.truncate(line_prefix.len());
19645                    current_line_len = line_prefix_len;
19646                }
19647                current_line.push_str(token);
19648                current_line_len += grapheme_len;
19649            }
19650            WordBreakToken::InlineWhitespace {
19651                mut token,
19652                mut grapheme_len,
19653            } => {
19654                in_whitespace = true;
19655                if have_preceding_whitespace && !preserve_existing_whitespace {
19656                    continue;
19657                }
19658                if !preserve_existing_whitespace {
19659                    token = " ";
19660                    grapheme_len = 1;
19661                }
19662                if current_line_len + grapheme_len > wrap_column {
19663                    wrapped_text.push_str(current_line.trim_end());
19664                    wrapped_text.push('\n');
19665                    current_line.truncate(line_prefix.len());
19666                    current_line_len = line_prefix_len;
19667                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19668                    current_line.push_str(token);
19669                    current_line_len += grapheme_len;
19670                }
19671            }
19672            WordBreakToken::Newline => {
19673                in_whitespace = true;
19674                if preserve_existing_whitespace {
19675                    wrapped_text.push_str(current_line.trim_end());
19676                    wrapped_text.push('\n');
19677                    current_line.truncate(line_prefix.len());
19678                    current_line_len = line_prefix_len;
19679                } else if have_preceding_whitespace {
19680                    continue;
19681                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19682                {
19683                    wrapped_text.push_str(current_line.trim_end());
19684                    wrapped_text.push('\n');
19685                    current_line.truncate(line_prefix.len());
19686                    current_line_len = line_prefix_len;
19687                } else if current_line_len != line_prefix_len {
19688                    current_line.push(' ');
19689                    current_line_len += 1;
19690                }
19691            }
19692        }
19693    }
19694
19695    if !current_line.is_empty() {
19696        wrapped_text.push_str(&current_line);
19697    }
19698    wrapped_text
19699}
19700
19701#[test]
19702fn test_wrap_with_prefix() {
19703    assert_eq!(
19704        wrap_with_prefix(
19705            "# ".to_string(),
19706            "abcdefg".to_string(),
19707            4,
19708            NonZeroU32::new(4).unwrap(),
19709            false,
19710        ),
19711        "# abcdefg"
19712    );
19713    assert_eq!(
19714        wrap_with_prefix(
19715            "".to_string(),
19716            "\thello world".to_string(),
19717            8,
19718            NonZeroU32::new(4).unwrap(),
19719            false,
19720        ),
19721        "hello\nworld"
19722    );
19723    assert_eq!(
19724        wrap_with_prefix(
19725            "// ".to_string(),
19726            "xx \nyy zz aa bb cc".to_string(),
19727            12,
19728            NonZeroU32::new(4).unwrap(),
19729            false,
19730        ),
19731        "// xx yy zz\n// aa bb cc"
19732    );
19733    assert_eq!(
19734        wrap_with_prefix(
19735            String::new(),
19736            "这是什么 \n 钢笔".to_string(),
19737            3,
19738            NonZeroU32::new(4).unwrap(),
19739            false,
19740        ),
19741        "这是什\n么 钢\n"
19742    );
19743}
19744
19745pub trait CollaborationHub {
19746    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19747    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19748    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19749}
19750
19751impl CollaborationHub for Entity<Project> {
19752    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19753        self.read(cx).collaborators()
19754    }
19755
19756    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19757        self.read(cx).user_store().read(cx).participant_indices()
19758    }
19759
19760    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19761        let this = self.read(cx);
19762        let user_ids = this.collaborators().values().map(|c| c.user_id);
19763        this.user_store().read_with(cx, |user_store, cx| {
19764            user_store.participant_names(user_ids, cx)
19765        })
19766    }
19767}
19768
19769pub trait SemanticsProvider {
19770    fn hover(
19771        &self,
19772        buffer: &Entity<Buffer>,
19773        position: text::Anchor,
19774        cx: &mut App,
19775    ) -> Option<Task<Vec<project::Hover>>>;
19776
19777    fn inline_values(
19778        &self,
19779        buffer_handle: Entity<Buffer>,
19780        range: Range<text::Anchor>,
19781        cx: &mut App,
19782    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19783
19784    fn inlay_hints(
19785        &self,
19786        buffer_handle: Entity<Buffer>,
19787        range: Range<text::Anchor>,
19788        cx: &mut App,
19789    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19790
19791    fn resolve_inlay_hint(
19792        &self,
19793        hint: InlayHint,
19794        buffer_handle: Entity<Buffer>,
19795        server_id: LanguageServerId,
19796        cx: &mut App,
19797    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19798
19799    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19800
19801    fn document_highlights(
19802        &self,
19803        buffer: &Entity<Buffer>,
19804        position: text::Anchor,
19805        cx: &mut App,
19806    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19807
19808    fn definitions(
19809        &self,
19810        buffer: &Entity<Buffer>,
19811        position: text::Anchor,
19812        kind: GotoDefinitionKind,
19813        cx: &mut App,
19814    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19815
19816    fn range_for_rename(
19817        &self,
19818        buffer: &Entity<Buffer>,
19819        position: text::Anchor,
19820        cx: &mut App,
19821    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19822
19823    fn perform_rename(
19824        &self,
19825        buffer: &Entity<Buffer>,
19826        position: text::Anchor,
19827        new_name: String,
19828        cx: &mut App,
19829    ) -> Option<Task<Result<ProjectTransaction>>>;
19830}
19831
19832pub trait CompletionProvider {
19833    fn completions(
19834        &self,
19835        excerpt_id: ExcerptId,
19836        buffer: &Entity<Buffer>,
19837        buffer_position: text::Anchor,
19838        trigger: CompletionContext,
19839        window: &mut Window,
19840        cx: &mut Context<Editor>,
19841    ) -> Task<Result<Option<Vec<Completion>>>>;
19842
19843    fn resolve_completions(
19844        &self,
19845        buffer: Entity<Buffer>,
19846        completion_indices: Vec<usize>,
19847        completions: Rc<RefCell<Box<[Completion]>>>,
19848        cx: &mut Context<Editor>,
19849    ) -> Task<Result<bool>>;
19850
19851    fn apply_additional_edits_for_completion(
19852        &self,
19853        _buffer: Entity<Buffer>,
19854        _completions: Rc<RefCell<Box<[Completion]>>>,
19855        _completion_index: usize,
19856        _push_to_history: bool,
19857        _cx: &mut Context<Editor>,
19858    ) -> Task<Result<Option<language::Transaction>>> {
19859        Task::ready(Ok(None))
19860    }
19861
19862    fn is_completion_trigger(
19863        &self,
19864        buffer: &Entity<Buffer>,
19865        position: language::Anchor,
19866        text: &str,
19867        trigger_in_words: bool,
19868        cx: &mut Context<Editor>,
19869    ) -> bool;
19870
19871    fn sort_completions(&self) -> bool {
19872        true
19873    }
19874
19875    fn filter_completions(&self) -> bool {
19876        true
19877    }
19878}
19879
19880pub trait CodeActionProvider {
19881    fn id(&self) -> Arc<str>;
19882
19883    fn code_actions(
19884        &self,
19885        buffer: &Entity<Buffer>,
19886        range: Range<text::Anchor>,
19887        window: &mut Window,
19888        cx: &mut App,
19889    ) -> Task<Result<Vec<CodeAction>>>;
19890
19891    fn apply_code_action(
19892        &self,
19893        buffer_handle: Entity<Buffer>,
19894        action: CodeAction,
19895        excerpt_id: ExcerptId,
19896        push_to_history: bool,
19897        window: &mut Window,
19898        cx: &mut App,
19899    ) -> Task<Result<ProjectTransaction>>;
19900}
19901
19902impl CodeActionProvider for Entity<Project> {
19903    fn id(&self) -> Arc<str> {
19904        "project".into()
19905    }
19906
19907    fn code_actions(
19908        &self,
19909        buffer: &Entity<Buffer>,
19910        range: Range<text::Anchor>,
19911        _window: &mut Window,
19912        cx: &mut App,
19913    ) -> Task<Result<Vec<CodeAction>>> {
19914        self.update(cx, |project, cx| {
19915            let code_lens = project.code_lens(buffer, range.clone(), cx);
19916            let code_actions = project.code_actions(buffer, range, None, cx);
19917            cx.background_spawn(async move {
19918                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19919                Ok(code_lens
19920                    .context("code lens fetch")?
19921                    .into_iter()
19922                    .chain(code_actions.context("code action fetch")?)
19923                    .collect())
19924            })
19925        })
19926    }
19927
19928    fn apply_code_action(
19929        &self,
19930        buffer_handle: Entity<Buffer>,
19931        action: CodeAction,
19932        _excerpt_id: ExcerptId,
19933        push_to_history: bool,
19934        _window: &mut Window,
19935        cx: &mut App,
19936    ) -> Task<Result<ProjectTransaction>> {
19937        self.update(cx, |project, cx| {
19938            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19939        })
19940    }
19941}
19942
19943fn snippet_completions(
19944    project: &Project,
19945    buffer: &Entity<Buffer>,
19946    buffer_position: text::Anchor,
19947    cx: &mut App,
19948) -> Task<Result<Vec<Completion>>> {
19949    let languages = buffer.read(cx).languages_at(buffer_position);
19950    let snippet_store = project.snippets().read(cx);
19951
19952    let scopes: Vec<_> = languages
19953        .iter()
19954        .filter_map(|language| {
19955            let language_name = language.lsp_id();
19956            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19957
19958            if snippets.is_empty() {
19959                None
19960            } else {
19961                Some((language.default_scope(), snippets))
19962            }
19963        })
19964        .collect();
19965
19966    if scopes.is_empty() {
19967        return Task::ready(Ok(vec![]));
19968    }
19969
19970    let snapshot = buffer.read(cx).text_snapshot();
19971    let chars: String = snapshot
19972        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19973        .collect();
19974    let executor = cx.background_executor().clone();
19975
19976    cx.background_spawn(async move {
19977        let mut all_results: Vec<Completion> = Vec::new();
19978        for (scope, snippets) in scopes.into_iter() {
19979            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19980            let mut last_word = chars
19981                .chars()
19982                .take_while(|c| classifier.is_word(*c))
19983                .collect::<String>();
19984            last_word = last_word.chars().rev().collect();
19985
19986            if last_word.is_empty() {
19987                return Ok(vec![]);
19988            }
19989
19990            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19991            let to_lsp = |point: &text::Anchor| {
19992                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19993                point_to_lsp(end)
19994            };
19995            let lsp_end = to_lsp(&buffer_position);
19996
19997            let candidates = snippets
19998                .iter()
19999                .enumerate()
20000                .flat_map(|(ix, snippet)| {
20001                    snippet
20002                        .prefix
20003                        .iter()
20004                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20005                })
20006                .collect::<Vec<StringMatchCandidate>>();
20007
20008            let mut matches = fuzzy::match_strings(
20009                &candidates,
20010                &last_word,
20011                last_word.chars().any(|c| c.is_uppercase()),
20012                100,
20013                &Default::default(),
20014                executor.clone(),
20015            )
20016            .await;
20017
20018            // Remove all candidates where the query's start does not match the start of any word in the candidate
20019            if let Some(query_start) = last_word.chars().next() {
20020                matches.retain(|string_match| {
20021                    split_words(&string_match.string).any(|word| {
20022                        // Check that the first codepoint of the word as lowercase matches the first
20023                        // codepoint of the query as lowercase
20024                        word.chars()
20025                            .flat_map(|codepoint| codepoint.to_lowercase())
20026                            .zip(query_start.to_lowercase())
20027                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20028                    })
20029                });
20030            }
20031
20032            let matched_strings = matches
20033                .into_iter()
20034                .map(|m| m.string)
20035                .collect::<HashSet<_>>();
20036
20037            let mut result: Vec<Completion> = snippets
20038                .iter()
20039                .filter_map(|snippet| {
20040                    let matching_prefix = snippet
20041                        .prefix
20042                        .iter()
20043                        .find(|prefix| matched_strings.contains(*prefix))?;
20044                    let start = as_offset - last_word.len();
20045                    let start = snapshot.anchor_before(start);
20046                    let range = start..buffer_position;
20047                    let lsp_start = to_lsp(&start);
20048                    let lsp_range = lsp::Range {
20049                        start: lsp_start,
20050                        end: lsp_end,
20051                    };
20052                    Some(Completion {
20053                        replace_range: range,
20054                        new_text: snippet.body.clone(),
20055                        source: CompletionSource::Lsp {
20056                            insert_range: None,
20057                            server_id: LanguageServerId(usize::MAX),
20058                            resolved: true,
20059                            lsp_completion: Box::new(lsp::CompletionItem {
20060                                label: snippet.prefix.first().unwrap().clone(),
20061                                kind: Some(CompletionItemKind::SNIPPET),
20062                                label_details: snippet.description.as_ref().map(|description| {
20063                                    lsp::CompletionItemLabelDetails {
20064                                        detail: Some(description.clone()),
20065                                        description: None,
20066                                    }
20067                                }),
20068                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20069                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20070                                    lsp::InsertReplaceEdit {
20071                                        new_text: snippet.body.clone(),
20072                                        insert: lsp_range,
20073                                        replace: lsp_range,
20074                                    },
20075                                )),
20076                                filter_text: Some(snippet.body.clone()),
20077                                sort_text: Some(char::MAX.to_string()),
20078                                ..lsp::CompletionItem::default()
20079                            }),
20080                            lsp_defaults: None,
20081                        },
20082                        label: CodeLabel {
20083                            text: matching_prefix.clone(),
20084                            runs: Vec::new(),
20085                            filter_range: 0..matching_prefix.len(),
20086                        },
20087                        icon_path: None,
20088                        documentation: Some(
20089                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20090                                single_line: snippet.name.clone().into(),
20091                                plain_text: snippet
20092                                    .description
20093                                    .clone()
20094                                    .map(|description| description.into()),
20095                            },
20096                        ),
20097                        insert_text_mode: None,
20098                        confirm: None,
20099                    })
20100                })
20101                .collect();
20102
20103            all_results.append(&mut result);
20104        }
20105
20106        Ok(all_results)
20107    })
20108}
20109
20110impl CompletionProvider for Entity<Project> {
20111    fn completions(
20112        &self,
20113        _excerpt_id: ExcerptId,
20114        buffer: &Entity<Buffer>,
20115        buffer_position: text::Anchor,
20116        options: CompletionContext,
20117        _window: &mut Window,
20118        cx: &mut Context<Editor>,
20119    ) -> Task<Result<Option<Vec<Completion>>>> {
20120        self.update(cx, |project, cx| {
20121            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20122            let project_completions = project.completions(buffer, buffer_position, options, cx);
20123            cx.background_spawn(async move {
20124                let snippets_completions = snippets.await?;
20125                match project_completions.await? {
20126                    Some(mut completions) => {
20127                        completions.extend(snippets_completions);
20128                        Ok(Some(completions))
20129                    }
20130                    None => {
20131                        if snippets_completions.is_empty() {
20132                            Ok(None)
20133                        } else {
20134                            Ok(Some(snippets_completions))
20135                        }
20136                    }
20137                }
20138            })
20139        })
20140    }
20141
20142    fn resolve_completions(
20143        &self,
20144        buffer: Entity<Buffer>,
20145        completion_indices: Vec<usize>,
20146        completions: Rc<RefCell<Box<[Completion]>>>,
20147        cx: &mut Context<Editor>,
20148    ) -> Task<Result<bool>> {
20149        self.update(cx, |project, cx| {
20150            project.lsp_store().update(cx, |lsp_store, cx| {
20151                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20152            })
20153        })
20154    }
20155
20156    fn apply_additional_edits_for_completion(
20157        &self,
20158        buffer: Entity<Buffer>,
20159        completions: Rc<RefCell<Box<[Completion]>>>,
20160        completion_index: usize,
20161        push_to_history: bool,
20162        cx: &mut Context<Editor>,
20163    ) -> Task<Result<Option<language::Transaction>>> {
20164        self.update(cx, |project, cx| {
20165            project.lsp_store().update(cx, |lsp_store, cx| {
20166                lsp_store.apply_additional_edits_for_completion(
20167                    buffer,
20168                    completions,
20169                    completion_index,
20170                    push_to_history,
20171                    cx,
20172                )
20173            })
20174        })
20175    }
20176
20177    fn is_completion_trigger(
20178        &self,
20179        buffer: &Entity<Buffer>,
20180        position: language::Anchor,
20181        text: &str,
20182        trigger_in_words: bool,
20183        cx: &mut Context<Editor>,
20184    ) -> bool {
20185        let mut chars = text.chars();
20186        let char = if let Some(char) = chars.next() {
20187            char
20188        } else {
20189            return false;
20190        };
20191        if chars.next().is_some() {
20192            return false;
20193        }
20194
20195        let buffer = buffer.read(cx);
20196        let snapshot = buffer.snapshot();
20197        if !snapshot.settings_at(position, cx).show_completions_on_input {
20198            return false;
20199        }
20200        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20201        if trigger_in_words && classifier.is_word(char) {
20202            return true;
20203        }
20204
20205        buffer.completion_triggers().contains(text)
20206    }
20207}
20208
20209impl SemanticsProvider for Entity<Project> {
20210    fn hover(
20211        &self,
20212        buffer: &Entity<Buffer>,
20213        position: text::Anchor,
20214        cx: &mut App,
20215    ) -> Option<Task<Vec<project::Hover>>> {
20216        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20217    }
20218
20219    fn document_highlights(
20220        &self,
20221        buffer: &Entity<Buffer>,
20222        position: text::Anchor,
20223        cx: &mut App,
20224    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20225        Some(self.update(cx, |project, cx| {
20226            project.document_highlights(buffer, position, cx)
20227        }))
20228    }
20229
20230    fn definitions(
20231        &self,
20232        buffer: &Entity<Buffer>,
20233        position: text::Anchor,
20234        kind: GotoDefinitionKind,
20235        cx: &mut App,
20236    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20237        Some(self.update(cx, |project, cx| match kind {
20238            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20239            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20240            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20241            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20242        }))
20243    }
20244
20245    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20246        // TODO: make this work for remote projects
20247        self.update(cx, |project, cx| {
20248            if project
20249                .active_debug_session(cx)
20250                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20251            {
20252                return true;
20253            }
20254
20255            buffer.update(cx, |buffer, cx| {
20256                project.any_language_server_supports_inlay_hints(buffer, cx)
20257            })
20258        })
20259    }
20260
20261    fn inline_values(
20262        &self,
20263        buffer_handle: Entity<Buffer>,
20264
20265        range: Range<text::Anchor>,
20266        cx: &mut App,
20267    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20268        self.update(cx, |project, cx| {
20269            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20270
20271            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20272        })
20273    }
20274
20275    fn inlay_hints(
20276        &self,
20277        buffer_handle: Entity<Buffer>,
20278        range: Range<text::Anchor>,
20279        cx: &mut App,
20280    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20281        Some(self.update(cx, |project, cx| {
20282            project.inlay_hints(buffer_handle, range, cx)
20283        }))
20284    }
20285
20286    fn resolve_inlay_hint(
20287        &self,
20288        hint: InlayHint,
20289        buffer_handle: Entity<Buffer>,
20290        server_id: LanguageServerId,
20291        cx: &mut App,
20292    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20293        Some(self.update(cx, |project, cx| {
20294            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20295        }))
20296    }
20297
20298    fn range_for_rename(
20299        &self,
20300        buffer: &Entity<Buffer>,
20301        position: text::Anchor,
20302        cx: &mut App,
20303    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20304        Some(self.update(cx, |project, cx| {
20305            let buffer = buffer.clone();
20306            let task = project.prepare_rename(buffer.clone(), position, cx);
20307            cx.spawn(async move |_, cx| {
20308                Ok(match task.await? {
20309                    PrepareRenameResponse::Success(range) => Some(range),
20310                    PrepareRenameResponse::InvalidPosition => None,
20311                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20312                        // Fallback on using TreeSitter info to determine identifier range
20313                        buffer.update(cx, |buffer, _| {
20314                            let snapshot = buffer.snapshot();
20315                            let (range, kind) = snapshot.surrounding_word(position);
20316                            if kind != Some(CharKind::Word) {
20317                                return None;
20318                            }
20319                            Some(
20320                                snapshot.anchor_before(range.start)
20321                                    ..snapshot.anchor_after(range.end),
20322                            )
20323                        })?
20324                    }
20325                })
20326            })
20327        }))
20328    }
20329
20330    fn perform_rename(
20331        &self,
20332        buffer: &Entity<Buffer>,
20333        position: text::Anchor,
20334        new_name: String,
20335        cx: &mut App,
20336    ) -> Option<Task<Result<ProjectTransaction>>> {
20337        Some(self.update(cx, |project, cx| {
20338            project.perform_rename(buffer.clone(), position, new_name, cx)
20339        }))
20340    }
20341}
20342
20343fn inlay_hint_settings(
20344    location: Anchor,
20345    snapshot: &MultiBufferSnapshot,
20346    cx: &mut Context<Editor>,
20347) -> InlayHintSettings {
20348    let file = snapshot.file_at(location);
20349    let language = snapshot.language_at(location).map(|l| l.name());
20350    language_settings(language, file, cx).inlay_hints
20351}
20352
20353fn consume_contiguous_rows(
20354    contiguous_row_selections: &mut Vec<Selection<Point>>,
20355    selection: &Selection<Point>,
20356    display_map: &DisplaySnapshot,
20357    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20358) -> (MultiBufferRow, MultiBufferRow) {
20359    contiguous_row_selections.push(selection.clone());
20360    let start_row = MultiBufferRow(selection.start.row);
20361    let mut end_row = ending_row(selection, display_map);
20362
20363    while let Some(next_selection) = selections.peek() {
20364        if next_selection.start.row <= end_row.0 {
20365            end_row = ending_row(next_selection, display_map);
20366            contiguous_row_selections.push(selections.next().unwrap().clone());
20367        } else {
20368            break;
20369        }
20370    }
20371    (start_row, end_row)
20372}
20373
20374fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20375    if next_selection.end.column > 0 || next_selection.is_empty() {
20376        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20377    } else {
20378        MultiBufferRow(next_selection.end.row)
20379    }
20380}
20381
20382impl EditorSnapshot {
20383    pub fn remote_selections_in_range<'a>(
20384        &'a self,
20385        range: &'a Range<Anchor>,
20386        collaboration_hub: &dyn CollaborationHub,
20387        cx: &'a App,
20388    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20389        let participant_names = collaboration_hub.user_names(cx);
20390        let participant_indices = collaboration_hub.user_participant_indices(cx);
20391        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20392        let collaborators_by_replica_id = collaborators_by_peer_id
20393            .values()
20394            .map(|collaborator| (collaborator.replica_id, collaborator))
20395            .collect::<HashMap<_, _>>();
20396        self.buffer_snapshot
20397            .selections_in_range(range, false)
20398            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20399                if replica_id == AGENT_REPLICA_ID {
20400                    Some(RemoteSelection {
20401                        replica_id,
20402                        selection,
20403                        cursor_shape,
20404                        line_mode,
20405                        collaborator_id: CollaboratorId::Agent,
20406                        user_name: Some("Agent".into()),
20407                        color: cx.theme().players().agent(),
20408                    })
20409                } else {
20410                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20411                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20412                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20413                    Some(RemoteSelection {
20414                        replica_id,
20415                        selection,
20416                        cursor_shape,
20417                        line_mode,
20418                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20419                        user_name,
20420                        color: if let Some(index) = participant_index {
20421                            cx.theme().players().color_for_participant(index.0)
20422                        } else {
20423                            cx.theme().players().absent()
20424                        },
20425                    })
20426                }
20427            })
20428    }
20429
20430    pub fn hunks_for_ranges(
20431        &self,
20432        ranges: impl IntoIterator<Item = Range<Point>>,
20433    ) -> Vec<MultiBufferDiffHunk> {
20434        let mut hunks = Vec::new();
20435        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20436            HashMap::default();
20437        for query_range in ranges {
20438            let query_rows =
20439                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20440            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20441                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20442            ) {
20443                // Include deleted hunks that are adjacent to the query range, because
20444                // otherwise they would be missed.
20445                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20446                if hunk.status().is_deleted() {
20447                    intersects_range |= hunk.row_range.start == query_rows.end;
20448                    intersects_range |= hunk.row_range.end == query_rows.start;
20449                }
20450                if intersects_range {
20451                    if !processed_buffer_rows
20452                        .entry(hunk.buffer_id)
20453                        .or_default()
20454                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20455                    {
20456                        continue;
20457                    }
20458                    hunks.push(hunk);
20459                }
20460            }
20461        }
20462
20463        hunks
20464    }
20465
20466    fn display_diff_hunks_for_rows<'a>(
20467        &'a self,
20468        display_rows: Range<DisplayRow>,
20469        folded_buffers: &'a HashSet<BufferId>,
20470    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20471        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20472        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20473
20474        self.buffer_snapshot
20475            .diff_hunks_in_range(buffer_start..buffer_end)
20476            .filter_map(|hunk| {
20477                if folded_buffers.contains(&hunk.buffer_id) {
20478                    return None;
20479                }
20480
20481                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20482                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20483
20484                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20485                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20486
20487                let display_hunk = if hunk_display_start.column() != 0 {
20488                    DisplayDiffHunk::Folded {
20489                        display_row: hunk_display_start.row(),
20490                    }
20491                } else {
20492                    let mut end_row = hunk_display_end.row();
20493                    if hunk_display_end.column() > 0 {
20494                        end_row.0 += 1;
20495                    }
20496                    let is_created_file = hunk.is_created_file();
20497                    DisplayDiffHunk::Unfolded {
20498                        status: hunk.status(),
20499                        diff_base_byte_range: hunk.diff_base_byte_range,
20500                        display_row_range: hunk_display_start.row()..end_row,
20501                        multi_buffer_range: Anchor::range_in_buffer(
20502                            hunk.excerpt_id,
20503                            hunk.buffer_id,
20504                            hunk.buffer_range,
20505                        ),
20506                        is_created_file,
20507                    }
20508                };
20509
20510                Some(display_hunk)
20511            })
20512    }
20513
20514    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20515        self.display_snapshot.buffer_snapshot.language_at(position)
20516    }
20517
20518    pub fn is_focused(&self) -> bool {
20519        self.is_focused
20520    }
20521
20522    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20523        self.placeholder_text.as_ref()
20524    }
20525
20526    pub fn scroll_position(&self) -> gpui::Point<f32> {
20527        self.scroll_anchor.scroll_position(&self.display_snapshot)
20528    }
20529
20530    fn gutter_dimensions(
20531        &self,
20532        font_id: FontId,
20533        font_size: Pixels,
20534        max_line_number_width: Pixels,
20535        cx: &App,
20536    ) -> Option<GutterDimensions> {
20537        if !self.show_gutter {
20538            return None;
20539        }
20540
20541        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20542        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20543
20544        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20545            matches!(
20546                ProjectSettings::get_global(cx).git.git_gutter,
20547                Some(GitGutterSetting::TrackedFiles)
20548            )
20549        });
20550        let gutter_settings = EditorSettings::get_global(cx).gutter;
20551        let show_line_numbers = self
20552            .show_line_numbers
20553            .unwrap_or(gutter_settings.line_numbers);
20554        let line_gutter_width = if show_line_numbers {
20555            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20556            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20557            max_line_number_width.max(min_width_for_number_on_gutter)
20558        } else {
20559            0.0.into()
20560        };
20561
20562        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20563        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20564
20565        let git_blame_entries_width =
20566            self.git_blame_gutter_max_author_length
20567                .map(|max_author_length| {
20568                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20569                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20570
20571                    /// The number of characters to dedicate to gaps and margins.
20572                    const SPACING_WIDTH: usize = 4;
20573
20574                    let max_char_count = max_author_length.min(renderer.max_author_length())
20575                        + ::git::SHORT_SHA_LENGTH
20576                        + MAX_RELATIVE_TIMESTAMP.len()
20577                        + SPACING_WIDTH;
20578
20579                    em_advance * max_char_count
20580                });
20581
20582        let is_singleton = self.buffer_snapshot.is_singleton();
20583
20584        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20585        left_padding += if !is_singleton {
20586            em_width * 4.0
20587        } else if show_runnables || show_breakpoints {
20588            em_width * 3.0
20589        } else if show_git_gutter && show_line_numbers {
20590            em_width * 2.0
20591        } else if show_git_gutter || show_line_numbers {
20592            em_width
20593        } else {
20594            px(0.)
20595        };
20596
20597        let shows_folds = is_singleton && gutter_settings.folds;
20598
20599        let right_padding = if shows_folds && show_line_numbers {
20600            em_width * 4.0
20601        } else if shows_folds || (!is_singleton && show_line_numbers) {
20602            em_width * 3.0
20603        } else if show_line_numbers {
20604            em_width
20605        } else {
20606            px(0.)
20607        };
20608
20609        Some(GutterDimensions {
20610            left_padding,
20611            right_padding,
20612            width: line_gutter_width + left_padding + right_padding,
20613            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20614            git_blame_entries_width,
20615        })
20616    }
20617
20618    pub fn render_crease_toggle(
20619        &self,
20620        buffer_row: MultiBufferRow,
20621        row_contains_cursor: bool,
20622        editor: Entity<Editor>,
20623        window: &mut Window,
20624        cx: &mut App,
20625    ) -> Option<AnyElement> {
20626        let folded = self.is_line_folded(buffer_row);
20627        let mut is_foldable = false;
20628
20629        if let Some(crease) = self
20630            .crease_snapshot
20631            .query_row(buffer_row, &self.buffer_snapshot)
20632        {
20633            is_foldable = true;
20634            match crease {
20635                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20636                    if let Some(render_toggle) = render_toggle {
20637                        let toggle_callback =
20638                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20639                                if folded {
20640                                    editor.update(cx, |editor, cx| {
20641                                        editor.fold_at(buffer_row, window, cx)
20642                                    });
20643                                } else {
20644                                    editor.update(cx, |editor, cx| {
20645                                        editor.unfold_at(buffer_row, window, cx)
20646                                    });
20647                                }
20648                            });
20649                        return Some((render_toggle)(
20650                            buffer_row,
20651                            folded,
20652                            toggle_callback,
20653                            window,
20654                            cx,
20655                        ));
20656                    }
20657                }
20658            }
20659        }
20660
20661        is_foldable |= self.starts_indent(buffer_row);
20662
20663        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20664            Some(
20665                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20666                    .toggle_state(folded)
20667                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20668                        if folded {
20669                            this.unfold_at(buffer_row, window, cx);
20670                        } else {
20671                            this.fold_at(buffer_row, window, cx);
20672                        }
20673                    }))
20674                    .into_any_element(),
20675            )
20676        } else {
20677            None
20678        }
20679    }
20680
20681    pub fn render_crease_trailer(
20682        &self,
20683        buffer_row: MultiBufferRow,
20684        window: &mut Window,
20685        cx: &mut App,
20686    ) -> Option<AnyElement> {
20687        let folded = self.is_line_folded(buffer_row);
20688        if let Crease::Inline { render_trailer, .. } = self
20689            .crease_snapshot
20690            .query_row(buffer_row, &self.buffer_snapshot)?
20691        {
20692            let render_trailer = render_trailer.as_ref()?;
20693            Some(render_trailer(buffer_row, folded, window, cx))
20694        } else {
20695            None
20696        }
20697    }
20698}
20699
20700impl Deref for EditorSnapshot {
20701    type Target = DisplaySnapshot;
20702
20703    fn deref(&self) -> &Self::Target {
20704        &self.display_snapshot
20705    }
20706}
20707
20708#[derive(Clone, Debug, PartialEq, Eq)]
20709pub enum EditorEvent {
20710    InputIgnored {
20711        text: Arc<str>,
20712    },
20713    InputHandled {
20714        utf16_range_to_replace: Option<Range<isize>>,
20715        text: Arc<str>,
20716    },
20717    ExcerptsAdded {
20718        buffer: Entity<Buffer>,
20719        predecessor: ExcerptId,
20720        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20721    },
20722    ExcerptsRemoved {
20723        ids: Vec<ExcerptId>,
20724        removed_buffer_ids: Vec<BufferId>,
20725    },
20726    BufferFoldToggled {
20727        ids: Vec<ExcerptId>,
20728        folded: bool,
20729    },
20730    ExcerptsEdited {
20731        ids: Vec<ExcerptId>,
20732    },
20733    ExcerptsExpanded {
20734        ids: Vec<ExcerptId>,
20735    },
20736    BufferEdited,
20737    Edited {
20738        transaction_id: clock::Lamport,
20739    },
20740    Reparsed(BufferId),
20741    Focused,
20742    FocusedIn,
20743    Blurred,
20744    DirtyChanged,
20745    Saved,
20746    TitleChanged,
20747    DiffBaseChanged,
20748    SelectionsChanged {
20749        local: bool,
20750    },
20751    ScrollPositionChanged {
20752        local: bool,
20753        autoscroll: bool,
20754    },
20755    Closed,
20756    TransactionUndone {
20757        transaction_id: clock::Lamport,
20758    },
20759    TransactionBegun {
20760        transaction_id: clock::Lamport,
20761    },
20762    Reloaded,
20763    CursorShapeChanged,
20764    PushedToNavHistory {
20765        anchor: Anchor,
20766        is_deactivate: bool,
20767    },
20768}
20769
20770impl EventEmitter<EditorEvent> for Editor {}
20771
20772impl Focusable for Editor {
20773    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20774        self.focus_handle.clone()
20775    }
20776}
20777
20778impl Render for Editor {
20779    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20780        let settings = ThemeSettings::get_global(cx);
20781
20782        let mut text_style = match self.mode {
20783            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20784                color: cx.theme().colors().editor_foreground,
20785                font_family: settings.ui_font.family.clone(),
20786                font_features: settings.ui_font.features.clone(),
20787                font_fallbacks: settings.ui_font.fallbacks.clone(),
20788                font_size: rems(0.875).into(),
20789                font_weight: settings.ui_font.weight,
20790                line_height: relative(settings.buffer_line_height.value()),
20791                ..Default::default()
20792            },
20793            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20794                color: cx.theme().colors().editor_foreground,
20795                font_family: settings.buffer_font.family.clone(),
20796                font_features: settings.buffer_font.features.clone(),
20797                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20798                font_size: settings.buffer_font_size(cx).into(),
20799                font_weight: settings.buffer_font.weight,
20800                line_height: relative(settings.buffer_line_height.value()),
20801                ..Default::default()
20802            },
20803        };
20804        if let Some(text_style_refinement) = &self.text_style_refinement {
20805            text_style.refine(text_style_refinement)
20806        }
20807
20808        let background = match self.mode {
20809            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20810            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20811            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20812            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20813        };
20814
20815        EditorElement::new(
20816            &cx.entity(),
20817            EditorStyle {
20818                background,
20819                local_player: cx.theme().players().local(),
20820                text: text_style,
20821                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20822                syntax: cx.theme().syntax().clone(),
20823                status: cx.theme().status().clone(),
20824                inlay_hints_style: make_inlay_hints_style(cx),
20825                inline_completion_styles: make_suggestion_styles(cx),
20826                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20827                show_underlines: !self.mode.is_minimap(),
20828            },
20829        )
20830    }
20831}
20832
20833impl EntityInputHandler for Editor {
20834    fn text_for_range(
20835        &mut self,
20836        range_utf16: Range<usize>,
20837        adjusted_range: &mut Option<Range<usize>>,
20838        _: &mut Window,
20839        cx: &mut Context<Self>,
20840    ) -> Option<String> {
20841        let snapshot = self.buffer.read(cx).read(cx);
20842        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20843        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20844        if (start.0..end.0) != range_utf16 {
20845            adjusted_range.replace(start.0..end.0);
20846        }
20847        Some(snapshot.text_for_range(start..end).collect())
20848    }
20849
20850    fn selected_text_range(
20851        &mut self,
20852        ignore_disabled_input: bool,
20853        _: &mut Window,
20854        cx: &mut Context<Self>,
20855    ) -> Option<UTF16Selection> {
20856        // Prevent the IME menu from appearing when holding down an alphabetic key
20857        // while input is disabled.
20858        if !ignore_disabled_input && !self.input_enabled {
20859            return None;
20860        }
20861
20862        let selection = self.selections.newest::<OffsetUtf16>(cx);
20863        let range = selection.range();
20864
20865        Some(UTF16Selection {
20866            range: range.start.0..range.end.0,
20867            reversed: selection.reversed,
20868        })
20869    }
20870
20871    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20872        let snapshot = self.buffer.read(cx).read(cx);
20873        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20874        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20875    }
20876
20877    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20878        self.clear_highlights::<InputComposition>(cx);
20879        self.ime_transaction.take();
20880    }
20881
20882    fn replace_text_in_range(
20883        &mut self,
20884        range_utf16: Option<Range<usize>>,
20885        text: &str,
20886        window: &mut Window,
20887        cx: &mut Context<Self>,
20888    ) {
20889        if !self.input_enabled {
20890            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20891            return;
20892        }
20893
20894        self.transact(window, cx, |this, window, cx| {
20895            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20896                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20897                Some(this.selection_replacement_ranges(range_utf16, cx))
20898            } else {
20899                this.marked_text_ranges(cx)
20900            };
20901
20902            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20903                let newest_selection_id = this.selections.newest_anchor().id;
20904                this.selections
20905                    .all::<OffsetUtf16>(cx)
20906                    .iter()
20907                    .zip(ranges_to_replace.iter())
20908                    .find_map(|(selection, range)| {
20909                        if selection.id == newest_selection_id {
20910                            Some(
20911                                (range.start.0 as isize - selection.head().0 as isize)
20912                                    ..(range.end.0 as isize - selection.head().0 as isize),
20913                            )
20914                        } else {
20915                            None
20916                        }
20917                    })
20918            });
20919
20920            cx.emit(EditorEvent::InputHandled {
20921                utf16_range_to_replace: range_to_replace,
20922                text: text.into(),
20923            });
20924
20925            if let Some(new_selected_ranges) = new_selected_ranges {
20926                this.change_selections(None, window, cx, |selections| {
20927                    selections.select_ranges(new_selected_ranges)
20928                });
20929                this.backspace(&Default::default(), window, cx);
20930            }
20931
20932            this.handle_input(text, window, cx);
20933        });
20934
20935        if let Some(transaction) = self.ime_transaction {
20936            self.buffer.update(cx, |buffer, cx| {
20937                buffer.group_until_transaction(transaction, cx);
20938            });
20939        }
20940
20941        self.unmark_text(window, cx);
20942    }
20943
20944    fn replace_and_mark_text_in_range(
20945        &mut self,
20946        range_utf16: Option<Range<usize>>,
20947        text: &str,
20948        new_selected_range_utf16: Option<Range<usize>>,
20949        window: &mut Window,
20950        cx: &mut Context<Self>,
20951    ) {
20952        if !self.input_enabled {
20953            return;
20954        }
20955
20956        let transaction = self.transact(window, cx, |this, window, cx| {
20957            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20958                let snapshot = this.buffer.read(cx).read(cx);
20959                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20960                    for marked_range in &mut marked_ranges {
20961                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20962                        marked_range.start.0 += relative_range_utf16.start;
20963                        marked_range.start =
20964                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20965                        marked_range.end =
20966                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20967                    }
20968                }
20969                Some(marked_ranges)
20970            } else if let Some(range_utf16) = range_utf16 {
20971                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20972                Some(this.selection_replacement_ranges(range_utf16, cx))
20973            } else {
20974                None
20975            };
20976
20977            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20978                let newest_selection_id = this.selections.newest_anchor().id;
20979                this.selections
20980                    .all::<OffsetUtf16>(cx)
20981                    .iter()
20982                    .zip(ranges_to_replace.iter())
20983                    .find_map(|(selection, range)| {
20984                        if selection.id == newest_selection_id {
20985                            Some(
20986                                (range.start.0 as isize - selection.head().0 as isize)
20987                                    ..(range.end.0 as isize - selection.head().0 as isize),
20988                            )
20989                        } else {
20990                            None
20991                        }
20992                    })
20993            });
20994
20995            cx.emit(EditorEvent::InputHandled {
20996                utf16_range_to_replace: range_to_replace,
20997                text: text.into(),
20998            });
20999
21000            if let Some(ranges) = ranges_to_replace {
21001                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21002            }
21003
21004            let marked_ranges = {
21005                let snapshot = this.buffer.read(cx).read(cx);
21006                this.selections
21007                    .disjoint_anchors()
21008                    .iter()
21009                    .map(|selection| {
21010                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21011                    })
21012                    .collect::<Vec<_>>()
21013            };
21014
21015            if text.is_empty() {
21016                this.unmark_text(window, cx);
21017            } else {
21018                this.highlight_text::<InputComposition>(
21019                    marked_ranges.clone(),
21020                    HighlightStyle {
21021                        underline: Some(UnderlineStyle {
21022                            thickness: px(1.),
21023                            color: None,
21024                            wavy: false,
21025                        }),
21026                        ..Default::default()
21027                    },
21028                    cx,
21029                );
21030            }
21031
21032            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21033            let use_autoclose = this.use_autoclose;
21034            let use_auto_surround = this.use_auto_surround;
21035            this.set_use_autoclose(false);
21036            this.set_use_auto_surround(false);
21037            this.handle_input(text, window, cx);
21038            this.set_use_autoclose(use_autoclose);
21039            this.set_use_auto_surround(use_auto_surround);
21040
21041            if let Some(new_selected_range) = new_selected_range_utf16 {
21042                let snapshot = this.buffer.read(cx).read(cx);
21043                let new_selected_ranges = marked_ranges
21044                    .into_iter()
21045                    .map(|marked_range| {
21046                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21047                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21048                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21049                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21050                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21051                    })
21052                    .collect::<Vec<_>>();
21053
21054                drop(snapshot);
21055                this.change_selections(None, window, cx, |selections| {
21056                    selections.select_ranges(new_selected_ranges)
21057                });
21058            }
21059        });
21060
21061        self.ime_transaction = self.ime_transaction.or(transaction);
21062        if let Some(transaction) = self.ime_transaction {
21063            self.buffer.update(cx, |buffer, cx| {
21064                buffer.group_until_transaction(transaction, cx);
21065            });
21066        }
21067
21068        if self.text_highlights::<InputComposition>(cx).is_none() {
21069            self.ime_transaction.take();
21070        }
21071    }
21072
21073    fn bounds_for_range(
21074        &mut self,
21075        range_utf16: Range<usize>,
21076        element_bounds: gpui::Bounds<Pixels>,
21077        window: &mut Window,
21078        cx: &mut Context<Self>,
21079    ) -> Option<gpui::Bounds<Pixels>> {
21080        let text_layout_details = self.text_layout_details(window);
21081        let gpui::Size {
21082            width: em_width,
21083            height: line_height,
21084        } = self.character_size(window);
21085
21086        let snapshot = self.snapshot(window, cx);
21087        let scroll_position = snapshot.scroll_position();
21088        let scroll_left = scroll_position.x * em_width;
21089
21090        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21091        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21092            + self.gutter_dimensions.width
21093            + self.gutter_dimensions.margin;
21094        let y = line_height * (start.row().as_f32() - scroll_position.y);
21095
21096        Some(Bounds {
21097            origin: element_bounds.origin + point(x, y),
21098            size: size(em_width, line_height),
21099        })
21100    }
21101
21102    fn character_index_for_point(
21103        &mut self,
21104        point: gpui::Point<Pixels>,
21105        _window: &mut Window,
21106        _cx: &mut Context<Self>,
21107    ) -> Option<usize> {
21108        let position_map = self.last_position_map.as_ref()?;
21109        if !position_map.text_hitbox.contains(&point) {
21110            return None;
21111        }
21112        let display_point = position_map.point_for_position(point).previous_valid;
21113        let anchor = position_map
21114            .snapshot
21115            .display_point_to_anchor(display_point, Bias::Left);
21116        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21117        Some(utf16_offset.0)
21118    }
21119}
21120
21121trait SelectionExt {
21122    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21123    fn spanned_rows(
21124        &self,
21125        include_end_if_at_line_start: bool,
21126        map: &DisplaySnapshot,
21127    ) -> Range<MultiBufferRow>;
21128}
21129
21130impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21131    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21132        let start = self
21133            .start
21134            .to_point(&map.buffer_snapshot)
21135            .to_display_point(map);
21136        let end = self
21137            .end
21138            .to_point(&map.buffer_snapshot)
21139            .to_display_point(map);
21140        if self.reversed {
21141            end..start
21142        } else {
21143            start..end
21144        }
21145    }
21146
21147    fn spanned_rows(
21148        &self,
21149        include_end_if_at_line_start: bool,
21150        map: &DisplaySnapshot,
21151    ) -> Range<MultiBufferRow> {
21152        let start = self.start.to_point(&map.buffer_snapshot);
21153        let mut end = self.end.to_point(&map.buffer_snapshot);
21154        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21155            end.row -= 1;
21156        }
21157
21158        let buffer_start = map.prev_line_boundary(start).0;
21159        let buffer_end = map.next_line_boundary(end).0;
21160        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21161    }
21162}
21163
21164impl<T: InvalidationRegion> InvalidationStack<T> {
21165    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21166    where
21167        S: Clone + ToOffset,
21168    {
21169        while let Some(region) = self.last() {
21170            let all_selections_inside_invalidation_ranges =
21171                if selections.len() == region.ranges().len() {
21172                    selections
21173                        .iter()
21174                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21175                        .all(|(selection, invalidation_range)| {
21176                            let head = selection.head().to_offset(buffer);
21177                            invalidation_range.start <= head && invalidation_range.end >= head
21178                        })
21179                } else {
21180                    false
21181                };
21182
21183            if all_selections_inside_invalidation_ranges {
21184                break;
21185            } else {
21186                self.pop();
21187            }
21188        }
21189    }
21190}
21191
21192impl<T> Default for InvalidationStack<T> {
21193    fn default() -> Self {
21194        Self(Default::default())
21195    }
21196}
21197
21198impl<T> Deref for InvalidationStack<T> {
21199    type Target = Vec<T>;
21200
21201    fn deref(&self) -> &Self::Target {
21202        &self.0
21203    }
21204}
21205
21206impl<T> DerefMut for InvalidationStack<T> {
21207    fn deref_mut(&mut self) -> &mut Self::Target {
21208        &mut self.0
21209    }
21210}
21211
21212impl InvalidationRegion for SnippetState {
21213    fn ranges(&self) -> &[Range<Anchor>] {
21214        &self.ranges[self.active_index]
21215    }
21216}
21217
21218fn inline_completion_edit_text(
21219    current_snapshot: &BufferSnapshot,
21220    edits: &[(Range<Anchor>, String)],
21221    edit_preview: &EditPreview,
21222    include_deletions: bool,
21223    cx: &App,
21224) -> HighlightedText {
21225    let edits = edits
21226        .iter()
21227        .map(|(anchor, text)| {
21228            (
21229                anchor.start.text_anchor..anchor.end.text_anchor,
21230                text.clone(),
21231            )
21232        })
21233        .collect::<Vec<_>>();
21234
21235    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21236}
21237
21238pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21239    match severity {
21240        lsp::DiagnosticSeverity::ERROR => colors.error,
21241        lsp::DiagnosticSeverity::WARNING => colors.warning,
21242        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21243        lsp::DiagnosticSeverity::HINT => colors.info,
21244        _ => colors.ignored,
21245    }
21246}
21247
21248pub fn styled_runs_for_code_label<'a>(
21249    label: &'a CodeLabel,
21250    syntax_theme: &'a theme::SyntaxTheme,
21251) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21252    let fade_out = HighlightStyle {
21253        fade_out: Some(0.35),
21254        ..Default::default()
21255    };
21256
21257    let mut prev_end = label.filter_range.end;
21258    label
21259        .runs
21260        .iter()
21261        .enumerate()
21262        .flat_map(move |(ix, (range, highlight_id))| {
21263            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21264                style
21265            } else {
21266                return Default::default();
21267            };
21268            let mut muted_style = style;
21269            muted_style.highlight(fade_out);
21270
21271            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21272            if range.start >= label.filter_range.end {
21273                if range.start > prev_end {
21274                    runs.push((prev_end..range.start, fade_out));
21275                }
21276                runs.push((range.clone(), muted_style));
21277            } else if range.end <= label.filter_range.end {
21278                runs.push((range.clone(), style));
21279            } else {
21280                runs.push((range.start..label.filter_range.end, style));
21281                runs.push((label.filter_range.end..range.end, muted_style));
21282            }
21283            prev_end = cmp::max(prev_end, range.end);
21284
21285            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21286                runs.push((prev_end..label.text.len(), fade_out));
21287            }
21288
21289            runs
21290        })
21291}
21292
21293pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21294    let mut prev_index = 0;
21295    let mut prev_codepoint: Option<char> = None;
21296    text.char_indices()
21297        .chain([(text.len(), '\0')])
21298        .filter_map(move |(index, codepoint)| {
21299            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21300            let is_boundary = index == text.len()
21301                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21302                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21303            if is_boundary {
21304                let chunk = &text[prev_index..index];
21305                prev_index = index;
21306                Some(chunk)
21307            } else {
21308                None
21309            }
21310        })
21311}
21312
21313pub trait RangeToAnchorExt: Sized {
21314    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21315
21316    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21317        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21318        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21319    }
21320}
21321
21322impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21323    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21324        let start_offset = self.start.to_offset(snapshot);
21325        let end_offset = self.end.to_offset(snapshot);
21326        if start_offset == end_offset {
21327            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21328        } else {
21329            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21330        }
21331    }
21332}
21333
21334pub trait RowExt {
21335    fn as_f32(&self) -> f32;
21336
21337    fn next_row(&self) -> Self;
21338
21339    fn previous_row(&self) -> Self;
21340
21341    fn minus(&self, other: Self) -> u32;
21342}
21343
21344impl RowExt for DisplayRow {
21345    fn as_f32(&self) -> f32 {
21346        self.0 as f32
21347    }
21348
21349    fn next_row(&self) -> Self {
21350        Self(self.0 + 1)
21351    }
21352
21353    fn previous_row(&self) -> Self {
21354        Self(self.0.saturating_sub(1))
21355    }
21356
21357    fn minus(&self, other: Self) -> u32 {
21358        self.0 - other.0
21359    }
21360}
21361
21362impl RowExt for MultiBufferRow {
21363    fn as_f32(&self) -> f32 {
21364        self.0 as f32
21365    }
21366
21367    fn next_row(&self) -> Self {
21368        Self(self.0 + 1)
21369    }
21370
21371    fn previous_row(&self) -> Self {
21372        Self(self.0.saturating_sub(1))
21373    }
21374
21375    fn minus(&self, other: Self) -> u32 {
21376        self.0 - other.0
21377    }
21378}
21379
21380trait RowRangeExt {
21381    type Row;
21382
21383    fn len(&self) -> usize;
21384
21385    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21386}
21387
21388impl RowRangeExt for Range<MultiBufferRow> {
21389    type Row = MultiBufferRow;
21390
21391    fn len(&self) -> usize {
21392        (self.end.0 - self.start.0) as usize
21393    }
21394
21395    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21396        (self.start.0..self.end.0).map(MultiBufferRow)
21397    }
21398}
21399
21400impl RowRangeExt for Range<DisplayRow> {
21401    type Row = DisplayRow;
21402
21403    fn len(&self) -> usize {
21404        (self.end.0 - self.start.0) as usize
21405    }
21406
21407    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21408        (self.start.0..self.end.0).map(DisplayRow)
21409    }
21410}
21411
21412/// If select range has more than one line, we
21413/// just point the cursor to range.start.
21414fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21415    if range.start.row == range.end.row {
21416        range
21417    } else {
21418        range.start..range.start
21419    }
21420}
21421pub struct KillRing(ClipboardItem);
21422impl Global for KillRing {}
21423
21424const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21425
21426enum BreakpointPromptEditAction {
21427    Log,
21428    Condition,
21429    HitCondition,
21430}
21431
21432struct BreakpointPromptEditor {
21433    pub(crate) prompt: Entity<Editor>,
21434    editor: WeakEntity<Editor>,
21435    breakpoint_anchor: Anchor,
21436    breakpoint: Breakpoint,
21437    edit_action: BreakpointPromptEditAction,
21438    block_ids: HashSet<CustomBlockId>,
21439    editor_margins: Arc<Mutex<EditorMargins>>,
21440    _subscriptions: Vec<Subscription>,
21441}
21442
21443impl BreakpointPromptEditor {
21444    const MAX_LINES: u8 = 4;
21445
21446    fn new(
21447        editor: WeakEntity<Editor>,
21448        breakpoint_anchor: Anchor,
21449        breakpoint: Breakpoint,
21450        edit_action: BreakpointPromptEditAction,
21451        window: &mut Window,
21452        cx: &mut Context<Self>,
21453    ) -> Self {
21454        let base_text = match edit_action {
21455            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21456            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21457            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21458        }
21459        .map(|msg| msg.to_string())
21460        .unwrap_or_default();
21461
21462        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21463        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21464
21465        let prompt = cx.new(|cx| {
21466            let mut prompt = Editor::new(
21467                EditorMode::AutoHeight {
21468                    max_lines: Self::MAX_LINES as usize,
21469                },
21470                buffer,
21471                None,
21472                window,
21473                cx,
21474            );
21475            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21476            prompt.set_show_cursor_when_unfocused(false, cx);
21477            prompt.set_placeholder_text(
21478                match edit_action {
21479                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21480                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21481                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21482                },
21483                cx,
21484            );
21485
21486            prompt
21487        });
21488
21489        Self {
21490            prompt,
21491            editor,
21492            breakpoint_anchor,
21493            breakpoint,
21494            edit_action,
21495            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21496            block_ids: Default::default(),
21497            _subscriptions: vec![],
21498        }
21499    }
21500
21501    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21502        self.block_ids.extend(block_ids)
21503    }
21504
21505    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21506        if let Some(editor) = self.editor.upgrade() {
21507            let message = self
21508                .prompt
21509                .read(cx)
21510                .buffer
21511                .read(cx)
21512                .as_singleton()
21513                .expect("A multi buffer in breakpoint prompt isn't possible")
21514                .read(cx)
21515                .as_rope()
21516                .to_string();
21517
21518            editor.update(cx, |editor, cx| {
21519                editor.edit_breakpoint_at_anchor(
21520                    self.breakpoint_anchor,
21521                    self.breakpoint.clone(),
21522                    match self.edit_action {
21523                        BreakpointPromptEditAction::Log => {
21524                            BreakpointEditAction::EditLogMessage(message.into())
21525                        }
21526                        BreakpointPromptEditAction::Condition => {
21527                            BreakpointEditAction::EditCondition(message.into())
21528                        }
21529                        BreakpointPromptEditAction::HitCondition => {
21530                            BreakpointEditAction::EditHitCondition(message.into())
21531                        }
21532                    },
21533                    cx,
21534                );
21535
21536                editor.remove_blocks(self.block_ids.clone(), None, cx);
21537                cx.focus_self(window);
21538            });
21539        }
21540    }
21541
21542    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21543        self.editor
21544            .update(cx, |editor, cx| {
21545                editor.remove_blocks(self.block_ids.clone(), None, cx);
21546                window.focus(&editor.focus_handle);
21547            })
21548            .log_err();
21549    }
21550
21551    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21552        let settings = ThemeSettings::get_global(cx);
21553        let text_style = TextStyle {
21554            color: if self.prompt.read(cx).read_only(cx) {
21555                cx.theme().colors().text_disabled
21556            } else {
21557                cx.theme().colors().text
21558            },
21559            font_family: settings.buffer_font.family.clone(),
21560            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21561            font_size: settings.buffer_font_size(cx).into(),
21562            font_weight: settings.buffer_font.weight,
21563            line_height: relative(settings.buffer_line_height.value()),
21564            ..Default::default()
21565        };
21566        EditorElement::new(
21567            &self.prompt,
21568            EditorStyle {
21569                background: cx.theme().colors().editor_background,
21570                local_player: cx.theme().players().local(),
21571                text: text_style,
21572                ..Default::default()
21573            },
21574        )
21575    }
21576}
21577
21578impl Render for BreakpointPromptEditor {
21579    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21580        let editor_margins = *self.editor_margins.lock();
21581        let gutter_dimensions = editor_margins.gutter;
21582        h_flex()
21583            .key_context("Editor")
21584            .bg(cx.theme().colors().editor_background)
21585            .border_y_1()
21586            .border_color(cx.theme().status().info_border)
21587            .size_full()
21588            .py(window.line_height() / 2.5)
21589            .on_action(cx.listener(Self::confirm))
21590            .on_action(cx.listener(Self::cancel))
21591            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21592            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21593    }
21594}
21595
21596impl Focusable for BreakpointPromptEditor {
21597    fn focus_handle(&self, cx: &App) -> FocusHandle {
21598        self.prompt.focus_handle(cx)
21599    }
21600}
21601
21602fn all_edits_insertions_or_deletions(
21603    edits: &Vec<(Range<Anchor>, String)>,
21604    snapshot: &MultiBufferSnapshot,
21605) -> bool {
21606    let mut all_insertions = true;
21607    let mut all_deletions = true;
21608
21609    for (range, new_text) in edits.iter() {
21610        let range_is_empty = range.to_offset(&snapshot).is_empty();
21611        let text_is_empty = new_text.is_empty();
21612
21613        if range_is_empty != text_is_empty {
21614            if range_is_empty {
21615                all_deletions = false;
21616            } else {
21617                all_insertions = false;
21618            }
21619        } else {
21620            return false;
21621        }
21622
21623        if !all_insertions && !all_deletions {
21624            return false;
21625        }
21626    }
21627    all_insertions || all_deletions
21628}
21629
21630struct MissingEditPredictionKeybindingTooltip;
21631
21632impl Render for MissingEditPredictionKeybindingTooltip {
21633    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21634        ui::tooltip_container(window, cx, |container, _, cx| {
21635            container
21636                .flex_shrink_0()
21637                .max_w_80()
21638                .min_h(rems_from_px(124.))
21639                .justify_between()
21640                .child(
21641                    v_flex()
21642                        .flex_1()
21643                        .text_ui_sm(cx)
21644                        .child(Label::new("Conflict with Accept Keybinding"))
21645                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21646                )
21647                .child(
21648                    h_flex()
21649                        .pb_1()
21650                        .gap_1()
21651                        .items_end()
21652                        .w_full()
21653                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21654                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21655                        }))
21656                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21657                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21658                        })),
21659                )
21660        })
21661    }
21662}
21663
21664#[derive(Debug, Clone, Copy, PartialEq)]
21665pub struct LineHighlight {
21666    pub background: Background,
21667    pub border: Option<gpui::Hsla>,
21668    pub include_gutter: bool,
21669    pub type_id: Option<TypeId>,
21670}
21671
21672fn render_diff_hunk_controls(
21673    row: u32,
21674    status: &DiffHunkStatus,
21675    hunk_range: Range<Anchor>,
21676    is_created_file: bool,
21677    line_height: Pixels,
21678    editor: &Entity<Editor>,
21679    _window: &mut Window,
21680    cx: &mut App,
21681) -> AnyElement {
21682    h_flex()
21683        .h(line_height)
21684        .mr_1()
21685        .gap_1()
21686        .px_0p5()
21687        .pb_1()
21688        .border_x_1()
21689        .border_b_1()
21690        .border_color(cx.theme().colors().border_variant)
21691        .rounded_b_lg()
21692        .bg(cx.theme().colors().editor_background)
21693        .gap_1()
21694        .occlude()
21695        .shadow_md()
21696        .child(if status.has_secondary_hunk() {
21697            Button::new(("stage", row as u64), "Stage")
21698                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21699                .tooltip({
21700                    let focus_handle = editor.focus_handle(cx);
21701                    move |window, cx| {
21702                        Tooltip::for_action_in(
21703                            "Stage Hunk",
21704                            &::git::ToggleStaged,
21705                            &focus_handle,
21706                            window,
21707                            cx,
21708                        )
21709                    }
21710                })
21711                .on_click({
21712                    let editor = editor.clone();
21713                    move |_event, _window, cx| {
21714                        editor.update(cx, |editor, cx| {
21715                            editor.stage_or_unstage_diff_hunks(
21716                                true,
21717                                vec![hunk_range.start..hunk_range.start],
21718                                cx,
21719                            );
21720                        });
21721                    }
21722                })
21723        } else {
21724            Button::new(("unstage", row as u64), "Unstage")
21725                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21726                .tooltip({
21727                    let focus_handle = editor.focus_handle(cx);
21728                    move |window, cx| {
21729                        Tooltip::for_action_in(
21730                            "Unstage Hunk",
21731                            &::git::ToggleStaged,
21732                            &focus_handle,
21733                            window,
21734                            cx,
21735                        )
21736                    }
21737                })
21738                .on_click({
21739                    let editor = editor.clone();
21740                    move |_event, _window, cx| {
21741                        editor.update(cx, |editor, cx| {
21742                            editor.stage_or_unstage_diff_hunks(
21743                                false,
21744                                vec![hunk_range.start..hunk_range.start],
21745                                cx,
21746                            );
21747                        });
21748                    }
21749                })
21750        })
21751        .child(
21752            Button::new(("restore", row as u64), "Restore")
21753                .tooltip({
21754                    let focus_handle = editor.focus_handle(cx);
21755                    move |window, cx| {
21756                        Tooltip::for_action_in(
21757                            "Restore Hunk",
21758                            &::git::Restore,
21759                            &focus_handle,
21760                            window,
21761                            cx,
21762                        )
21763                    }
21764                })
21765                .on_click({
21766                    let editor = editor.clone();
21767                    move |_event, window, cx| {
21768                        editor.update(cx, |editor, cx| {
21769                            let snapshot = editor.snapshot(window, cx);
21770                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21771                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21772                        });
21773                    }
21774                })
21775                .disabled(is_created_file),
21776        )
21777        .when(
21778            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21779            |el| {
21780                el.child(
21781                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21782                        .shape(IconButtonShape::Square)
21783                        .icon_size(IconSize::Small)
21784                        // .disabled(!has_multiple_hunks)
21785                        .tooltip({
21786                            let focus_handle = editor.focus_handle(cx);
21787                            move |window, cx| {
21788                                Tooltip::for_action_in(
21789                                    "Next Hunk",
21790                                    &GoToHunk,
21791                                    &focus_handle,
21792                                    window,
21793                                    cx,
21794                                )
21795                            }
21796                        })
21797                        .on_click({
21798                            let editor = editor.clone();
21799                            move |_event, window, cx| {
21800                                editor.update(cx, |editor, cx| {
21801                                    let snapshot = editor.snapshot(window, cx);
21802                                    let position =
21803                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21804                                    editor.go_to_hunk_before_or_after_position(
21805                                        &snapshot,
21806                                        position,
21807                                        Direction::Next,
21808                                        window,
21809                                        cx,
21810                                    );
21811                                    editor.expand_selected_diff_hunks(cx);
21812                                });
21813                            }
21814                        }),
21815                )
21816                .child(
21817                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21818                        .shape(IconButtonShape::Square)
21819                        .icon_size(IconSize::Small)
21820                        // .disabled(!has_multiple_hunks)
21821                        .tooltip({
21822                            let focus_handle = editor.focus_handle(cx);
21823                            move |window, cx| {
21824                                Tooltip::for_action_in(
21825                                    "Previous Hunk",
21826                                    &GoToPreviousHunk,
21827                                    &focus_handle,
21828                                    window,
21829                                    cx,
21830                                )
21831                            }
21832                        })
21833                        .on_click({
21834                            let editor = editor.clone();
21835                            move |_event, window, cx| {
21836                                editor.update(cx, |editor, cx| {
21837                                    let snapshot = editor.snapshot(window, cx);
21838                                    let point =
21839                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21840                                    editor.go_to_hunk_before_or_after_position(
21841                                        &snapshot,
21842                                        point,
21843                                        Direction::Prev,
21844                                        window,
21845                                        cx,
21846                                    );
21847                                    editor.expand_selected_diff_hunks(cx);
21848                                });
21849                            }
21850                        }),
21851                )
21852            },
21853        )
21854        .into_any_element()
21855}