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 is_within_block_comment = buffer
 4009                                    .language_scope_at(start_point)
 4010                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4011                                if !is_within_block_comment {
 4012                                    return None;
 4013                                }
 4014
 4015                                let (snapshot, range) =
 4016                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4017
 4018                                let num_of_whitespaces = snapshot
 4019                                    .chars_for_range(range.clone())
 4020                                    .take_while(|c| c.is_whitespace())
 4021                                    .count();
 4022
 4023                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4024                                let column = start_point.column;
 4025                                let cursor_is_after_start_tag = {
 4026                                    let start_tag_len = start_tag.len();
 4027                                    let start_tag_line = snapshot
 4028                                        .chars_for_range(range.clone())
 4029                                        .skip(num_of_whitespaces)
 4030                                        .take(start_tag_len)
 4031                                        .collect::<String>();
 4032                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4033                                        num_of_whitespaces + start_tag_len <= column as usize
 4034                                    } else {
 4035                                        false
 4036                                    }
 4037                                };
 4038
 4039                                let cursor_is_after_delimiter = {
 4040                                    let delimiter_trim = delimiter.trim_end();
 4041                                    let delimiter_line = snapshot
 4042                                        .chars_for_range(range.clone())
 4043                                        .skip(num_of_whitespaces)
 4044                                        .take(delimiter_trim.len())
 4045                                        .collect::<String>();
 4046                                    if delimiter_line.starts_with(delimiter_trim) {
 4047                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4048                                    } else {
 4049                                        false
 4050                                    }
 4051                                };
 4052
 4053                                let cursor_is_before_end_tag_if_exists = {
 4054                                    let mut char_position = 0u32;
 4055                                    let mut end_tag_offset = None;
 4056
 4057                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4058                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4059                                            let chars_before_match =
 4060                                                chunk[..byte_pos].chars().count() as u32;
 4061                                            end_tag_offset =
 4062                                                Some(char_position + chars_before_match);
 4063                                            break 'outer;
 4064                                        }
 4065                                        char_position += chunk.chars().count() as u32;
 4066                                    }
 4067
 4068                                    if let Some(end_tag_offset) = end_tag_offset {
 4069                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4070                                        if cursor_is_after_start_tag {
 4071                                            if cursor_is_before_end_tag {
 4072                                                insert_extra_newline = true;
 4073                                            }
 4074                                            let cursor_is_at_start_of_end_tag =
 4075                                                column == end_tag_offset;
 4076                                            if cursor_is_at_start_of_end_tag {
 4077                                                indent_on_extra_newline.len = (*len).into();
 4078                                            }
 4079                                        }
 4080                                        cursor_is_before_end_tag
 4081                                    } else {
 4082                                        true
 4083                                    }
 4084                                };
 4085
 4086                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4087                                    && cursor_is_before_end_tag_if_exists
 4088                                {
 4089                                    if cursor_is_after_start_tag {
 4090                                        indent_on_newline.len = (*len).into();
 4091                                    }
 4092                                    Some(delimiter.clone())
 4093                                } else {
 4094                                    None
 4095                                }
 4096                            });
 4097
 4098                            (
 4099                                comment_delimiter,
 4100                                doc_delimiter,
 4101                                insert_extra_newline,
 4102                                indent_on_newline,
 4103                                indent_on_extra_newline,
 4104                            )
 4105                        } else {
 4106                            (
 4107                                None,
 4108                                None,
 4109                                false,
 4110                                IndentSize::default(),
 4111                                IndentSize::default(),
 4112                            )
 4113                        };
 4114
 4115                        let prevent_auto_indent = doc_delimiter.is_some();
 4116                        let delimiter = comment_delimiter.or(doc_delimiter);
 4117
 4118                        let capacity_for_delimiter =
 4119                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4120                        let mut new_text = String::with_capacity(
 4121                            1 + capacity_for_delimiter
 4122                                + existing_indent.len as usize
 4123                                + indent_on_newline.len as usize
 4124                                + indent_on_extra_newline.len as usize,
 4125                        );
 4126                        new_text.push('\n');
 4127                        new_text.extend(existing_indent.chars());
 4128                        new_text.extend(indent_on_newline.chars());
 4129
 4130                        if let Some(delimiter) = &delimiter {
 4131                            new_text.push_str(delimiter);
 4132                        }
 4133
 4134                        if insert_extra_newline {
 4135                            new_text.push('\n');
 4136                            new_text.extend(existing_indent.chars());
 4137                            new_text.extend(indent_on_extra_newline.chars());
 4138                        }
 4139
 4140                        let anchor = buffer.anchor_after(end);
 4141                        let new_selection = selection.map(|_| anchor);
 4142                        (
 4143                            ((start..end, new_text), prevent_auto_indent),
 4144                            (insert_extra_newline, new_selection),
 4145                        )
 4146                    })
 4147                    .unzip()
 4148            };
 4149
 4150            let mut auto_indent_edits = Vec::new();
 4151            let mut edits = Vec::new();
 4152            for (edit, prevent_auto_indent) in edits_with_flags {
 4153                if prevent_auto_indent {
 4154                    edits.push(edit);
 4155                } else {
 4156                    auto_indent_edits.push(edit);
 4157                }
 4158            }
 4159            if !edits.is_empty() {
 4160                this.edit(edits, cx);
 4161            }
 4162            if !auto_indent_edits.is_empty() {
 4163                this.edit_with_autoindent(auto_indent_edits, cx);
 4164            }
 4165
 4166            let buffer = this.buffer.read(cx).snapshot(cx);
 4167            let new_selections = selection_info
 4168                .into_iter()
 4169                .map(|(extra_newline_inserted, new_selection)| {
 4170                    let mut cursor = new_selection.end.to_point(&buffer);
 4171                    if extra_newline_inserted {
 4172                        cursor.row -= 1;
 4173                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4174                    }
 4175                    new_selection.map(|_| cursor)
 4176                })
 4177                .collect();
 4178
 4179            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4180                s.select(new_selections)
 4181            });
 4182            this.refresh_inline_completion(true, false, window, cx);
 4183        });
 4184    }
 4185
 4186    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4187        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4188
 4189        let buffer = self.buffer.read(cx);
 4190        let snapshot = buffer.snapshot(cx);
 4191
 4192        let mut edits = Vec::new();
 4193        let mut rows = Vec::new();
 4194
 4195        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4196            let cursor = selection.head();
 4197            let row = cursor.row;
 4198
 4199            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4200
 4201            let newline = "\n".to_string();
 4202            edits.push((start_of_line..start_of_line, newline));
 4203
 4204            rows.push(row + rows_inserted as u32);
 4205        }
 4206
 4207        self.transact(window, cx, |editor, window, cx| {
 4208            editor.edit(edits, cx);
 4209
 4210            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4211                let mut index = 0;
 4212                s.move_cursors_with(|map, _, _| {
 4213                    let row = rows[index];
 4214                    index += 1;
 4215
 4216                    let point = Point::new(row, 0);
 4217                    let boundary = map.next_line_boundary(point).1;
 4218                    let clipped = map.clip_point(boundary, Bias::Left);
 4219
 4220                    (clipped, SelectionGoal::None)
 4221                });
 4222            });
 4223
 4224            let mut indent_edits = Vec::new();
 4225            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4226            for row in rows {
 4227                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4228                for (row, indent) in indents {
 4229                    if indent.len == 0 {
 4230                        continue;
 4231                    }
 4232
 4233                    let text = match indent.kind {
 4234                        IndentKind::Space => " ".repeat(indent.len as usize),
 4235                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4236                    };
 4237                    let point = Point::new(row.0, 0);
 4238                    indent_edits.push((point..point, text));
 4239                }
 4240            }
 4241            editor.edit(indent_edits, cx);
 4242        });
 4243    }
 4244
 4245    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4246        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4247
 4248        let buffer = self.buffer.read(cx);
 4249        let snapshot = buffer.snapshot(cx);
 4250
 4251        let mut edits = Vec::new();
 4252        let mut rows = Vec::new();
 4253        let mut rows_inserted = 0;
 4254
 4255        for selection in self.selections.all_adjusted(cx) {
 4256            let cursor = selection.head();
 4257            let row = cursor.row;
 4258
 4259            let point = Point::new(row + 1, 0);
 4260            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4261
 4262            let newline = "\n".to_string();
 4263            edits.push((start_of_line..start_of_line, newline));
 4264
 4265            rows_inserted += 1;
 4266            rows.push(row + rows_inserted);
 4267        }
 4268
 4269        self.transact(window, cx, |editor, window, cx| {
 4270            editor.edit(edits, cx);
 4271
 4272            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4273                let mut index = 0;
 4274                s.move_cursors_with(|map, _, _| {
 4275                    let row = rows[index];
 4276                    index += 1;
 4277
 4278                    let point = Point::new(row, 0);
 4279                    let boundary = map.next_line_boundary(point).1;
 4280                    let clipped = map.clip_point(boundary, Bias::Left);
 4281
 4282                    (clipped, SelectionGoal::None)
 4283                });
 4284            });
 4285
 4286            let mut indent_edits = Vec::new();
 4287            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4288            for row in rows {
 4289                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4290                for (row, indent) in indents {
 4291                    if indent.len == 0 {
 4292                        continue;
 4293                    }
 4294
 4295                    let text = match indent.kind {
 4296                        IndentKind::Space => " ".repeat(indent.len as usize),
 4297                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4298                    };
 4299                    let point = Point::new(row.0, 0);
 4300                    indent_edits.push((point..point, text));
 4301                }
 4302            }
 4303            editor.edit(indent_edits, cx);
 4304        });
 4305    }
 4306
 4307    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4308        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4309            original_indent_columns: Vec::new(),
 4310        });
 4311        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4312    }
 4313
 4314    fn insert_with_autoindent_mode(
 4315        &mut self,
 4316        text: &str,
 4317        autoindent_mode: Option<AutoindentMode>,
 4318        window: &mut Window,
 4319        cx: &mut Context<Self>,
 4320    ) {
 4321        if self.read_only(cx) {
 4322            return;
 4323        }
 4324
 4325        let text: Arc<str> = text.into();
 4326        self.transact(window, cx, |this, window, cx| {
 4327            let old_selections = this.selections.all_adjusted(cx);
 4328            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4329                let anchors = {
 4330                    let snapshot = buffer.read(cx);
 4331                    old_selections
 4332                        .iter()
 4333                        .map(|s| {
 4334                            let anchor = snapshot.anchor_after(s.head());
 4335                            s.map(|_| anchor)
 4336                        })
 4337                        .collect::<Vec<_>>()
 4338                };
 4339                buffer.edit(
 4340                    old_selections
 4341                        .iter()
 4342                        .map(|s| (s.start..s.end, text.clone())),
 4343                    autoindent_mode,
 4344                    cx,
 4345                );
 4346                anchors
 4347            });
 4348
 4349            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4350                s.select_anchors(selection_anchors);
 4351            });
 4352
 4353            cx.notify();
 4354        });
 4355    }
 4356
 4357    fn trigger_completion_on_input(
 4358        &mut self,
 4359        text: &str,
 4360        trigger_in_words: bool,
 4361        window: &mut Window,
 4362        cx: &mut Context<Self>,
 4363    ) {
 4364        let ignore_completion_provider = self
 4365            .context_menu
 4366            .borrow()
 4367            .as_ref()
 4368            .map(|menu| match menu {
 4369                CodeContextMenu::Completions(completions_menu) => {
 4370                    completions_menu.ignore_completion_provider
 4371                }
 4372                CodeContextMenu::CodeActions(_) => false,
 4373            })
 4374            .unwrap_or(false);
 4375
 4376        if ignore_completion_provider {
 4377            self.show_word_completions(&ShowWordCompletions, window, cx);
 4378        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4379            self.show_completions(
 4380                &ShowCompletions {
 4381                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4382                },
 4383                window,
 4384                cx,
 4385            );
 4386        } else {
 4387            self.hide_context_menu(window, cx);
 4388        }
 4389    }
 4390
 4391    fn is_completion_trigger(
 4392        &self,
 4393        text: &str,
 4394        trigger_in_words: bool,
 4395        cx: &mut Context<Self>,
 4396    ) -> bool {
 4397        let position = self.selections.newest_anchor().head();
 4398        let multibuffer = self.buffer.read(cx);
 4399        let Some(buffer) = position
 4400            .buffer_id
 4401            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4402        else {
 4403            return false;
 4404        };
 4405
 4406        if let Some(completion_provider) = &self.completion_provider {
 4407            completion_provider.is_completion_trigger(
 4408                &buffer,
 4409                position.text_anchor,
 4410                text,
 4411                trigger_in_words,
 4412                cx,
 4413            )
 4414        } else {
 4415            false
 4416        }
 4417    }
 4418
 4419    /// If any empty selections is touching the start of its innermost containing autoclose
 4420    /// region, expand it to select the brackets.
 4421    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4422        let selections = self.selections.all::<usize>(cx);
 4423        let buffer = self.buffer.read(cx).read(cx);
 4424        let new_selections = self
 4425            .selections_with_autoclose_regions(selections, &buffer)
 4426            .map(|(mut selection, region)| {
 4427                if !selection.is_empty() {
 4428                    return selection;
 4429                }
 4430
 4431                if let Some(region) = region {
 4432                    let mut range = region.range.to_offset(&buffer);
 4433                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4434                        range.start -= region.pair.start.len();
 4435                        if buffer.contains_str_at(range.start, &region.pair.start)
 4436                            && buffer.contains_str_at(range.end, &region.pair.end)
 4437                        {
 4438                            range.end += region.pair.end.len();
 4439                            selection.start = range.start;
 4440                            selection.end = range.end;
 4441
 4442                            return selection;
 4443                        }
 4444                    }
 4445                }
 4446
 4447                let always_treat_brackets_as_autoclosed = buffer
 4448                    .language_settings_at(selection.start, cx)
 4449                    .always_treat_brackets_as_autoclosed;
 4450
 4451                if !always_treat_brackets_as_autoclosed {
 4452                    return selection;
 4453                }
 4454
 4455                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4456                    for (pair, enabled) in scope.brackets() {
 4457                        if !enabled || !pair.close {
 4458                            continue;
 4459                        }
 4460
 4461                        if buffer.contains_str_at(selection.start, &pair.end) {
 4462                            let pair_start_len = pair.start.len();
 4463                            if buffer.contains_str_at(
 4464                                selection.start.saturating_sub(pair_start_len),
 4465                                &pair.start,
 4466                            ) {
 4467                                selection.start -= pair_start_len;
 4468                                selection.end += pair.end.len();
 4469
 4470                                return selection;
 4471                            }
 4472                        }
 4473                    }
 4474                }
 4475
 4476                selection
 4477            })
 4478            .collect();
 4479
 4480        drop(buffer);
 4481        self.change_selections(None, window, cx, |selections| {
 4482            selections.select(new_selections)
 4483        });
 4484    }
 4485
 4486    /// Iterate the given selections, and for each one, find the smallest surrounding
 4487    /// autoclose region. This uses the ordering of the selections and the autoclose
 4488    /// regions to avoid repeated comparisons.
 4489    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4490        &'a self,
 4491        selections: impl IntoIterator<Item = Selection<D>>,
 4492        buffer: &'a MultiBufferSnapshot,
 4493    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4494        let mut i = 0;
 4495        let mut regions = self.autoclose_regions.as_slice();
 4496        selections.into_iter().map(move |selection| {
 4497            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4498
 4499            let mut enclosing = None;
 4500            while let Some(pair_state) = regions.get(i) {
 4501                if pair_state.range.end.to_offset(buffer) < range.start {
 4502                    regions = &regions[i + 1..];
 4503                    i = 0;
 4504                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4505                    break;
 4506                } else {
 4507                    if pair_state.selection_id == selection.id {
 4508                        enclosing = Some(pair_state);
 4509                    }
 4510                    i += 1;
 4511                }
 4512            }
 4513
 4514            (selection, enclosing)
 4515        })
 4516    }
 4517
 4518    /// Remove any autoclose regions that no longer contain their selection.
 4519    fn invalidate_autoclose_regions(
 4520        &mut self,
 4521        mut selections: &[Selection<Anchor>],
 4522        buffer: &MultiBufferSnapshot,
 4523    ) {
 4524        self.autoclose_regions.retain(|state| {
 4525            let mut i = 0;
 4526            while let Some(selection) = selections.get(i) {
 4527                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4528                    selections = &selections[1..];
 4529                    continue;
 4530                }
 4531                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4532                    break;
 4533                }
 4534                if selection.id == state.selection_id {
 4535                    return true;
 4536                } else {
 4537                    i += 1;
 4538                }
 4539            }
 4540            false
 4541        });
 4542    }
 4543
 4544    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4545        let offset = position.to_offset(buffer);
 4546        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4547        if offset > word_range.start && kind == Some(CharKind::Word) {
 4548            Some(
 4549                buffer
 4550                    .text_for_range(word_range.start..offset)
 4551                    .collect::<String>(),
 4552            )
 4553        } else {
 4554            None
 4555        }
 4556    }
 4557
 4558    pub fn toggle_inline_values(
 4559        &mut self,
 4560        _: &ToggleInlineValues,
 4561        _: &mut Window,
 4562        cx: &mut Context<Self>,
 4563    ) {
 4564        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4565
 4566        self.refresh_inline_values(cx);
 4567    }
 4568
 4569    pub fn toggle_inlay_hints(
 4570        &mut self,
 4571        _: &ToggleInlayHints,
 4572        _: &mut Window,
 4573        cx: &mut Context<Self>,
 4574    ) {
 4575        self.refresh_inlay_hints(
 4576            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4577            cx,
 4578        );
 4579    }
 4580
 4581    pub fn inlay_hints_enabled(&self) -> bool {
 4582        self.inlay_hint_cache.enabled
 4583    }
 4584
 4585    pub fn inline_values_enabled(&self) -> bool {
 4586        self.inline_value_cache.enabled
 4587    }
 4588
 4589    #[cfg(any(test, feature = "test-support"))]
 4590    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4591        self.display_map
 4592            .read(cx)
 4593            .current_inlays()
 4594            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4595            .cloned()
 4596            .collect()
 4597    }
 4598
 4599    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4600        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4601            return;
 4602        }
 4603
 4604        let reason_description = reason.description();
 4605        let ignore_debounce = matches!(
 4606            reason,
 4607            InlayHintRefreshReason::SettingsChange(_)
 4608                | InlayHintRefreshReason::Toggle(_)
 4609                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4610                | InlayHintRefreshReason::ModifiersChanged(_)
 4611        );
 4612        let (invalidate_cache, required_languages) = match reason {
 4613            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4614                match self.inlay_hint_cache.modifiers_override(enabled) {
 4615                    Some(enabled) => {
 4616                        if enabled {
 4617                            (InvalidationStrategy::RefreshRequested, None)
 4618                        } else {
 4619                            self.splice_inlays(
 4620                                &self
 4621                                    .visible_inlay_hints(cx)
 4622                                    .iter()
 4623                                    .map(|inlay| inlay.id)
 4624                                    .collect::<Vec<InlayId>>(),
 4625                                Vec::new(),
 4626                                cx,
 4627                            );
 4628                            return;
 4629                        }
 4630                    }
 4631                    None => return,
 4632                }
 4633            }
 4634            InlayHintRefreshReason::Toggle(enabled) => {
 4635                if self.inlay_hint_cache.toggle(enabled) {
 4636                    if enabled {
 4637                        (InvalidationStrategy::RefreshRequested, None)
 4638                    } else {
 4639                        self.splice_inlays(
 4640                            &self
 4641                                .visible_inlay_hints(cx)
 4642                                .iter()
 4643                                .map(|inlay| inlay.id)
 4644                                .collect::<Vec<InlayId>>(),
 4645                            Vec::new(),
 4646                            cx,
 4647                        );
 4648                        return;
 4649                    }
 4650                } else {
 4651                    return;
 4652                }
 4653            }
 4654            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4655                match self.inlay_hint_cache.update_settings(
 4656                    &self.buffer,
 4657                    new_settings,
 4658                    self.visible_inlay_hints(cx),
 4659                    cx,
 4660                ) {
 4661                    ControlFlow::Break(Some(InlaySplice {
 4662                        to_remove,
 4663                        to_insert,
 4664                    })) => {
 4665                        self.splice_inlays(&to_remove, to_insert, cx);
 4666                        return;
 4667                    }
 4668                    ControlFlow::Break(None) => return,
 4669                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4670                }
 4671            }
 4672            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4673                if let Some(InlaySplice {
 4674                    to_remove,
 4675                    to_insert,
 4676                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4677                {
 4678                    self.splice_inlays(&to_remove, to_insert, cx);
 4679                }
 4680                self.display_map.update(cx, |display_map, _| {
 4681                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4682                });
 4683                return;
 4684            }
 4685            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4686            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4687                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4688            }
 4689            InlayHintRefreshReason::RefreshRequested => {
 4690                (InvalidationStrategy::RefreshRequested, None)
 4691            }
 4692        };
 4693
 4694        if let Some(InlaySplice {
 4695            to_remove,
 4696            to_insert,
 4697        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4698            reason_description,
 4699            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4700            invalidate_cache,
 4701            ignore_debounce,
 4702            cx,
 4703        ) {
 4704            self.splice_inlays(&to_remove, to_insert, cx);
 4705        }
 4706    }
 4707
 4708    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4709        self.display_map
 4710            .read(cx)
 4711            .current_inlays()
 4712            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4713            .cloned()
 4714            .collect()
 4715    }
 4716
 4717    pub fn excerpts_for_inlay_hints_query(
 4718        &self,
 4719        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4720        cx: &mut Context<Editor>,
 4721    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4722        let Some(project) = self.project.as_ref() else {
 4723            return HashMap::default();
 4724        };
 4725        let project = project.read(cx);
 4726        let multi_buffer = self.buffer().read(cx);
 4727        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4728        let multi_buffer_visible_start = self
 4729            .scroll_manager
 4730            .anchor()
 4731            .anchor
 4732            .to_point(&multi_buffer_snapshot);
 4733        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4734            multi_buffer_visible_start
 4735                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4736            Bias::Left,
 4737        );
 4738        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4739        multi_buffer_snapshot
 4740            .range_to_buffer_ranges(multi_buffer_visible_range)
 4741            .into_iter()
 4742            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4743            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4744                let buffer_file = project::File::from_dyn(buffer.file())?;
 4745                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4746                let worktree_entry = buffer_worktree
 4747                    .read(cx)
 4748                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4749                if worktree_entry.is_ignored {
 4750                    return None;
 4751                }
 4752
 4753                let language = buffer.language()?;
 4754                if let Some(restrict_to_languages) = restrict_to_languages {
 4755                    if !restrict_to_languages.contains(language) {
 4756                        return None;
 4757                    }
 4758                }
 4759                Some((
 4760                    excerpt_id,
 4761                    (
 4762                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4763                        buffer.version().clone(),
 4764                        excerpt_visible_range,
 4765                    ),
 4766                ))
 4767            })
 4768            .collect()
 4769    }
 4770
 4771    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4772        TextLayoutDetails {
 4773            text_system: window.text_system().clone(),
 4774            editor_style: self.style.clone().unwrap(),
 4775            rem_size: window.rem_size(),
 4776            scroll_anchor: self.scroll_manager.anchor(),
 4777            visible_rows: self.visible_line_count(),
 4778            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4779        }
 4780    }
 4781
 4782    pub fn splice_inlays(
 4783        &self,
 4784        to_remove: &[InlayId],
 4785        to_insert: Vec<Inlay>,
 4786        cx: &mut Context<Self>,
 4787    ) {
 4788        self.display_map.update(cx, |display_map, cx| {
 4789            display_map.splice_inlays(to_remove, to_insert, cx)
 4790        });
 4791        cx.notify();
 4792    }
 4793
 4794    fn trigger_on_type_formatting(
 4795        &self,
 4796        input: String,
 4797        window: &mut Window,
 4798        cx: &mut Context<Self>,
 4799    ) -> Option<Task<Result<()>>> {
 4800        if input.len() != 1 {
 4801            return None;
 4802        }
 4803
 4804        let project = self.project.as_ref()?;
 4805        let position = self.selections.newest_anchor().head();
 4806        let (buffer, buffer_position) = self
 4807            .buffer
 4808            .read(cx)
 4809            .text_anchor_for_position(position, cx)?;
 4810
 4811        let settings = language_settings::language_settings(
 4812            buffer
 4813                .read(cx)
 4814                .language_at(buffer_position)
 4815                .map(|l| l.name()),
 4816            buffer.read(cx).file(),
 4817            cx,
 4818        );
 4819        if !settings.use_on_type_format {
 4820            return None;
 4821        }
 4822
 4823        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4824        // hence we do LSP request & edit on host side only — add formats to host's history.
 4825        let push_to_lsp_host_history = true;
 4826        // If this is not the host, append its history with new edits.
 4827        let push_to_client_history = project.read(cx).is_via_collab();
 4828
 4829        let on_type_formatting = project.update(cx, |project, cx| {
 4830            project.on_type_format(
 4831                buffer.clone(),
 4832                buffer_position,
 4833                input,
 4834                push_to_lsp_host_history,
 4835                cx,
 4836            )
 4837        });
 4838        Some(cx.spawn_in(window, async move |editor, cx| {
 4839            if let Some(transaction) = on_type_formatting.await? {
 4840                if push_to_client_history {
 4841                    buffer
 4842                        .update(cx, |buffer, _| {
 4843                            buffer.push_transaction(transaction, Instant::now());
 4844                            buffer.finalize_last_transaction();
 4845                        })
 4846                        .ok();
 4847                }
 4848                editor.update(cx, |editor, cx| {
 4849                    editor.refresh_document_highlights(cx);
 4850                })?;
 4851            }
 4852            Ok(())
 4853        }))
 4854    }
 4855
 4856    pub fn show_word_completions(
 4857        &mut self,
 4858        _: &ShowWordCompletions,
 4859        window: &mut Window,
 4860        cx: &mut Context<Self>,
 4861    ) {
 4862        self.open_completions_menu(true, None, window, cx);
 4863    }
 4864
 4865    pub fn show_completions(
 4866        &mut self,
 4867        options: &ShowCompletions,
 4868        window: &mut Window,
 4869        cx: &mut Context<Self>,
 4870    ) {
 4871        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4872    }
 4873
 4874    fn open_completions_menu(
 4875        &mut self,
 4876        ignore_completion_provider: bool,
 4877        trigger: Option<&str>,
 4878        window: &mut Window,
 4879        cx: &mut Context<Self>,
 4880    ) {
 4881        if self.pending_rename.is_some() {
 4882            return;
 4883        }
 4884        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4885            return;
 4886        }
 4887
 4888        let position = self.selections.newest_anchor().head();
 4889        if position.diff_base_anchor.is_some() {
 4890            return;
 4891        }
 4892        let (buffer, buffer_position) =
 4893            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4894                output
 4895            } else {
 4896                return;
 4897            };
 4898        let buffer_snapshot = buffer.read(cx).snapshot();
 4899        let show_completion_documentation = buffer_snapshot
 4900            .settings_at(buffer_position, cx)
 4901            .show_completion_documentation;
 4902
 4903        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4904
 4905        let trigger_kind = match trigger {
 4906            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4907                CompletionTriggerKind::TRIGGER_CHARACTER
 4908            }
 4909            _ => CompletionTriggerKind::INVOKED,
 4910        };
 4911        let completion_context = CompletionContext {
 4912            trigger_character: trigger.and_then(|trigger| {
 4913                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4914                    Some(String::from(trigger))
 4915                } else {
 4916                    None
 4917                }
 4918            }),
 4919            trigger_kind,
 4920        };
 4921
 4922        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4923        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4924            let word_to_exclude = buffer_snapshot
 4925                .text_for_range(old_range.clone())
 4926                .collect::<String>();
 4927            (
 4928                buffer_snapshot.anchor_before(old_range.start)
 4929                    ..buffer_snapshot.anchor_after(old_range.end),
 4930                Some(word_to_exclude),
 4931            )
 4932        } else {
 4933            (buffer_position..buffer_position, None)
 4934        };
 4935
 4936        let completion_settings = language_settings(
 4937            buffer_snapshot
 4938                .language_at(buffer_position)
 4939                .map(|language| language.name()),
 4940            buffer_snapshot.file(),
 4941            cx,
 4942        )
 4943        .completions;
 4944
 4945        // The document can be large, so stay in reasonable bounds when searching for words,
 4946        // otherwise completion pop-up might be slow to appear.
 4947        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4948        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4949        let min_word_search = buffer_snapshot.clip_point(
 4950            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4951            Bias::Left,
 4952        );
 4953        let max_word_search = buffer_snapshot.clip_point(
 4954            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4955            Bias::Right,
 4956        );
 4957        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4958            ..buffer_snapshot.point_to_offset(max_word_search);
 4959
 4960        let provider = self
 4961            .completion_provider
 4962            .as_ref()
 4963            .filter(|_| !ignore_completion_provider);
 4964        let skip_digits = query
 4965            .as_ref()
 4966            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4967
 4968        let (mut words, provided_completions) = match provider {
 4969            Some(provider) => {
 4970                let completions = provider.completions(
 4971                    position.excerpt_id,
 4972                    &buffer,
 4973                    buffer_position,
 4974                    completion_context,
 4975                    window,
 4976                    cx,
 4977                );
 4978
 4979                let words = match completion_settings.words {
 4980                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4981                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4982                        .background_spawn(async move {
 4983                            buffer_snapshot.words_in_range(WordsQuery {
 4984                                fuzzy_contents: None,
 4985                                range: word_search_range,
 4986                                skip_digits,
 4987                            })
 4988                        }),
 4989                };
 4990
 4991                (words, completions)
 4992            }
 4993            None => (
 4994                cx.background_spawn(async move {
 4995                    buffer_snapshot.words_in_range(WordsQuery {
 4996                        fuzzy_contents: None,
 4997                        range: word_search_range,
 4998                        skip_digits,
 4999                    })
 5000                }),
 5001                Task::ready(Ok(None)),
 5002            ),
 5003        };
 5004
 5005        let sort_completions = provider
 5006            .as_ref()
 5007            .map_or(false, |provider| provider.sort_completions());
 5008
 5009        let filter_completions = provider
 5010            .as_ref()
 5011            .map_or(true, |provider| provider.filter_completions());
 5012
 5013        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5014
 5015        let id = post_inc(&mut self.next_completion_id);
 5016        let task = cx.spawn_in(window, async move |editor, cx| {
 5017            async move {
 5018                editor.update(cx, |this, _| {
 5019                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5020                })?;
 5021
 5022                let mut completions = Vec::new();
 5023                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5024                    completions.extend(provided_completions);
 5025                    if completion_settings.words == WordsCompletionMode::Fallback {
 5026                        words = Task::ready(BTreeMap::default());
 5027                    }
 5028                }
 5029
 5030                let mut words = words.await;
 5031                if let Some(word_to_exclude) = &word_to_exclude {
 5032                    words.remove(word_to_exclude);
 5033                }
 5034                for lsp_completion in &completions {
 5035                    words.remove(&lsp_completion.new_text);
 5036                }
 5037                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5038                    replace_range: old_range.clone(),
 5039                    new_text: word.clone(),
 5040                    label: CodeLabel::plain(word, None),
 5041                    icon_path: None,
 5042                    documentation: None,
 5043                    source: CompletionSource::BufferWord {
 5044                        word_range,
 5045                        resolved: false,
 5046                    },
 5047                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5048                    confirm: None,
 5049                }));
 5050
 5051                let menu = if completions.is_empty() {
 5052                    None
 5053                } else {
 5054                    let mut menu = CompletionsMenu::new(
 5055                        id,
 5056                        sort_completions,
 5057                        show_completion_documentation,
 5058                        ignore_completion_provider,
 5059                        position,
 5060                        buffer.clone(),
 5061                        completions.into(),
 5062                        snippet_sort_order,
 5063                    );
 5064
 5065                    menu.filter(
 5066                        if filter_completions {
 5067                            query.as_deref()
 5068                        } else {
 5069                            None
 5070                        },
 5071                        cx.background_executor().clone(),
 5072                    )
 5073                    .await;
 5074
 5075                    menu.visible().then_some(menu)
 5076                };
 5077
 5078                editor.update_in(cx, |editor, window, cx| {
 5079                    match editor.context_menu.borrow().as_ref() {
 5080                        None => {}
 5081                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5082                            if prev_menu.id > id {
 5083                                return;
 5084                            }
 5085                        }
 5086                        _ => return,
 5087                    }
 5088
 5089                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5090                        let mut menu = menu.unwrap();
 5091                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5092                        crate::hover_popover::hide_hover(editor, cx);
 5093                        *editor.context_menu.borrow_mut() =
 5094                            Some(CodeContextMenu::Completions(menu));
 5095
 5096                        if editor.show_edit_predictions_in_menu() {
 5097                            editor.update_visible_inline_completion(window, cx);
 5098                        } else {
 5099                            editor.discard_inline_completion(false, cx);
 5100                        }
 5101
 5102                        cx.notify();
 5103                    } else if editor.completion_tasks.len() <= 1 {
 5104                        // If there are no more completion tasks and the last menu was
 5105                        // empty, we should hide it.
 5106                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5107                        // If it was already hidden and we don't show inline
 5108                        // completions in the menu, we should also show the
 5109                        // inline-completion when available.
 5110                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5111                            editor.update_visible_inline_completion(window, cx);
 5112                        }
 5113                    }
 5114                })?;
 5115
 5116                anyhow::Ok(())
 5117            }
 5118            .log_err()
 5119            .await
 5120        });
 5121
 5122        self.completion_tasks.push((id, task));
 5123    }
 5124
 5125    #[cfg(feature = "test-support")]
 5126    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5127        let menu = self.context_menu.borrow();
 5128        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5129            let completions = menu.completions.borrow();
 5130            Some(completions.to_vec())
 5131        } else {
 5132            None
 5133        }
 5134    }
 5135
 5136    pub fn confirm_completion(
 5137        &mut self,
 5138        action: &ConfirmCompletion,
 5139        window: &mut Window,
 5140        cx: &mut Context<Self>,
 5141    ) -> Option<Task<Result<()>>> {
 5142        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5143        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5144    }
 5145
 5146    pub fn confirm_completion_insert(
 5147        &mut self,
 5148        _: &ConfirmCompletionInsert,
 5149        window: &mut Window,
 5150        cx: &mut Context<Self>,
 5151    ) -> Option<Task<Result<()>>> {
 5152        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5153        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5154    }
 5155
 5156    pub fn confirm_completion_replace(
 5157        &mut self,
 5158        _: &ConfirmCompletionReplace,
 5159        window: &mut Window,
 5160        cx: &mut Context<Self>,
 5161    ) -> Option<Task<Result<()>>> {
 5162        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5163        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5164    }
 5165
 5166    pub fn compose_completion(
 5167        &mut self,
 5168        action: &ComposeCompletion,
 5169        window: &mut Window,
 5170        cx: &mut Context<Self>,
 5171    ) -> Option<Task<Result<()>>> {
 5172        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5173        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5174    }
 5175
 5176    fn do_completion(
 5177        &mut self,
 5178        item_ix: Option<usize>,
 5179        intent: CompletionIntent,
 5180        window: &mut Window,
 5181        cx: &mut Context<Editor>,
 5182    ) -> Option<Task<Result<()>>> {
 5183        use language::ToOffset as _;
 5184
 5185        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5186        else {
 5187            return None;
 5188        };
 5189
 5190        let candidate_id = {
 5191            let entries = completions_menu.entries.borrow();
 5192            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5193            if self.show_edit_predictions_in_menu() {
 5194                self.discard_inline_completion(true, cx);
 5195            }
 5196            mat.candidate_id
 5197        };
 5198
 5199        let buffer_handle = completions_menu.buffer;
 5200        let completion = completions_menu
 5201            .completions
 5202            .borrow()
 5203            .get(candidate_id)?
 5204            .clone();
 5205        cx.stop_propagation();
 5206
 5207        let snapshot = self.buffer.read(cx).snapshot(cx);
 5208        let newest_anchor = self.selections.newest_anchor();
 5209
 5210        let snippet;
 5211        let new_text;
 5212        if completion.is_snippet() {
 5213            let mut snippet_source = completion.new_text.clone();
 5214            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5215                if scope.prefers_label_for_snippet_in_completion() {
 5216                    if let Some(label) = completion.label() {
 5217                        if matches!(
 5218                            completion.kind(),
 5219                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5220                        ) {
 5221                            snippet_source = label;
 5222                        }
 5223                    }
 5224                }
 5225            }
 5226            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5227            new_text = snippet.as_ref().unwrap().text.clone();
 5228        } else {
 5229            snippet = None;
 5230            new_text = completion.new_text.clone();
 5231        };
 5232
 5233        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5234        let buffer = buffer_handle.read(cx);
 5235        let replace_range_multibuffer = {
 5236            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5237            let multibuffer_anchor = snapshot
 5238                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5239                .unwrap()
 5240                ..snapshot
 5241                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5242                    .unwrap();
 5243            multibuffer_anchor.start.to_offset(&snapshot)
 5244                ..multibuffer_anchor.end.to_offset(&snapshot)
 5245        };
 5246        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5247            return None;
 5248        }
 5249
 5250        let old_text = buffer
 5251            .text_for_range(replace_range.clone())
 5252            .collect::<String>();
 5253        let lookbehind = newest_anchor
 5254            .start
 5255            .text_anchor
 5256            .to_offset(buffer)
 5257            .saturating_sub(replace_range.start);
 5258        let lookahead = replace_range
 5259            .end
 5260            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5261        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5262        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5263
 5264        let selections = self.selections.all::<usize>(cx);
 5265        let mut ranges = Vec::new();
 5266        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5267
 5268        for selection in &selections {
 5269            let range = if selection.id == newest_anchor.id {
 5270                replace_range_multibuffer.clone()
 5271            } else {
 5272                let mut range = selection.range();
 5273
 5274                // if prefix is present, don't duplicate it
 5275                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5276                    range.start = range.start.saturating_sub(lookbehind);
 5277
 5278                    // if suffix is also present, mimic the newest cursor and replace it
 5279                    if selection.id != newest_anchor.id
 5280                        && snapshot.contains_str_at(range.end, suffix)
 5281                    {
 5282                        range.end += lookahead;
 5283                    }
 5284                }
 5285                range
 5286            };
 5287
 5288            ranges.push(range.clone());
 5289
 5290            if !self.linked_edit_ranges.is_empty() {
 5291                let start_anchor = snapshot.anchor_before(range.start);
 5292                let end_anchor = snapshot.anchor_after(range.end);
 5293                if let Some(ranges) = self
 5294                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5295                {
 5296                    for (buffer, edits) in ranges {
 5297                        linked_edits
 5298                            .entry(buffer.clone())
 5299                            .or_default()
 5300                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5301                    }
 5302                }
 5303            }
 5304        }
 5305
 5306        cx.emit(EditorEvent::InputHandled {
 5307            utf16_range_to_replace: None,
 5308            text: new_text.clone().into(),
 5309        });
 5310
 5311        self.transact(window, cx, |this, window, cx| {
 5312            if let Some(mut snippet) = snippet {
 5313                snippet.text = new_text.to_string();
 5314                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5315            } else {
 5316                this.buffer.update(cx, |buffer, cx| {
 5317                    let auto_indent = match completion.insert_text_mode {
 5318                        Some(InsertTextMode::AS_IS) => None,
 5319                        _ => this.autoindent_mode.clone(),
 5320                    };
 5321                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5322                    buffer.edit(edits, auto_indent, cx);
 5323                });
 5324            }
 5325            for (buffer, edits) in linked_edits {
 5326                buffer.update(cx, |buffer, cx| {
 5327                    let snapshot = buffer.snapshot();
 5328                    let edits = edits
 5329                        .into_iter()
 5330                        .map(|(range, text)| {
 5331                            use text::ToPoint as TP;
 5332                            let end_point = TP::to_point(&range.end, &snapshot);
 5333                            let start_point = TP::to_point(&range.start, &snapshot);
 5334                            (start_point..end_point, text)
 5335                        })
 5336                        .sorted_by_key(|(range, _)| range.start);
 5337                    buffer.edit(edits, None, cx);
 5338                })
 5339            }
 5340
 5341            this.refresh_inline_completion(true, false, window, cx);
 5342        });
 5343
 5344        let show_new_completions_on_confirm = completion
 5345            .confirm
 5346            .as_ref()
 5347            .map_or(false, |confirm| confirm(intent, window, cx));
 5348        if show_new_completions_on_confirm {
 5349            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5350        }
 5351
 5352        let provider = self.completion_provider.as_ref()?;
 5353        drop(completion);
 5354        let apply_edits = provider.apply_additional_edits_for_completion(
 5355            buffer_handle,
 5356            completions_menu.completions.clone(),
 5357            candidate_id,
 5358            true,
 5359            cx,
 5360        );
 5361
 5362        let editor_settings = EditorSettings::get_global(cx);
 5363        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5364            // After the code completion is finished, users often want to know what signatures are needed.
 5365            // so we should automatically call signature_help
 5366            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5367        }
 5368
 5369        Some(cx.foreground_executor().spawn(async move {
 5370            apply_edits.await?;
 5371            Ok(())
 5372        }))
 5373    }
 5374
 5375    pub fn toggle_code_actions(
 5376        &mut self,
 5377        action: &ToggleCodeActions,
 5378        window: &mut Window,
 5379        cx: &mut Context<Self>,
 5380    ) {
 5381        let quick_launch = action.quick_launch;
 5382        let mut context_menu = self.context_menu.borrow_mut();
 5383        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5384            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 5385                // Toggle if we're selecting the same one
 5386                *context_menu = None;
 5387                cx.notify();
 5388                return;
 5389            } else {
 5390                // Otherwise, clear it and start a new one
 5391                *context_menu = None;
 5392                cx.notify();
 5393            }
 5394        }
 5395        drop(context_menu);
 5396        let snapshot = self.snapshot(window, cx);
 5397        let deployed_from_indicator = action.deployed_from_indicator;
 5398        let mut task = self.code_actions_task.take();
 5399        let action = action.clone();
 5400        cx.spawn_in(window, async move |editor, cx| {
 5401            while let Some(prev_task) = task {
 5402                prev_task.await.log_err();
 5403                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5404            }
 5405
 5406            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5407                if editor.focus_handle.is_focused(window) {
 5408                    let multibuffer_point = action
 5409                        .deployed_from_indicator
 5410                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 5411                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 5412                    let (buffer, buffer_row) = snapshot
 5413                        .buffer_snapshot
 5414                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5415                        .and_then(|(buffer_snapshot, range)| {
 5416                            editor
 5417                                .buffer
 5418                                .read(cx)
 5419                                .buffer(buffer_snapshot.remote_id())
 5420                                .map(|buffer| (buffer, range.start.row))
 5421                        })?;
 5422                    let (_, code_actions) = editor
 5423                        .available_code_actions
 5424                        .clone()
 5425                        .and_then(|(location, code_actions)| {
 5426                            let snapshot = location.buffer.read(cx).snapshot();
 5427                            let point_range = location.range.to_point(&snapshot);
 5428                            let point_range = point_range.start.row..=point_range.end.row;
 5429                            if point_range.contains(&buffer_row) {
 5430                                Some((location, code_actions))
 5431                            } else {
 5432                                None
 5433                            }
 5434                        })
 5435                        .unzip();
 5436                    let buffer_id = buffer.read(cx).remote_id();
 5437                    let tasks = editor
 5438                        .tasks
 5439                        .get(&(buffer_id, buffer_row))
 5440                        .map(|t| Arc::new(t.to_owned()));
 5441                    if tasks.is_none() && code_actions.is_none() {
 5442                        return None;
 5443                    }
 5444
 5445                    editor.completion_tasks.clear();
 5446                    editor.discard_inline_completion(false, cx);
 5447                    let task_context =
 5448                        tasks
 5449                            .as_ref()
 5450                            .zip(editor.project.clone())
 5451                            .map(|(tasks, project)| {
 5452                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5453                            });
 5454
 5455                    Some(cx.spawn_in(window, async move |editor, cx| {
 5456                        let task_context = match task_context {
 5457                            Some(task_context) => task_context.await,
 5458                            None => None,
 5459                        };
 5460                        let resolved_tasks =
 5461                            tasks
 5462                                .zip(task_context.clone())
 5463                                .map(|(tasks, task_context)| ResolvedTasks {
 5464                                    templates: tasks.resolve(&task_context).collect(),
 5465                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5466                                        multibuffer_point.row,
 5467                                        tasks.column,
 5468                                    )),
 5469                                });
 5470                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5471                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5472                                maybe!({
 5473                                    let project = editor.project.as_ref()?;
 5474                                    let dap_store = project.read(cx).dap_store();
 5475                                    let mut scenarios = vec![];
 5476                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5477                                    let buffer = buffer.read(cx);
 5478                                    let language = buffer.language()?;
 5479                                    let file = buffer.file();
 5480                                    let debug_adapter =
 5481                                        language_settings(language.name().into(), file, cx)
 5482                                            .debuggers
 5483                                            .first()
 5484                                            .map(SharedString::from)
 5485                                            .or_else(|| {
 5486                                                language
 5487                                                    .config()
 5488                                                    .debuggers
 5489                                                    .first()
 5490                                                    .map(SharedString::from)
 5491                                            })?;
 5492
 5493                                    dap_store.update(cx, |dap_store, cx| {
 5494                                        for (_, task) in &resolved_tasks.templates {
 5495                                            if let Some(scenario) = dap_store
 5496                                                .debug_scenario_for_build_task(
 5497                                                    task.original_task().clone(),
 5498                                                    debug_adapter.clone().into(),
 5499                                                    task.display_label().to_owned().into(),
 5500                                                    cx,
 5501                                                )
 5502                                            {
 5503                                                scenarios.push(scenario);
 5504                                            }
 5505                                        }
 5506                                    });
 5507                                    Some(scenarios)
 5508                                })
 5509                                .unwrap_or_default()
 5510                            } else {
 5511                                vec![]
 5512                            }
 5513                        })?;
 5514                        let spawn_straight_away = quick_launch
 5515                            && resolved_tasks
 5516                                .as_ref()
 5517                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5518                            && code_actions
 5519                                .as_ref()
 5520                                .map_or(true, |actions| actions.is_empty())
 5521                            && debug_scenarios.is_empty();
 5522                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5523                            crate::hover_popover::hide_hover(editor, cx);
 5524                            *editor.context_menu.borrow_mut() =
 5525                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5526                                    buffer,
 5527                                    actions: CodeActionContents::new(
 5528                                        resolved_tasks,
 5529                                        code_actions,
 5530                                        debug_scenarios,
 5531                                        task_context.unwrap_or_default(),
 5532                                    ),
 5533                                    selected_item: Default::default(),
 5534                                    scroll_handle: UniformListScrollHandle::default(),
 5535                                    deployed_from_indicator,
 5536                                }));
 5537                            if spawn_straight_away {
 5538                                if let Some(task) = editor.confirm_code_action(
 5539                                    &ConfirmCodeAction { item_ix: Some(0) },
 5540                                    window,
 5541                                    cx,
 5542                                ) {
 5543                                    cx.notify();
 5544                                    return task;
 5545                                }
 5546                            }
 5547                            cx.notify();
 5548                            Task::ready(Ok(()))
 5549                        }) {
 5550                            task.await
 5551                        } else {
 5552                            Ok(())
 5553                        }
 5554                    }))
 5555                } else {
 5556                    Some(Task::ready(Ok(())))
 5557                }
 5558            })?;
 5559            if let Some(task) = spawned_test_task {
 5560                task.await?;
 5561            }
 5562
 5563            anyhow::Ok(())
 5564        })
 5565        .detach_and_log_err(cx);
 5566    }
 5567
 5568    pub fn confirm_code_action(
 5569        &mut self,
 5570        action: &ConfirmCodeAction,
 5571        window: &mut Window,
 5572        cx: &mut Context<Self>,
 5573    ) -> Option<Task<Result<()>>> {
 5574        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5575
 5576        let actions_menu =
 5577            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5578                menu
 5579            } else {
 5580                return None;
 5581            };
 5582
 5583        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5584        let action = actions_menu.actions.get(action_ix)?;
 5585        let title = action.label();
 5586        let buffer = actions_menu.buffer;
 5587        let workspace = self.workspace()?;
 5588
 5589        match action {
 5590            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5591                workspace.update(cx, |workspace, cx| {
 5592                    workspace.schedule_resolved_task(
 5593                        task_source_kind,
 5594                        resolved_task,
 5595                        false,
 5596                        window,
 5597                        cx,
 5598                    );
 5599
 5600                    Some(Task::ready(Ok(())))
 5601                })
 5602            }
 5603            CodeActionsItem::CodeAction {
 5604                excerpt_id,
 5605                action,
 5606                provider,
 5607            } => {
 5608                let apply_code_action =
 5609                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5610                let workspace = workspace.downgrade();
 5611                Some(cx.spawn_in(window, async move |editor, cx| {
 5612                    let project_transaction = apply_code_action.await?;
 5613                    Self::open_project_transaction(
 5614                        &editor,
 5615                        workspace,
 5616                        project_transaction,
 5617                        title,
 5618                        cx,
 5619                    )
 5620                    .await
 5621                }))
 5622            }
 5623            CodeActionsItem::DebugScenario(scenario) => {
 5624                let context = actions_menu.actions.context.clone();
 5625
 5626                workspace.update(cx, |workspace, cx| {
 5627                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5628                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5629                });
 5630                Some(Task::ready(Ok(())))
 5631            }
 5632        }
 5633    }
 5634
 5635    pub async fn open_project_transaction(
 5636        this: &WeakEntity<Editor>,
 5637        workspace: WeakEntity<Workspace>,
 5638        transaction: ProjectTransaction,
 5639        title: String,
 5640        cx: &mut AsyncWindowContext,
 5641    ) -> Result<()> {
 5642        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5643        cx.update(|_, cx| {
 5644            entries.sort_unstable_by_key(|(buffer, _)| {
 5645                buffer.read(cx).file().map(|f| f.path().clone())
 5646            });
 5647        })?;
 5648
 5649        // If the project transaction's edits are all contained within this editor, then
 5650        // avoid opening a new editor to display them.
 5651
 5652        if let Some((buffer, transaction)) = entries.first() {
 5653            if entries.len() == 1 {
 5654                let excerpt = this.update(cx, |editor, cx| {
 5655                    editor
 5656                        .buffer()
 5657                        .read(cx)
 5658                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5659                })?;
 5660                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5661                    if excerpted_buffer == *buffer {
 5662                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5663                            let excerpt_range = excerpt_range.to_offset(buffer);
 5664                            buffer
 5665                                .edited_ranges_for_transaction::<usize>(transaction)
 5666                                .all(|range| {
 5667                                    excerpt_range.start <= range.start
 5668                                        && excerpt_range.end >= range.end
 5669                                })
 5670                        })?;
 5671
 5672                        if all_edits_within_excerpt {
 5673                            return Ok(());
 5674                        }
 5675                    }
 5676                }
 5677            }
 5678        } else {
 5679            return Ok(());
 5680        }
 5681
 5682        let mut ranges_to_highlight = Vec::new();
 5683        let excerpt_buffer = cx.new(|cx| {
 5684            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5685            for (buffer_handle, transaction) in &entries {
 5686                let edited_ranges = buffer_handle
 5687                    .read(cx)
 5688                    .edited_ranges_for_transaction::<Point>(transaction)
 5689                    .collect::<Vec<_>>();
 5690                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5691                    PathKey::for_buffer(buffer_handle, cx),
 5692                    buffer_handle.clone(),
 5693                    edited_ranges,
 5694                    DEFAULT_MULTIBUFFER_CONTEXT,
 5695                    cx,
 5696                );
 5697
 5698                ranges_to_highlight.extend(ranges);
 5699            }
 5700            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5701            multibuffer
 5702        })?;
 5703
 5704        workspace.update_in(cx, |workspace, window, cx| {
 5705            let project = workspace.project().clone();
 5706            let editor =
 5707                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5708            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5709            editor.update(cx, |editor, cx| {
 5710                editor.highlight_background::<Self>(
 5711                    &ranges_to_highlight,
 5712                    |theme| theme.editor_highlighted_line_background,
 5713                    cx,
 5714                );
 5715            });
 5716        })?;
 5717
 5718        Ok(())
 5719    }
 5720
 5721    pub fn clear_code_action_providers(&mut self) {
 5722        self.code_action_providers.clear();
 5723        self.available_code_actions.take();
 5724    }
 5725
 5726    pub fn add_code_action_provider(
 5727        &mut self,
 5728        provider: Rc<dyn CodeActionProvider>,
 5729        window: &mut Window,
 5730        cx: &mut Context<Self>,
 5731    ) {
 5732        if self
 5733            .code_action_providers
 5734            .iter()
 5735            .any(|existing_provider| existing_provider.id() == provider.id())
 5736        {
 5737            return;
 5738        }
 5739
 5740        self.code_action_providers.push(provider);
 5741        self.refresh_code_actions(window, cx);
 5742    }
 5743
 5744    pub fn remove_code_action_provider(
 5745        &mut self,
 5746        id: Arc<str>,
 5747        window: &mut Window,
 5748        cx: &mut Context<Self>,
 5749    ) {
 5750        self.code_action_providers
 5751            .retain(|provider| provider.id() != id);
 5752        self.refresh_code_actions(window, cx);
 5753    }
 5754
 5755    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5756        let newest_selection = self.selections.newest_anchor().clone();
 5757        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5758        let buffer = self.buffer.read(cx);
 5759        if newest_selection.head().diff_base_anchor.is_some() {
 5760            return None;
 5761        }
 5762        let (start_buffer, start) =
 5763            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5764        let (end_buffer, end) =
 5765            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5766        if start_buffer != end_buffer {
 5767            return None;
 5768        }
 5769
 5770        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5771            cx.background_executor()
 5772                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5773                .await;
 5774
 5775            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5776                let providers = this.code_action_providers.clone();
 5777                let tasks = this
 5778                    .code_action_providers
 5779                    .iter()
 5780                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5781                    .collect::<Vec<_>>();
 5782                (providers, tasks)
 5783            })?;
 5784
 5785            let mut actions = Vec::new();
 5786            for (provider, provider_actions) in
 5787                providers.into_iter().zip(future::join_all(tasks).await)
 5788            {
 5789                if let Some(provider_actions) = provider_actions.log_err() {
 5790                    actions.extend(provider_actions.into_iter().map(|action| {
 5791                        AvailableCodeAction {
 5792                            excerpt_id: newest_selection.start.excerpt_id,
 5793                            action,
 5794                            provider: provider.clone(),
 5795                        }
 5796                    }));
 5797                }
 5798            }
 5799
 5800            this.update(cx, |this, cx| {
 5801                this.available_code_actions = if actions.is_empty() {
 5802                    None
 5803                } else {
 5804                    Some((
 5805                        Location {
 5806                            buffer: start_buffer,
 5807                            range: start..end,
 5808                        },
 5809                        actions.into(),
 5810                    ))
 5811                };
 5812                cx.notify();
 5813            })
 5814        }));
 5815        None
 5816    }
 5817
 5818    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5819        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5820            self.show_git_blame_inline = false;
 5821
 5822            self.show_git_blame_inline_delay_task =
 5823                Some(cx.spawn_in(window, async move |this, cx| {
 5824                    cx.background_executor().timer(delay).await;
 5825
 5826                    this.update(cx, |this, cx| {
 5827                        this.show_git_blame_inline = true;
 5828                        cx.notify();
 5829                    })
 5830                    .log_err();
 5831                }));
 5832        }
 5833    }
 5834
 5835    fn show_blame_popover(
 5836        &mut self,
 5837        blame_entry: &BlameEntry,
 5838        position: gpui::Point<Pixels>,
 5839        cx: &mut Context<Self>,
 5840    ) {
 5841        if let Some(state) = &mut self.inline_blame_popover {
 5842            state.hide_task.take();
 5843            cx.notify();
 5844        } else {
 5845            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5846            let show_task = cx.spawn(async move |editor, cx| {
 5847                cx.background_executor()
 5848                    .timer(std::time::Duration::from_millis(delay))
 5849                    .await;
 5850                editor
 5851                    .update(cx, |editor, cx| {
 5852                        if let Some(state) = &mut editor.inline_blame_popover {
 5853                            state.show_task = None;
 5854                            cx.notify();
 5855                        }
 5856                    })
 5857                    .ok();
 5858            });
 5859            let Some(blame) = self.blame.as_ref() else {
 5860                return;
 5861            };
 5862            let blame = blame.read(cx);
 5863            let details = blame.details_for_entry(&blame_entry);
 5864            let markdown = cx.new(|cx| {
 5865                Markdown::new(
 5866                    details
 5867                        .as_ref()
 5868                        .map(|message| message.message.clone())
 5869                        .unwrap_or_default(),
 5870                    None,
 5871                    None,
 5872                    cx,
 5873                )
 5874            });
 5875            self.inline_blame_popover = Some(InlineBlamePopover {
 5876                position,
 5877                show_task: Some(show_task),
 5878                hide_task: None,
 5879                popover_bounds: None,
 5880                popover_state: InlineBlamePopoverState {
 5881                    scroll_handle: ScrollHandle::new(),
 5882                    commit_message: details,
 5883                    markdown,
 5884                },
 5885            });
 5886        }
 5887    }
 5888
 5889    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5890        if let Some(state) = &mut self.inline_blame_popover {
 5891            if state.show_task.is_some() {
 5892                self.inline_blame_popover.take();
 5893                cx.notify();
 5894            } else {
 5895                let hide_task = cx.spawn(async move |editor, cx| {
 5896                    cx.background_executor()
 5897                        .timer(std::time::Duration::from_millis(100))
 5898                        .await;
 5899                    editor
 5900                        .update(cx, |editor, cx| {
 5901                            editor.inline_blame_popover.take();
 5902                            cx.notify();
 5903                        })
 5904                        .ok();
 5905                });
 5906                state.hide_task = Some(hide_task);
 5907            }
 5908        }
 5909    }
 5910
 5911    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5912        if self.pending_rename.is_some() {
 5913            return None;
 5914        }
 5915
 5916        let provider = self.semantics_provider.clone()?;
 5917        let buffer = self.buffer.read(cx);
 5918        let newest_selection = self.selections.newest_anchor().clone();
 5919        let cursor_position = newest_selection.head();
 5920        let (cursor_buffer, cursor_buffer_position) =
 5921            buffer.text_anchor_for_position(cursor_position, cx)?;
 5922        let (tail_buffer, tail_buffer_position) =
 5923            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5924        if cursor_buffer != tail_buffer {
 5925            return None;
 5926        }
 5927
 5928        let snapshot = cursor_buffer.read(cx).snapshot();
 5929        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5930        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5931        if start_word_range != end_word_range {
 5932            self.document_highlights_task.take();
 5933            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5934            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5935            return None;
 5936        }
 5937
 5938        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5939        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5940            cx.background_executor()
 5941                .timer(Duration::from_millis(debounce))
 5942                .await;
 5943
 5944            let highlights = if let Some(highlights) = cx
 5945                .update(|cx| {
 5946                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5947                })
 5948                .ok()
 5949                .flatten()
 5950            {
 5951                highlights.await.log_err()
 5952            } else {
 5953                None
 5954            };
 5955
 5956            if let Some(highlights) = highlights {
 5957                this.update(cx, |this, cx| {
 5958                    if this.pending_rename.is_some() {
 5959                        return;
 5960                    }
 5961
 5962                    let buffer_id = cursor_position.buffer_id;
 5963                    let buffer = this.buffer.read(cx);
 5964                    if !buffer
 5965                        .text_anchor_for_position(cursor_position, cx)
 5966                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5967                    {
 5968                        return;
 5969                    }
 5970
 5971                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5972                    let mut write_ranges = Vec::new();
 5973                    let mut read_ranges = Vec::new();
 5974                    for highlight in highlights {
 5975                        for (excerpt_id, excerpt_range) in
 5976                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5977                        {
 5978                            let start = highlight
 5979                                .range
 5980                                .start
 5981                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5982                            let end = highlight
 5983                                .range
 5984                                .end
 5985                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5986                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5987                                continue;
 5988                            }
 5989
 5990                            let range = Anchor {
 5991                                buffer_id,
 5992                                excerpt_id,
 5993                                text_anchor: start,
 5994                                diff_base_anchor: None,
 5995                            }..Anchor {
 5996                                buffer_id,
 5997                                excerpt_id,
 5998                                text_anchor: end,
 5999                                diff_base_anchor: None,
 6000                            };
 6001                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6002                                write_ranges.push(range);
 6003                            } else {
 6004                                read_ranges.push(range);
 6005                            }
 6006                        }
 6007                    }
 6008
 6009                    this.highlight_background::<DocumentHighlightRead>(
 6010                        &read_ranges,
 6011                        |theme| theme.editor_document_highlight_read_background,
 6012                        cx,
 6013                    );
 6014                    this.highlight_background::<DocumentHighlightWrite>(
 6015                        &write_ranges,
 6016                        |theme| theme.editor_document_highlight_write_background,
 6017                        cx,
 6018                    );
 6019                    cx.notify();
 6020                })
 6021                .log_err();
 6022            }
 6023        }));
 6024        None
 6025    }
 6026
 6027    fn prepare_highlight_query_from_selection(
 6028        &mut self,
 6029        cx: &mut Context<Editor>,
 6030    ) -> Option<(String, Range<Anchor>)> {
 6031        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6032            return None;
 6033        }
 6034        if !EditorSettings::get_global(cx).selection_highlight {
 6035            return None;
 6036        }
 6037        if self.selections.count() != 1 || self.selections.line_mode {
 6038            return None;
 6039        }
 6040        let selection = self.selections.newest::<Point>(cx);
 6041        if selection.is_empty() || selection.start.row != selection.end.row {
 6042            return None;
 6043        }
 6044        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6045        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6046        let query = multi_buffer_snapshot
 6047            .text_for_range(selection_anchor_range.clone())
 6048            .collect::<String>();
 6049        if query.trim().is_empty() {
 6050            return None;
 6051        }
 6052        Some((query, selection_anchor_range))
 6053    }
 6054
 6055    fn update_selection_occurrence_highlights(
 6056        &mut self,
 6057        query_text: String,
 6058        query_range: Range<Anchor>,
 6059        multi_buffer_range_to_query: Range<Point>,
 6060        use_debounce: bool,
 6061        window: &mut Window,
 6062        cx: &mut Context<Editor>,
 6063    ) -> Task<()> {
 6064        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6065        cx.spawn_in(window, async move |editor, cx| {
 6066            if use_debounce {
 6067                cx.background_executor()
 6068                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6069                    .await;
 6070            }
 6071            let match_task = cx.background_spawn(async move {
 6072                let buffer_ranges = multi_buffer_snapshot
 6073                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6074                    .into_iter()
 6075                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6076                let mut match_ranges = Vec::new();
 6077                let Ok(regex) = project::search::SearchQuery::text(
 6078                    query_text.clone(),
 6079                    false,
 6080                    false,
 6081                    false,
 6082                    Default::default(),
 6083                    Default::default(),
 6084                    false,
 6085                    None,
 6086                ) else {
 6087                    return Vec::default();
 6088                };
 6089                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6090                    match_ranges.extend(
 6091                        regex
 6092                            .search(&buffer_snapshot, Some(search_range.clone()))
 6093                            .await
 6094                            .into_iter()
 6095                            .filter_map(|match_range| {
 6096                                let match_start = buffer_snapshot
 6097                                    .anchor_after(search_range.start + match_range.start);
 6098                                let match_end = buffer_snapshot
 6099                                    .anchor_before(search_range.start + match_range.end);
 6100                                let match_anchor_range = Anchor::range_in_buffer(
 6101                                    excerpt_id,
 6102                                    buffer_snapshot.remote_id(),
 6103                                    match_start..match_end,
 6104                                );
 6105                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6106                            }),
 6107                    );
 6108                }
 6109                match_ranges
 6110            });
 6111            let match_ranges = match_task.await;
 6112            editor
 6113                .update_in(cx, |editor, _, cx| {
 6114                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6115                    if !match_ranges.is_empty() {
 6116                        editor.highlight_background::<SelectedTextHighlight>(
 6117                            &match_ranges,
 6118                            |theme| theme.editor_document_highlight_bracket_background,
 6119                            cx,
 6120                        )
 6121                    }
 6122                })
 6123                .log_err();
 6124        })
 6125    }
 6126
 6127    fn refresh_selected_text_highlights(
 6128        &mut self,
 6129        on_buffer_edit: bool,
 6130        window: &mut Window,
 6131        cx: &mut Context<Editor>,
 6132    ) {
 6133        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6134        else {
 6135            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6136            self.quick_selection_highlight_task.take();
 6137            self.debounced_selection_highlight_task.take();
 6138            return;
 6139        };
 6140        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6141        if on_buffer_edit
 6142            || self
 6143                .quick_selection_highlight_task
 6144                .as_ref()
 6145                .map_or(true, |(prev_anchor_range, _)| {
 6146                    prev_anchor_range != &query_range
 6147                })
 6148        {
 6149            let multi_buffer_visible_start = self
 6150                .scroll_manager
 6151                .anchor()
 6152                .anchor
 6153                .to_point(&multi_buffer_snapshot);
 6154            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6155                multi_buffer_visible_start
 6156                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6157                Bias::Left,
 6158            );
 6159            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6160            self.quick_selection_highlight_task = Some((
 6161                query_range.clone(),
 6162                self.update_selection_occurrence_highlights(
 6163                    query_text.clone(),
 6164                    query_range.clone(),
 6165                    multi_buffer_visible_range,
 6166                    false,
 6167                    window,
 6168                    cx,
 6169                ),
 6170            ));
 6171        }
 6172        if on_buffer_edit
 6173            || self
 6174                .debounced_selection_highlight_task
 6175                .as_ref()
 6176                .map_or(true, |(prev_anchor_range, _)| {
 6177                    prev_anchor_range != &query_range
 6178                })
 6179        {
 6180            let multi_buffer_start = multi_buffer_snapshot
 6181                .anchor_before(0)
 6182                .to_point(&multi_buffer_snapshot);
 6183            let multi_buffer_end = multi_buffer_snapshot
 6184                .anchor_after(multi_buffer_snapshot.len())
 6185                .to_point(&multi_buffer_snapshot);
 6186            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6187            self.debounced_selection_highlight_task = Some((
 6188                query_range.clone(),
 6189                self.update_selection_occurrence_highlights(
 6190                    query_text,
 6191                    query_range,
 6192                    multi_buffer_full_range,
 6193                    true,
 6194                    window,
 6195                    cx,
 6196                ),
 6197            ));
 6198        }
 6199    }
 6200
 6201    pub fn refresh_inline_completion(
 6202        &mut self,
 6203        debounce: bool,
 6204        user_requested: bool,
 6205        window: &mut Window,
 6206        cx: &mut Context<Self>,
 6207    ) -> Option<()> {
 6208        let provider = self.edit_prediction_provider()?;
 6209        let cursor = self.selections.newest_anchor().head();
 6210        let (buffer, cursor_buffer_position) =
 6211            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6212
 6213        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6214            self.discard_inline_completion(false, cx);
 6215            return None;
 6216        }
 6217
 6218        if !user_requested
 6219            && (!self.should_show_edit_predictions()
 6220                || !self.is_focused(window)
 6221                || buffer.read(cx).is_empty())
 6222        {
 6223            self.discard_inline_completion(false, cx);
 6224            return None;
 6225        }
 6226
 6227        self.update_visible_inline_completion(window, cx);
 6228        provider.refresh(
 6229            self.project.clone(),
 6230            buffer,
 6231            cursor_buffer_position,
 6232            debounce,
 6233            cx,
 6234        );
 6235        Some(())
 6236    }
 6237
 6238    fn show_edit_predictions_in_menu(&self) -> bool {
 6239        match self.edit_prediction_settings {
 6240            EditPredictionSettings::Disabled => false,
 6241            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6242        }
 6243    }
 6244
 6245    pub fn edit_predictions_enabled(&self) -> bool {
 6246        match self.edit_prediction_settings {
 6247            EditPredictionSettings::Disabled => false,
 6248            EditPredictionSettings::Enabled { .. } => true,
 6249        }
 6250    }
 6251
 6252    fn edit_prediction_requires_modifier(&self) -> bool {
 6253        match self.edit_prediction_settings {
 6254            EditPredictionSettings::Disabled => false,
 6255            EditPredictionSettings::Enabled {
 6256                preview_requires_modifier,
 6257                ..
 6258            } => preview_requires_modifier,
 6259        }
 6260    }
 6261
 6262    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6263        if self.edit_prediction_provider.is_none() {
 6264            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6265        } else {
 6266            let selection = self.selections.newest_anchor();
 6267            let cursor = selection.head();
 6268
 6269            if let Some((buffer, cursor_buffer_position)) =
 6270                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6271            {
 6272                self.edit_prediction_settings =
 6273                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6274            }
 6275        }
 6276    }
 6277
 6278    fn edit_prediction_settings_at_position(
 6279        &self,
 6280        buffer: &Entity<Buffer>,
 6281        buffer_position: language::Anchor,
 6282        cx: &App,
 6283    ) -> EditPredictionSettings {
 6284        if !self.mode.is_full()
 6285            || !self.show_inline_completions_override.unwrap_or(true)
 6286            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6287        {
 6288            return EditPredictionSettings::Disabled;
 6289        }
 6290
 6291        let buffer = buffer.read(cx);
 6292
 6293        let file = buffer.file();
 6294
 6295        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6296            return EditPredictionSettings::Disabled;
 6297        };
 6298
 6299        let by_provider = matches!(
 6300            self.menu_inline_completions_policy,
 6301            MenuInlineCompletionsPolicy::ByProvider
 6302        );
 6303
 6304        let show_in_menu = by_provider
 6305            && self
 6306                .edit_prediction_provider
 6307                .as_ref()
 6308                .map_or(false, |provider| {
 6309                    provider.provider.show_completions_in_menu()
 6310                });
 6311
 6312        let preview_requires_modifier =
 6313            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6314
 6315        EditPredictionSettings::Enabled {
 6316            show_in_menu,
 6317            preview_requires_modifier,
 6318        }
 6319    }
 6320
 6321    fn should_show_edit_predictions(&self) -> bool {
 6322        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6323    }
 6324
 6325    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6326        matches!(
 6327            self.edit_prediction_preview,
 6328            EditPredictionPreview::Active { .. }
 6329        )
 6330    }
 6331
 6332    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6333        let cursor = self.selections.newest_anchor().head();
 6334        if let Some((buffer, cursor_position)) =
 6335            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6336        {
 6337            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6338        } else {
 6339            false
 6340        }
 6341    }
 6342
 6343    pub fn supports_minimap(&self, cx: &App) -> bool {
 6344        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6345    }
 6346
 6347    fn edit_predictions_enabled_in_buffer(
 6348        &self,
 6349        buffer: &Entity<Buffer>,
 6350        buffer_position: language::Anchor,
 6351        cx: &App,
 6352    ) -> bool {
 6353        maybe!({
 6354            if self.read_only(cx) {
 6355                return Some(false);
 6356            }
 6357            let provider = self.edit_prediction_provider()?;
 6358            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6359                return Some(false);
 6360            }
 6361            let buffer = buffer.read(cx);
 6362            let Some(file) = buffer.file() else {
 6363                return Some(true);
 6364            };
 6365            let settings = all_language_settings(Some(file), cx);
 6366            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6367        })
 6368        .unwrap_or(false)
 6369    }
 6370
 6371    fn cycle_inline_completion(
 6372        &mut self,
 6373        direction: Direction,
 6374        window: &mut Window,
 6375        cx: &mut Context<Self>,
 6376    ) -> Option<()> {
 6377        let provider = self.edit_prediction_provider()?;
 6378        let cursor = self.selections.newest_anchor().head();
 6379        let (buffer, cursor_buffer_position) =
 6380            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6381        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6382            return None;
 6383        }
 6384
 6385        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6386        self.update_visible_inline_completion(window, cx);
 6387
 6388        Some(())
 6389    }
 6390
 6391    pub fn show_inline_completion(
 6392        &mut self,
 6393        _: &ShowEditPrediction,
 6394        window: &mut Window,
 6395        cx: &mut Context<Self>,
 6396    ) {
 6397        if !self.has_active_inline_completion() {
 6398            self.refresh_inline_completion(false, true, window, cx);
 6399            return;
 6400        }
 6401
 6402        self.update_visible_inline_completion(window, cx);
 6403    }
 6404
 6405    pub fn display_cursor_names(
 6406        &mut self,
 6407        _: &DisplayCursorNames,
 6408        window: &mut Window,
 6409        cx: &mut Context<Self>,
 6410    ) {
 6411        self.show_cursor_names(window, cx);
 6412    }
 6413
 6414    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6415        self.show_cursor_names = true;
 6416        cx.notify();
 6417        cx.spawn_in(window, async move |this, cx| {
 6418            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6419            this.update(cx, |this, cx| {
 6420                this.show_cursor_names = false;
 6421                cx.notify()
 6422            })
 6423            .ok()
 6424        })
 6425        .detach();
 6426    }
 6427
 6428    pub fn next_edit_prediction(
 6429        &mut self,
 6430        _: &NextEditPrediction,
 6431        window: &mut Window,
 6432        cx: &mut Context<Self>,
 6433    ) {
 6434        if self.has_active_inline_completion() {
 6435            self.cycle_inline_completion(Direction::Next, window, cx);
 6436        } else {
 6437            let is_copilot_disabled = self
 6438                .refresh_inline_completion(false, true, window, cx)
 6439                .is_none();
 6440            if is_copilot_disabled {
 6441                cx.propagate();
 6442            }
 6443        }
 6444    }
 6445
 6446    pub fn previous_edit_prediction(
 6447        &mut self,
 6448        _: &PreviousEditPrediction,
 6449        window: &mut Window,
 6450        cx: &mut Context<Self>,
 6451    ) {
 6452        if self.has_active_inline_completion() {
 6453            self.cycle_inline_completion(Direction::Prev, window, cx);
 6454        } else {
 6455            let is_copilot_disabled = self
 6456                .refresh_inline_completion(false, true, window, cx)
 6457                .is_none();
 6458            if is_copilot_disabled {
 6459                cx.propagate();
 6460            }
 6461        }
 6462    }
 6463
 6464    pub fn accept_edit_prediction(
 6465        &mut self,
 6466        _: &AcceptEditPrediction,
 6467        window: &mut Window,
 6468        cx: &mut Context<Self>,
 6469    ) {
 6470        if self.show_edit_predictions_in_menu() {
 6471            self.hide_context_menu(window, cx);
 6472        }
 6473
 6474        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6475            return;
 6476        };
 6477
 6478        self.report_inline_completion_event(
 6479            active_inline_completion.completion_id.clone(),
 6480            true,
 6481            cx,
 6482        );
 6483
 6484        match &active_inline_completion.completion {
 6485            InlineCompletion::Move { target, .. } => {
 6486                let target = *target;
 6487
 6488                if let Some(position_map) = &self.last_position_map {
 6489                    if position_map
 6490                        .visible_row_range
 6491                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6492                        || !self.edit_prediction_requires_modifier()
 6493                    {
 6494                        self.unfold_ranges(&[target..target], true, false, cx);
 6495                        // Note that this is also done in vim's handler of the Tab action.
 6496                        self.change_selections(
 6497                            Some(Autoscroll::newest()),
 6498                            window,
 6499                            cx,
 6500                            |selections| {
 6501                                selections.select_anchor_ranges([target..target]);
 6502                            },
 6503                        );
 6504                        self.clear_row_highlights::<EditPredictionPreview>();
 6505
 6506                        self.edit_prediction_preview
 6507                            .set_previous_scroll_position(None);
 6508                    } else {
 6509                        self.edit_prediction_preview
 6510                            .set_previous_scroll_position(Some(
 6511                                position_map.snapshot.scroll_anchor,
 6512                            ));
 6513
 6514                        self.highlight_rows::<EditPredictionPreview>(
 6515                            target..target,
 6516                            cx.theme().colors().editor_highlighted_line_background,
 6517                            RowHighlightOptions {
 6518                                autoscroll: true,
 6519                                ..Default::default()
 6520                            },
 6521                            cx,
 6522                        );
 6523                        self.request_autoscroll(Autoscroll::fit(), cx);
 6524                    }
 6525                }
 6526            }
 6527            InlineCompletion::Edit { edits, .. } => {
 6528                if let Some(provider) = self.edit_prediction_provider() {
 6529                    provider.accept(cx);
 6530                }
 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                self.update_visible_inline_completion(window, cx);
 6544                if self.active_inline_completion.is_none() {
 6545                    self.refresh_inline_completion(true, true, window, cx);
 6546                }
 6547
 6548                cx.notify();
 6549            }
 6550        }
 6551
 6552        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6553    }
 6554
 6555    pub fn accept_partial_inline_completion(
 6556        &mut self,
 6557        _: &AcceptPartialEditPrediction,
 6558        window: &mut Window,
 6559        cx: &mut Context<Self>,
 6560    ) {
 6561        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6562            return;
 6563        };
 6564        if self.selections.count() != 1 {
 6565            return;
 6566        }
 6567
 6568        self.report_inline_completion_event(
 6569            active_inline_completion.completion_id.clone(),
 6570            true,
 6571            cx,
 6572        );
 6573
 6574        match &active_inline_completion.completion {
 6575            InlineCompletion::Move { target, .. } => {
 6576                let target = *target;
 6577                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6578                    selections.select_anchor_ranges([target..target]);
 6579                });
 6580            }
 6581            InlineCompletion::Edit { edits, .. } => {
 6582                // Find an insertion that starts at the cursor position.
 6583                let snapshot = self.buffer.read(cx).snapshot(cx);
 6584                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6585                let insertion = edits.iter().find_map(|(range, text)| {
 6586                    let range = range.to_offset(&snapshot);
 6587                    if range.is_empty() && range.start == cursor_offset {
 6588                        Some(text)
 6589                    } else {
 6590                        None
 6591                    }
 6592                });
 6593
 6594                if let Some(text) = insertion {
 6595                    let mut partial_completion = text
 6596                        .chars()
 6597                        .by_ref()
 6598                        .take_while(|c| c.is_alphabetic())
 6599                        .collect::<String>();
 6600                    if partial_completion.is_empty() {
 6601                        partial_completion = text
 6602                            .chars()
 6603                            .by_ref()
 6604                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6605                            .collect::<String>();
 6606                    }
 6607
 6608                    cx.emit(EditorEvent::InputHandled {
 6609                        utf16_range_to_replace: None,
 6610                        text: partial_completion.clone().into(),
 6611                    });
 6612
 6613                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6614
 6615                    self.refresh_inline_completion(true, true, window, cx);
 6616                    cx.notify();
 6617                } else {
 6618                    self.accept_edit_prediction(&Default::default(), window, cx);
 6619                }
 6620            }
 6621        }
 6622    }
 6623
 6624    fn discard_inline_completion(
 6625        &mut self,
 6626        should_report_inline_completion_event: bool,
 6627        cx: &mut Context<Self>,
 6628    ) -> bool {
 6629        if should_report_inline_completion_event {
 6630            let completion_id = self
 6631                .active_inline_completion
 6632                .as_ref()
 6633                .and_then(|active_completion| active_completion.completion_id.clone());
 6634
 6635            self.report_inline_completion_event(completion_id, false, cx);
 6636        }
 6637
 6638        if let Some(provider) = self.edit_prediction_provider() {
 6639            provider.discard(cx);
 6640        }
 6641
 6642        self.take_active_inline_completion(cx)
 6643    }
 6644
 6645    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6646        let Some(provider) = self.edit_prediction_provider() else {
 6647            return;
 6648        };
 6649
 6650        let Some((_, buffer, _)) = self
 6651            .buffer
 6652            .read(cx)
 6653            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6654        else {
 6655            return;
 6656        };
 6657
 6658        let extension = buffer
 6659            .read(cx)
 6660            .file()
 6661            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6662
 6663        let event_type = match accepted {
 6664            true => "Edit Prediction Accepted",
 6665            false => "Edit Prediction Discarded",
 6666        };
 6667        telemetry::event!(
 6668            event_type,
 6669            provider = provider.name(),
 6670            prediction_id = id,
 6671            suggestion_accepted = accepted,
 6672            file_extension = extension,
 6673        );
 6674    }
 6675
 6676    pub fn has_active_inline_completion(&self) -> bool {
 6677        self.active_inline_completion.is_some()
 6678    }
 6679
 6680    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6681        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6682            return false;
 6683        };
 6684
 6685        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6686        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6687        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6688        true
 6689    }
 6690
 6691    /// Returns true when we're displaying the edit prediction popover below the cursor
 6692    /// like we are not previewing and the LSP autocomplete menu is visible
 6693    /// or we are in `when_holding_modifier` mode.
 6694    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6695        if self.edit_prediction_preview_is_active()
 6696            || !self.show_edit_predictions_in_menu()
 6697            || !self.edit_predictions_enabled()
 6698        {
 6699            return false;
 6700        }
 6701
 6702        if self.has_visible_completions_menu() {
 6703            return true;
 6704        }
 6705
 6706        has_completion && self.edit_prediction_requires_modifier()
 6707    }
 6708
 6709    fn handle_modifiers_changed(
 6710        &mut self,
 6711        modifiers: Modifiers,
 6712        position_map: &PositionMap,
 6713        window: &mut Window,
 6714        cx: &mut Context<Self>,
 6715    ) {
 6716        if self.show_edit_predictions_in_menu() {
 6717            self.update_edit_prediction_preview(&modifiers, window, cx);
 6718        }
 6719
 6720        self.update_selection_mode(&modifiers, position_map, window, cx);
 6721
 6722        let mouse_position = window.mouse_position();
 6723        if !position_map.text_hitbox.is_hovered(window) {
 6724            return;
 6725        }
 6726
 6727        self.update_hovered_link(
 6728            position_map.point_for_position(mouse_position),
 6729            &position_map.snapshot,
 6730            modifiers,
 6731            window,
 6732            cx,
 6733        )
 6734    }
 6735
 6736    fn update_selection_mode(
 6737        &mut self,
 6738        modifiers: &Modifiers,
 6739        position_map: &PositionMap,
 6740        window: &mut Window,
 6741        cx: &mut Context<Self>,
 6742    ) {
 6743        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6744            return;
 6745        }
 6746
 6747        let mouse_position = window.mouse_position();
 6748        let point_for_position = position_map.point_for_position(mouse_position);
 6749        let position = point_for_position.previous_valid;
 6750
 6751        self.select(
 6752            SelectPhase::BeginColumnar {
 6753                position,
 6754                reset: false,
 6755                goal_column: point_for_position.exact_unclipped.column(),
 6756            },
 6757            window,
 6758            cx,
 6759        );
 6760    }
 6761
 6762    fn update_edit_prediction_preview(
 6763        &mut self,
 6764        modifiers: &Modifiers,
 6765        window: &mut Window,
 6766        cx: &mut Context<Self>,
 6767    ) {
 6768        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6769        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6770            return;
 6771        };
 6772
 6773        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6774            if matches!(
 6775                self.edit_prediction_preview,
 6776                EditPredictionPreview::Inactive { .. }
 6777            ) {
 6778                self.edit_prediction_preview = EditPredictionPreview::Active {
 6779                    previous_scroll_position: None,
 6780                    since: Instant::now(),
 6781                };
 6782
 6783                self.update_visible_inline_completion(window, cx);
 6784                cx.notify();
 6785            }
 6786        } else if let EditPredictionPreview::Active {
 6787            previous_scroll_position,
 6788            since,
 6789        } = self.edit_prediction_preview
 6790        {
 6791            if let (Some(previous_scroll_position), Some(position_map)) =
 6792                (previous_scroll_position, self.last_position_map.as_ref())
 6793            {
 6794                self.set_scroll_position(
 6795                    previous_scroll_position
 6796                        .scroll_position(&position_map.snapshot.display_snapshot),
 6797                    window,
 6798                    cx,
 6799                );
 6800            }
 6801
 6802            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6803                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6804            };
 6805            self.clear_row_highlights::<EditPredictionPreview>();
 6806            self.update_visible_inline_completion(window, cx);
 6807            cx.notify();
 6808        }
 6809    }
 6810
 6811    fn update_visible_inline_completion(
 6812        &mut self,
 6813        _window: &mut Window,
 6814        cx: &mut Context<Self>,
 6815    ) -> Option<()> {
 6816        let selection = self.selections.newest_anchor();
 6817        let cursor = selection.head();
 6818        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6819        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6820        let excerpt_id = cursor.excerpt_id;
 6821
 6822        let show_in_menu = self.show_edit_predictions_in_menu();
 6823        let completions_menu_has_precedence = !show_in_menu
 6824            && (self.context_menu.borrow().is_some()
 6825                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6826
 6827        if completions_menu_has_precedence
 6828            || !offset_selection.is_empty()
 6829            || self
 6830                .active_inline_completion
 6831                .as_ref()
 6832                .map_or(false, |completion| {
 6833                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6834                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6835                    !invalidation_range.contains(&offset_selection.head())
 6836                })
 6837        {
 6838            self.discard_inline_completion(false, cx);
 6839            return None;
 6840        }
 6841
 6842        self.take_active_inline_completion(cx);
 6843        let Some(provider) = self.edit_prediction_provider() else {
 6844            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6845            return None;
 6846        };
 6847
 6848        let (buffer, cursor_buffer_position) =
 6849            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6850
 6851        self.edit_prediction_settings =
 6852            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6853
 6854        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6855
 6856        if self.edit_prediction_indent_conflict {
 6857            let cursor_point = cursor.to_point(&multibuffer);
 6858
 6859            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6860
 6861            if let Some((_, indent)) = indents.iter().next() {
 6862                if indent.len == cursor_point.column {
 6863                    self.edit_prediction_indent_conflict = false;
 6864                }
 6865            }
 6866        }
 6867
 6868        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6869        let edits = inline_completion
 6870            .edits
 6871            .into_iter()
 6872            .flat_map(|(range, new_text)| {
 6873                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6874                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6875                Some((start..end, new_text))
 6876            })
 6877            .collect::<Vec<_>>();
 6878        if edits.is_empty() {
 6879            return None;
 6880        }
 6881
 6882        let first_edit_start = edits.first().unwrap().0.start;
 6883        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6884        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6885
 6886        let last_edit_end = edits.last().unwrap().0.end;
 6887        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6888        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6889
 6890        let cursor_row = cursor.to_point(&multibuffer).row;
 6891
 6892        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6893
 6894        let mut inlay_ids = Vec::new();
 6895        let invalidation_row_range;
 6896        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6897            Some(cursor_row..edit_end_row)
 6898        } else if cursor_row > edit_end_row {
 6899            Some(edit_start_row..cursor_row)
 6900        } else {
 6901            None
 6902        };
 6903        let is_move =
 6904            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6905        let completion = if is_move {
 6906            invalidation_row_range =
 6907                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6908            let target = first_edit_start;
 6909            InlineCompletion::Move { target, snapshot }
 6910        } else {
 6911            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6912                && !self.inline_completions_hidden_for_vim_mode;
 6913
 6914            if show_completions_in_buffer {
 6915                if edits
 6916                    .iter()
 6917                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6918                {
 6919                    let mut inlays = Vec::new();
 6920                    for (range, new_text) in &edits {
 6921                        let inlay = Inlay::inline_completion(
 6922                            post_inc(&mut self.next_inlay_id),
 6923                            range.start,
 6924                            new_text.as_str(),
 6925                        );
 6926                        inlay_ids.push(inlay.id);
 6927                        inlays.push(inlay);
 6928                    }
 6929
 6930                    self.splice_inlays(&[], inlays, cx);
 6931                } else {
 6932                    let background_color = cx.theme().status().deleted_background;
 6933                    self.highlight_text::<InlineCompletionHighlight>(
 6934                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6935                        HighlightStyle {
 6936                            background_color: Some(background_color),
 6937                            ..Default::default()
 6938                        },
 6939                        cx,
 6940                    );
 6941                }
 6942            }
 6943
 6944            invalidation_row_range = edit_start_row..edit_end_row;
 6945
 6946            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6947                if provider.show_tab_accept_marker() {
 6948                    EditDisplayMode::TabAccept
 6949                } else {
 6950                    EditDisplayMode::Inline
 6951                }
 6952            } else {
 6953                EditDisplayMode::DiffPopover
 6954            };
 6955
 6956            InlineCompletion::Edit {
 6957                edits,
 6958                edit_preview: inline_completion.edit_preview,
 6959                display_mode,
 6960                snapshot,
 6961            }
 6962        };
 6963
 6964        let invalidation_range = multibuffer
 6965            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6966            ..multibuffer.anchor_after(Point::new(
 6967                invalidation_row_range.end,
 6968                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6969            ));
 6970
 6971        self.stale_inline_completion_in_menu = None;
 6972        self.active_inline_completion = Some(InlineCompletionState {
 6973            inlay_ids,
 6974            completion,
 6975            completion_id: inline_completion.id,
 6976            invalidation_range,
 6977        });
 6978
 6979        cx.notify();
 6980
 6981        Some(())
 6982    }
 6983
 6984    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6985        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6986    }
 6987
 6988    fn clear_tasks(&mut self) {
 6989        self.tasks.clear()
 6990    }
 6991
 6992    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 6993        if self.tasks.insert(key, value).is_some() {
 6994            // This case should hopefully be rare, but just in case...
 6995            log::error!(
 6996                "multiple different run targets found on a single line, only the last target will be rendered"
 6997            )
 6998        }
 6999    }
 7000
 7001    /// Get all display points of breakpoints that will be rendered within editor
 7002    ///
 7003    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7004    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7005    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7006    fn active_breakpoints(
 7007        &self,
 7008        range: Range<DisplayRow>,
 7009        window: &mut Window,
 7010        cx: &mut Context<Self>,
 7011    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7012        let mut breakpoint_display_points = HashMap::default();
 7013
 7014        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7015            return breakpoint_display_points;
 7016        };
 7017
 7018        let snapshot = self.snapshot(window, cx);
 7019
 7020        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7021        let Some(project) = self.project.as_ref() else {
 7022            return breakpoint_display_points;
 7023        };
 7024
 7025        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7026            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7027
 7028        for (buffer_snapshot, range, excerpt_id) in
 7029            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7030        {
 7031            let Some(buffer) = project.read_with(cx, |this, cx| {
 7032                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7033            }) else {
 7034                continue;
 7035            };
 7036            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7037                &buffer,
 7038                Some(
 7039                    buffer_snapshot.anchor_before(range.start)
 7040                        ..buffer_snapshot.anchor_after(range.end),
 7041                ),
 7042                buffer_snapshot,
 7043                cx,
 7044            );
 7045            for (breakpoint, state) in breakpoints {
 7046                let multi_buffer_anchor =
 7047                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7048                let position = multi_buffer_anchor
 7049                    .to_point(&multi_buffer_snapshot)
 7050                    .to_display_point(&snapshot);
 7051
 7052                breakpoint_display_points.insert(
 7053                    position.row(),
 7054                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7055                );
 7056            }
 7057        }
 7058
 7059        breakpoint_display_points
 7060    }
 7061
 7062    fn breakpoint_context_menu(
 7063        &self,
 7064        anchor: Anchor,
 7065        window: &mut Window,
 7066        cx: &mut Context<Self>,
 7067    ) -> Entity<ui::ContextMenu> {
 7068        let weak_editor = cx.weak_entity();
 7069        let focus_handle = self.focus_handle(cx);
 7070
 7071        let row = self
 7072            .buffer
 7073            .read(cx)
 7074            .snapshot(cx)
 7075            .summary_for_anchor::<Point>(&anchor)
 7076            .row;
 7077
 7078        let breakpoint = self
 7079            .breakpoint_at_row(row, window, cx)
 7080            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7081
 7082        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7083            "Edit Log Breakpoint"
 7084        } else {
 7085            "Set Log Breakpoint"
 7086        };
 7087
 7088        let condition_breakpoint_msg = if breakpoint
 7089            .as_ref()
 7090            .is_some_and(|bp| bp.1.condition.is_some())
 7091        {
 7092            "Edit Condition Breakpoint"
 7093        } else {
 7094            "Set Condition Breakpoint"
 7095        };
 7096
 7097        let hit_condition_breakpoint_msg = if breakpoint
 7098            .as_ref()
 7099            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7100        {
 7101            "Edit Hit Condition Breakpoint"
 7102        } else {
 7103            "Set Hit Condition Breakpoint"
 7104        };
 7105
 7106        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7107            "Unset Breakpoint"
 7108        } else {
 7109            "Set Breakpoint"
 7110        };
 7111
 7112        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7113            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7114
 7115        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7116            BreakpointState::Enabled => Some("Disable"),
 7117            BreakpointState::Disabled => Some("Enable"),
 7118        });
 7119
 7120        let (anchor, breakpoint) =
 7121            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7122
 7123        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7124            menu.on_blur_subscription(Subscription::new(|| {}))
 7125                .context(focus_handle)
 7126                .when(run_to_cursor, |this| {
 7127                    let weak_editor = weak_editor.clone();
 7128                    this.entry("Run to cursor", None, move |window, cx| {
 7129                        weak_editor
 7130                            .update(cx, |editor, cx| {
 7131                                editor.change_selections(None, window, cx, |s| {
 7132                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7133                                });
 7134                            })
 7135                            .ok();
 7136
 7137                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7138                    })
 7139                    .separator()
 7140                })
 7141                .when_some(toggle_state_msg, |this, msg| {
 7142                    this.entry(msg, None, {
 7143                        let weak_editor = weak_editor.clone();
 7144                        let breakpoint = breakpoint.clone();
 7145                        move |_window, cx| {
 7146                            weak_editor
 7147                                .update(cx, |this, cx| {
 7148                                    this.edit_breakpoint_at_anchor(
 7149                                        anchor,
 7150                                        breakpoint.as_ref().clone(),
 7151                                        BreakpointEditAction::InvertState,
 7152                                        cx,
 7153                                    );
 7154                                })
 7155                                .log_err();
 7156                        }
 7157                    })
 7158                })
 7159                .entry(set_breakpoint_msg, None, {
 7160                    let weak_editor = weak_editor.clone();
 7161                    let breakpoint = breakpoint.clone();
 7162                    move |_window, cx| {
 7163                        weak_editor
 7164                            .update(cx, |this, cx| {
 7165                                this.edit_breakpoint_at_anchor(
 7166                                    anchor,
 7167                                    breakpoint.as_ref().clone(),
 7168                                    BreakpointEditAction::Toggle,
 7169                                    cx,
 7170                                );
 7171                            })
 7172                            .log_err();
 7173                    }
 7174                })
 7175                .entry(log_breakpoint_msg, None, {
 7176                    let breakpoint = breakpoint.clone();
 7177                    let weak_editor = weak_editor.clone();
 7178                    move |window, cx| {
 7179                        weak_editor
 7180                            .update(cx, |this, cx| {
 7181                                this.add_edit_breakpoint_block(
 7182                                    anchor,
 7183                                    breakpoint.as_ref(),
 7184                                    BreakpointPromptEditAction::Log,
 7185                                    window,
 7186                                    cx,
 7187                                );
 7188                            })
 7189                            .log_err();
 7190                    }
 7191                })
 7192                .entry(condition_breakpoint_msg, None, {
 7193                    let breakpoint = breakpoint.clone();
 7194                    let weak_editor = weak_editor.clone();
 7195                    move |window, cx| {
 7196                        weak_editor
 7197                            .update(cx, |this, cx| {
 7198                                this.add_edit_breakpoint_block(
 7199                                    anchor,
 7200                                    breakpoint.as_ref(),
 7201                                    BreakpointPromptEditAction::Condition,
 7202                                    window,
 7203                                    cx,
 7204                                );
 7205                            })
 7206                            .log_err();
 7207                    }
 7208                })
 7209                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7210                    weak_editor
 7211                        .update(cx, |this, cx| {
 7212                            this.add_edit_breakpoint_block(
 7213                                anchor,
 7214                                breakpoint.as_ref(),
 7215                                BreakpointPromptEditAction::HitCondition,
 7216                                window,
 7217                                cx,
 7218                            );
 7219                        })
 7220                        .log_err();
 7221                })
 7222        })
 7223    }
 7224
 7225    fn render_breakpoint(
 7226        &self,
 7227        position: Anchor,
 7228        row: DisplayRow,
 7229        breakpoint: &Breakpoint,
 7230        state: Option<BreakpointSessionState>,
 7231        cx: &mut Context<Self>,
 7232    ) -> IconButton {
 7233        let is_rejected = state.is_some_and(|s| !s.verified);
 7234        // Is it a breakpoint that shows up when hovering over gutter?
 7235        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7236            (false, false),
 7237            |PhantomBreakpointIndicator {
 7238                 is_active,
 7239                 display_row,
 7240                 collides_with_existing_breakpoint,
 7241             }| {
 7242                (
 7243                    is_active && display_row == row,
 7244                    collides_with_existing_breakpoint,
 7245                )
 7246            },
 7247        );
 7248
 7249        let (color, icon) = {
 7250            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7251                (false, false) => ui::IconName::DebugBreakpoint,
 7252                (true, false) => ui::IconName::DebugLogBreakpoint,
 7253                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7254                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7255            };
 7256
 7257            let color = if is_phantom {
 7258                Color::Hint
 7259            } else if is_rejected {
 7260                Color::Disabled
 7261            } else {
 7262                Color::Debugger
 7263            };
 7264
 7265            (color, icon)
 7266        };
 7267
 7268        let breakpoint = Arc::from(breakpoint.clone());
 7269
 7270        let alt_as_text = gpui::Keystroke {
 7271            modifiers: Modifiers::secondary_key(),
 7272            ..Default::default()
 7273        };
 7274        let primary_action_text = if breakpoint.is_disabled() {
 7275            "Enable breakpoint"
 7276        } else if is_phantom && !collides_with_existing {
 7277            "Set breakpoint"
 7278        } else {
 7279            "Unset breakpoint"
 7280        };
 7281        let focus_handle = self.focus_handle.clone();
 7282
 7283        let meta = if is_rejected {
 7284            SharedString::from("No executable code is associated with this line.")
 7285        } else if collides_with_existing && !breakpoint.is_disabled() {
 7286            SharedString::from(format!(
 7287                "{alt_as_text}-click to disable,\nright-click for more options."
 7288            ))
 7289        } else {
 7290            SharedString::from("Right-click for more options.")
 7291        };
 7292        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7293            .icon_size(IconSize::XSmall)
 7294            .size(ui::ButtonSize::None)
 7295            .when(is_rejected, |this| {
 7296                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7297            })
 7298            .icon_color(color)
 7299            .style(ButtonStyle::Transparent)
 7300            .on_click(cx.listener({
 7301                let breakpoint = breakpoint.clone();
 7302
 7303                move |editor, event: &ClickEvent, window, cx| {
 7304                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7305                        BreakpointEditAction::InvertState
 7306                    } else {
 7307                        BreakpointEditAction::Toggle
 7308                    };
 7309
 7310                    window.focus(&editor.focus_handle(cx));
 7311                    editor.edit_breakpoint_at_anchor(
 7312                        position,
 7313                        breakpoint.as_ref().clone(),
 7314                        edit_action,
 7315                        cx,
 7316                    );
 7317                }
 7318            }))
 7319            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7320                editor.set_breakpoint_context_menu(
 7321                    row,
 7322                    Some(position),
 7323                    event.down.position,
 7324                    window,
 7325                    cx,
 7326                );
 7327            }))
 7328            .tooltip(move |window, cx| {
 7329                Tooltip::with_meta_in(
 7330                    primary_action_text,
 7331                    Some(&ToggleBreakpoint),
 7332                    meta.clone(),
 7333                    &focus_handle,
 7334                    window,
 7335                    cx,
 7336                )
 7337            })
 7338    }
 7339
 7340    fn build_tasks_context(
 7341        project: &Entity<Project>,
 7342        buffer: &Entity<Buffer>,
 7343        buffer_row: u32,
 7344        tasks: &Arc<RunnableTasks>,
 7345        cx: &mut Context<Self>,
 7346    ) -> Task<Option<task::TaskContext>> {
 7347        let position = Point::new(buffer_row, tasks.column);
 7348        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7349        let location = Location {
 7350            buffer: buffer.clone(),
 7351            range: range_start..range_start,
 7352        };
 7353        // Fill in the environmental variables from the tree-sitter captures
 7354        let mut captured_task_variables = TaskVariables::default();
 7355        for (capture_name, value) in tasks.extra_variables.clone() {
 7356            captured_task_variables.insert(
 7357                task::VariableName::Custom(capture_name.into()),
 7358                value.clone(),
 7359            );
 7360        }
 7361        project.update(cx, |project, cx| {
 7362            project.task_store().update(cx, |task_store, cx| {
 7363                task_store.task_context_for_location(captured_task_variables, location, cx)
 7364            })
 7365        })
 7366    }
 7367
 7368    pub fn spawn_nearest_task(
 7369        &mut self,
 7370        action: &SpawnNearestTask,
 7371        window: &mut Window,
 7372        cx: &mut Context<Self>,
 7373    ) {
 7374        let Some((workspace, _)) = self.workspace.clone() else {
 7375            return;
 7376        };
 7377        let Some(project) = self.project.clone() else {
 7378            return;
 7379        };
 7380
 7381        // Try to find a closest, enclosing node using tree-sitter that has a
 7382        // task
 7383        let Some((buffer, buffer_row, tasks)) = self
 7384            .find_enclosing_node_task(cx)
 7385            // Or find the task that's closest in row-distance.
 7386            .or_else(|| self.find_closest_task(cx))
 7387        else {
 7388            return;
 7389        };
 7390
 7391        let reveal_strategy = action.reveal;
 7392        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7393        cx.spawn_in(window, async move |_, cx| {
 7394            let context = task_context.await?;
 7395            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7396
 7397            let resolved = &mut resolved_task.resolved;
 7398            resolved.reveal = reveal_strategy;
 7399
 7400            workspace
 7401                .update_in(cx, |workspace, window, cx| {
 7402                    workspace.schedule_resolved_task(
 7403                        task_source_kind,
 7404                        resolved_task,
 7405                        false,
 7406                        window,
 7407                        cx,
 7408                    );
 7409                })
 7410                .ok()
 7411        })
 7412        .detach();
 7413    }
 7414
 7415    fn find_closest_task(
 7416        &mut self,
 7417        cx: &mut Context<Self>,
 7418    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7419        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7420
 7421        let ((buffer_id, row), tasks) = self
 7422            .tasks
 7423            .iter()
 7424            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7425
 7426        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7427        let tasks = Arc::new(tasks.to_owned());
 7428        Some((buffer, *row, tasks))
 7429    }
 7430
 7431    fn find_enclosing_node_task(
 7432        &mut self,
 7433        cx: &mut Context<Self>,
 7434    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7435        let snapshot = self.buffer.read(cx).snapshot(cx);
 7436        let offset = self.selections.newest::<usize>(cx).head();
 7437        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7438        let buffer_id = excerpt.buffer().remote_id();
 7439
 7440        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7441        let mut cursor = layer.node().walk();
 7442
 7443        while cursor.goto_first_child_for_byte(offset).is_some() {
 7444            if cursor.node().end_byte() == offset {
 7445                cursor.goto_next_sibling();
 7446            }
 7447        }
 7448
 7449        // Ascend to the smallest ancestor that contains the range and has a task.
 7450        loop {
 7451            let node = cursor.node();
 7452            let node_range = node.byte_range();
 7453            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7454
 7455            // Check if this node contains our offset
 7456            if node_range.start <= offset && node_range.end >= offset {
 7457                // If it contains offset, check for task
 7458                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7459                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7460                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7461                }
 7462            }
 7463
 7464            if !cursor.goto_parent() {
 7465                break;
 7466            }
 7467        }
 7468        None
 7469    }
 7470
 7471    fn render_run_indicator(
 7472        &self,
 7473        _style: &EditorStyle,
 7474        is_active: bool,
 7475        row: DisplayRow,
 7476        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7477        cx: &mut Context<Self>,
 7478    ) -> IconButton {
 7479        let color = Color::Muted;
 7480        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7481
 7482        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7483            .shape(ui::IconButtonShape::Square)
 7484            .icon_size(IconSize::XSmall)
 7485            .icon_color(color)
 7486            .toggle_state(is_active)
 7487            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7488                let quick_launch = e.down.button == MouseButton::Left;
 7489                window.focus(&editor.focus_handle(cx));
 7490                editor.toggle_code_actions(
 7491                    &ToggleCodeActions {
 7492                        deployed_from_indicator: Some(row),
 7493                        quick_launch,
 7494                    },
 7495                    window,
 7496                    cx,
 7497                );
 7498            }))
 7499            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7500                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7501            }))
 7502    }
 7503
 7504    pub fn context_menu_visible(&self) -> bool {
 7505        !self.edit_prediction_preview_is_active()
 7506            && self
 7507                .context_menu
 7508                .borrow()
 7509                .as_ref()
 7510                .map_or(false, |menu| menu.visible())
 7511    }
 7512
 7513    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7514        self.context_menu
 7515            .borrow()
 7516            .as_ref()
 7517            .map(|menu| menu.origin())
 7518    }
 7519
 7520    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7521        self.context_menu_options = Some(options);
 7522    }
 7523
 7524    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7525    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7526
 7527    fn render_edit_prediction_popover(
 7528        &mut self,
 7529        text_bounds: &Bounds<Pixels>,
 7530        content_origin: gpui::Point<Pixels>,
 7531        right_margin: Pixels,
 7532        editor_snapshot: &EditorSnapshot,
 7533        visible_row_range: Range<DisplayRow>,
 7534        scroll_top: f32,
 7535        scroll_bottom: f32,
 7536        line_layouts: &[LineWithInvisibles],
 7537        line_height: Pixels,
 7538        scroll_pixel_position: gpui::Point<Pixels>,
 7539        newest_selection_head: Option<DisplayPoint>,
 7540        editor_width: Pixels,
 7541        style: &EditorStyle,
 7542        window: &mut Window,
 7543        cx: &mut App,
 7544    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7545        if self.mode().is_minimap() {
 7546            return None;
 7547        }
 7548        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7549
 7550        if self.edit_prediction_visible_in_cursor_popover(true) {
 7551            return None;
 7552        }
 7553
 7554        match &active_inline_completion.completion {
 7555            InlineCompletion::Move { target, .. } => {
 7556                let target_display_point = target.to_display_point(editor_snapshot);
 7557
 7558                if self.edit_prediction_requires_modifier() {
 7559                    if !self.edit_prediction_preview_is_active() {
 7560                        return None;
 7561                    }
 7562
 7563                    self.render_edit_prediction_modifier_jump_popover(
 7564                        text_bounds,
 7565                        content_origin,
 7566                        visible_row_range,
 7567                        line_layouts,
 7568                        line_height,
 7569                        scroll_pixel_position,
 7570                        newest_selection_head,
 7571                        target_display_point,
 7572                        window,
 7573                        cx,
 7574                    )
 7575                } else {
 7576                    self.render_edit_prediction_eager_jump_popover(
 7577                        text_bounds,
 7578                        content_origin,
 7579                        editor_snapshot,
 7580                        visible_row_range,
 7581                        scroll_top,
 7582                        scroll_bottom,
 7583                        line_height,
 7584                        scroll_pixel_position,
 7585                        target_display_point,
 7586                        editor_width,
 7587                        window,
 7588                        cx,
 7589                    )
 7590                }
 7591            }
 7592            InlineCompletion::Edit {
 7593                display_mode: EditDisplayMode::Inline,
 7594                ..
 7595            } => None,
 7596            InlineCompletion::Edit {
 7597                display_mode: EditDisplayMode::TabAccept,
 7598                edits,
 7599                ..
 7600            } => {
 7601                let range = &edits.first()?.0;
 7602                let target_display_point = range.end.to_display_point(editor_snapshot);
 7603
 7604                self.render_edit_prediction_end_of_line_popover(
 7605                    "Accept",
 7606                    editor_snapshot,
 7607                    visible_row_range,
 7608                    target_display_point,
 7609                    line_height,
 7610                    scroll_pixel_position,
 7611                    content_origin,
 7612                    editor_width,
 7613                    window,
 7614                    cx,
 7615                )
 7616            }
 7617            InlineCompletion::Edit {
 7618                edits,
 7619                edit_preview,
 7620                display_mode: EditDisplayMode::DiffPopover,
 7621                snapshot,
 7622            } => self.render_edit_prediction_diff_popover(
 7623                text_bounds,
 7624                content_origin,
 7625                right_margin,
 7626                editor_snapshot,
 7627                visible_row_range,
 7628                line_layouts,
 7629                line_height,
 7630                scroll_pixel_position,
 7631                newest_selection_head,
 7632                editor_width,
 7633                style,
 7634                edits,
 7635                edit_preview,
 7636                snapshot,
 7637                window,
 7638                cx,
 7639            ),
 7640        }
 7641    }
 7642
 7643    fn render_edit_prediction_modifier_jump_popover(
 7644        &mut self,
 7645        text_bounds: &Bounds<Pixels>,
 7646        content_origin: gpui::Point<Pixels>,
 7647        visible_row_range: Range<DisplayRow>,
 7648        line_layouts: &[LineWithInvisibles],
 7649        line_height: Pixels,
 7650        scroll_pixel_position: gpui::Point<Pixels>,
 7651        newest_selection_head: Option<DisplayPoint>,
 7652        target_display_point: DisplayPoint,
 7653        window: &mut Window,
 7654        cx: &mut App,
 7655    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7656        let scrolled_content_origin =
 7657            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7658
 7659        const SCROLL_PADDING_Y: Pixels = px(12.);
 7660
 7661        if target_display_point.row() < visible_row_range.start {
 7662            return self.render_edit_prediction_scroll_popover(
 7663                |_| SCROLL_PADDING_Y,
 7664                IconName::ArrowUp,
 7665                visible_row_range,
 7666                line_layouts,
 7667                newest_selection_head,
 7668                scrolled_content_origin,
 7669                window,
 7670                cx,
 7671            );
 7672        } else if target_display_point.row() >= visible_row_range.end {
 7673            return self.render_edit_prediction_scroll_popover(
 7674                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7675                IconName::ArrowDown,
 7676                visible_row_range,
 7677                line_layouts,
 7678                newest_selection_head,
 7679                scrolled_content_origin,
 7680                window,
 7681                cx,
 7682            );
 7683        }
 7684
 7685        const POLE_WIDTH: Pixels = px(2.);
 7686
 7687        let line_layout =
 7688            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7689        let target_column = target_display_point.column() as usize;
 7690
 7691        let target_x = line_layout.x_for_index(target_column);
 7692        let target_y =
 7693            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7694
 7695        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7696
 7697        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7698        border_color.l += 0.001;
 7699
 7700        let mut element = v_flex()
 7701            .items_end()
 7702            .when(flag_on_right, |el| el.items_start())
 7703            .child(if flag_on_right {
 7704                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7705                    .rounded_bl(px(0.))
 7706                    .rounded_tl(px(0.))
 7707                    .border_l_2()
 7708                    .border_color(border_color)
 7709            } else {
 7710                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7711                    .rounded_br(px(0.))
 7712                    .rounded_tr(px(0.))
 7713                    .border_r_2()
 7714                    .border_color(border_color)
 7715            })
 7716            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7717            .into_any();
 7718
 7719        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7720
 7721        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7722            - point(
 7723                if flag_on_right {
 7724                    POLE_WIDTH
 7725                } else {
 7726                    size.width - POLE_WIDTH
 7727                },
 7728                size.height - line_height,
 7729            );
 7730
 7731        origin.x = origin.x.max(content_origin.x);
 7732
 7733        element.prepaint_at(origin, window, cx);
 7734
 7735        Some((element, origin))
 7736    }
 7737
 7738    fn render_edit_prediction_scroll_popover(
 7739        &mut self,
 7740        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7741        scroll_icon: IconName,
 7742        visible_row_range: Range<DisplayRow>,
 7743        line_layouts: &[LineWithInvisibles],
 7744        newest_selection_head: Option<DisplayPoint>,
 7745        scrolled_content_origin: gpui::Point<Pixels>,
 7746        window: &mut Window,
 7747        cx: &mut App,
 7748    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7749        let mut element = self
 7750            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7751            .into_any();
 7752
 7753        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7754
 7755        let cursor = newest_selection_head?;
 7756        let cursor_row_layout =
 7757            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7758        let cursor_column = cursor.column() as usize;
 7759
 7760        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7761
 7762        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7763
 7764        element.prepaint_at(origin, window, cx);
 7765        Some((element, origin))
 7766    }
 7767
 7768    fn render_edit_prediction_eager_jump_popover(
 7769        &mut self,
 7770        text_bounds: &Bounds<Pixels>,
 7771        content_origin: gpui::Point<Pixels>,
 7772        editor_snapshot: &EditorSnapshot,
 7773        visible_row_range: Range<DisplayRow>,
 7774        scroll_top: f32,
 7775        scroll_bottom: f32,
 7776        line_height: Pixels,
 7777        scroll_pixel_position: gpui::Point<Pixels>,
 7778        target_display_point: DisplayPoint,
 7779        editor_width: Pixels,
 7780        window: &mut Window,
 7781        cx: &mut App,
 7782    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7783        if target_display_point.row().as_f32() < scroll_top {
 7784            let mut element = self
 7785                .render_edit_prediction_line_popover(
 7786                    "Jump to Edit",
 7787                    Some(IconName::ArrowUp),
 7788                    window,
 7789                    cx,
 7790                )?
 7791                .into_any();
 7792
 7793            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7794            let offset = point(
 7795                (text_bounds.size.width - size.width) / 2.,
 7796                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7797            );
 7798
 7799            let origin = text_bounds.origin + offset;
 7800            element.prepaint_at(origin, window, cx);
 7801            Some((element, origin))
 7802        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7803            let mut element = self
 7804                .render_edit_prediction_line_popover(
 7805                    "Jump to Edit",
 7806                    Some(IconName::ArrowDown),
 7807                    window,
 7808                    cx,
 7809                )?
 7810                .into_any();
 7811
 7812            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7813            let offset = point(
 7814                (text_bounds.size.width - size.width) / 2.,
 7815                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7816            );
 7817
 7818            let origin = text_bounds.origin + offset;
 7819            element.prepaint_at(origin, window, cx);
 7820            Some((element, origin))
 7821        } else {
 7822            self.render_edit_prediction_end_of_line_popover(
 7823                "Jump to Edit",
 7824                editor_snapshot,
 7825                visible_row_range,
 7826                target_display_point,
 7827                line_height,
 7828                scroll_pixel_position,
 7829                content_origin,
 7830                editor_width,
 7831                window,
 7832                cx,
 7833            )
 7834        }
 7835    }
 7836
 7837    fn render_edit_prediction_end_of_line_popover(
 7838        self: &mut Editor,
 7839        label: &'static str,
 7840        editor_snapshot: &EditorSnapshot,
 7841        visible_row_range: Range<DisplayRow>,
 7842        target_display_point: DisplayPoint,
 7843        line_height: Pixels,
 7844        scroll_pixel_position: gpui::Point<Pixels>,
 7845        content_origin: gpui::Point<Pixels>,
 7846        editor_width: Pixels,
 7847        window: &mut Window,
 7848        cx: &mut App,
 7849    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7850        let target_line_end = DisplayPoint::new(
 7851            target_display_point.row(),
 7852            editor_snapshot.line_len(target_display_point.row()),
 7853        );
 7854
 7855        let mut element = self
 7856            .render_edit_prediction_line_popover(label, None, window, cx)?
 7857            .into_any();
 7858
 7859        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7860
 7861        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7862
 7863        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7864        let mut origin = start_point
 7865            + line_origin
 7866            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7867        origin.x = origin.x.max(content_origin.x);
 7868
 7869        let max_x = content_origin.x + editor_width - size.width;
 7870
 7871        if origin.x > max_x {
 7872            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7873
 7874            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7875                origin.y += offset;
 7876                IconName::ArrowUp
 7877            } else {
 7878                origin.y -= offset;
 7879                IconName::ArrowDown
 7880            };
 7881
 7882            element = self
 7883                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7884                .into_any();
 7885
 7886            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7887
 7888            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7889        }
 7890
 7891        element.prepaint_at(origin, window, cx);
 7892        Some((element, origin))
 7893    }
 7894
 7895    fn render_edit_prediction_diff_popover(
 7896        self: &Editor,
 7897        text_bounds: &Bounds<Pixels>,
 7898        content_origin: gpui::Point<Pixels>,
 7899        right_margin: Pixels,
 7900        editor_snapshot: &EditorSnapshot,
 7901        visible_row_range: Range<DisplayRow>,
 7902        line_layouts: &[LineWithInvisibles],
 7903        line_height: Pixels,
 7904        scroll_pixel_position: gpui::Point<Pixels>,
 7905        newest_selection_head: Option<DisplayPoint>,
 7906        editor_width: Pixels,
 7907        style: &EditorStyle,
 7908        edits: &Vec<(Range<Anchor>, String)>,
 7909        edit_preview: &Option<language::EditPreview>,
 7910        snapshot: &language::BufferSnapshot,
 7911        window: &mut Window,
 7912        cx: &mut App,
 7913    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7914        let edit_start = edits
 7915            .first()
 7916            .unwrap()
 7917            .0
 7918            .start
 7919            .to_display_point(editor_snapshot);
 7920        let edit_end = edits
 7921            .last()
 7922            .unwrap()
 7923            .0
 7924            .end
 7925            .to_display_point(editor_snapshot);
 7926
 7927        let is_visible = visible_row_range.contains(&edit_start.row())
 7928            || visible_row_range.contains(&edit_end.row());
 7929        if !is_visible {
 7930            return None;
 7931        }
 7932
 7933        let highlighted_edits =
 7934            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7935
 7936        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7937        let line_count = highlighted_edits.text.lines().count();
 7938
 7939        const BORDER_WIDTH: Pixels = px(1.);
 7940
 7941        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7942        let has_keybind = keybind.is_some();
 7943
 7944        let mut element = h_flex()
 7945            .items_start()
 7946            .child(
 7947                h_flex()
 7948                    .bg(cx.theme().colors().editor_background)
 7949                    .border(BORDER_WIDTH)
 7950                    .shadow_sm()
 7951                    .border_color(cx.theme().colors().border)
 7952                    .rounded_l_lg()
 7953                    .when(line_count > 1, |el| el.rounded_br_lg())
 7954                    .pr_1()
 7955                    .child(styled_text),
 7956            )
 7957            .child(
 7958                h_flex()
 7959                    .h(line_height + BORDER_WIDTH * 2.)
 7960                    .px_1p5()
 7961                    .gap_1()
 7962                    // Workaround: For some reason, there's a gap if we don't do this
 7963                    .ml(-BORDER_WIDTH)
 7964                    .shadow(smallvec![gpui::BoxShadow {
 7965                        color: gpui::black().opacity(0.05),
 7966                        offset: point(px(1.), px(1.)),
 7967                        blur_radius: px(2.),
 7968                        spread_radius: px(0.),
 7969                    }])
 7970                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7971                    .border(BORDER_WIDTH)
 7972                    .border_color(cx.theme().colors().border)
 7973                    .rounded_r_lg()
 7974                    .id("edit_prediction_diff_popover_keybind")
 7975                    .when(!has_keybind, |el| {
 7976                        let status_colors = cx.theme().status();
 7977
 7978                        el.bg(status_colors.error_background)
 7979                            .border_color(status_colors.error.opacity(0.6))
 7980                            .child(Icon::new(IconName::Info).color(Color::Error))
 7981                            .cursor_default()
 7982                            .hoverable_tooltip(move |_window, cx| {
 7983                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7984                            })
 7985                    })
 7986                    .children(keybind),
 7987            )
 7988            .into_any();
 7989
 7990        let longest_row =
 7991            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 7992        let longest_line_width = if visible_row_range.contains(&longest_row) {
 7993            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 7994        } else {
 7995            layout_line(
 7996                longest_row,
 7997                editor_snapshot,
 7998                style,
 7999                editor_width,
 8000                |_| false,
 8001                window,
 8002                cx,
 8003            )
 8004            .width
 8005        };
 8006
 8007        let viewport_bounds =
 8008            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8009                right: -right_margin,
 8010                ..Default::default()
 8011            });
 8012
 8013        let x_after_longest =
 8014            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8015                - scroll_pixel_position.x;
 8016
 8017        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8018
 8019        // Fully visible if it can be displayed within the window (allow overlapping other
 8020        // panes). However, this is only allowed if the popover starts within text_bounds.
 8021        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8022            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8023
 8024        let mut origin = if can_position_to_the_right {
 8025            point(
 8026                x_after_longest,
 8027                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8028                    - scroll_pixel_position.y,
 8029            )
 8030        } else {
 8031            let cursor_row = newest_selection_head.map(|head| head.row());
 8032            let above_edit = edit_start
 8033                .row()
 8034                .0
 8035                .checked_sub(line_count as u32)
 8036                .map(DisplayRow);
 8037            let below_edit = Some(edit_end.row() + 1);
 8038            let above_cursor =
 8039                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8040            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8041
 8042            // Place the edit popover adjacent to the edit if there is a location
 8043            // available that is onscreen and does not obscure the cursor. Otherwise,
 8044            // place it adjacent to the cursor.
 8045            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8046                .into_iter()
 8047                .flatten()
 8048                .find(|&start_row| {
 8049                    let end_row = start_row + line_count as u32;
 8050                    visible_row_range.contains(&start_row)
 8051                        && visible_row_range.contains(&end_row)
 8052                        && cursor_row.map_or(true, |cursor_row| {
 8053                            !((start_row..end_row).contains(&cursor_row))
 8054                        })
 8055                })?;
 8056
 8057            content_origin
 8058                + point(
 8059                    -scroll_pixel_position.x,
 8060                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8061                )
 8062        };
 8063
 8064        origin.x -= BORDER_WIDTH;
 8065
 8066        window.defer_draw(element, origin, 1);
 8067
 8068        // Do not return an element, since it will already be drawn due to defer_draw.
 8069        None
 8070    }
 8071
 8072    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8073        px(30.)
 8074    }
 8075
 8076    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8077        if self.read_only(cx) {
 8078            cx.theme().players().read_only()
 8079        } else {
 8080            self.style.as_ref().unwrap().local_player
 8081        }
 8082    }
 8083
 8084    fn render_edit_prediction_accept_keybind(
 8085        &self,
 8086        window: &mut Window,
 8087        cx: &App,
 8088    ) -> Option<AnyElement> {
 8089        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8090        let accept_keystroke = accept_binding.keystroke()?;
 8091
 8092        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8093
 8094        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8095            Color::Accent
 8096        } else {
 8097            Color::Muted
 8098        };
 8099
 8100        h_flex()
 8101            .px_0p5()
 8102            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8103            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8104            .text_size(TextSize::XSmall.rems(cx))
 8105            .child(h_flex().children(ui::render_modifiers(
 8106                &accept_keystroke.modifiers,
 8107                PlatformStyle::platform(),
 8108                Some(modifiers_color),
 8109                Some(IconSize::XSmall.rems().into()),
 8110                true,
 8111            )))
 8112            .when(is_platform_style_mac, |parent| {
 8113                parent.child(accept_keystroke.key.clone())
 8114            })
 8115            .when(!is_platform_style_mac, |parent| {
 8116                parent.child(
 8117                    Key::new(
 8118                        util::capitalize(&accept_keystroke.key),
 8119                        Some(Color::Default),
 8120                    )
 8121                    .size(Some(IconSize::XSmall.rems().into())),
 8122                )
 8123            })
 8124            .into_any()
 8125            .into()
 8126    }
 8127
 8128    fn render_edit_prediction_line_popover(
 8129        &self,
 8130        label: impl Into<SharedString>,
 8131        icon: Option<IconName>,
 8132        window: &mut Window,
 8133        cx: &App,
 8134    ) -> Option<Stateful<Div>> {
 8135        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8136
 8137        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8138        let has_keybind = keybind.is_some();
 8139
 8140        let result = h_flex()
 8141            .id("ep-line-popover")
 8142            .py_0p5()
 8143            .pl_1()
 8144            .pr(padding_right)
 8145            .gap_1()
 8146            .rounded_md()
 8147            .border_1()
 8148            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8149            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8150            .shadow_sm()
 8151            .when(!has_keybind, |el| {
 8152                let status_colors = cx.theme().status();
 8153
 8154                el.bg(status_colors.error_background)
 8155                    .border_color(status_colors.error.opacity(0.6))
 8156                    .pl_2()
 8157                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8158                    .cursor_default()
 8159                    .hoverable_tooltip(move |_window, cx| {
 8160                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8161                    })
 8162            })
 8163            .children(keybind)
 8164            .child(
 8165                Label::new(label)
 8166                    .size(LabelSize::Small)
 8167                    .when(!has_keybind, |el| {
 8168                        el.color(cx.theme().status().error.into()).strikethrough()
 8169                    }),
 8170            )
 8171            .when(!has_keybind, |el| {
 8172                el.child(
 8173                    h_flex().ml_1().child(
 8174                        Icon::new(IconName::Info)
 8175                            .size(IconSize::Small)
 8176                            .color(cx.theme().status().error.into()),
 8177                    ),
 8178                )
 8179            })
 8180            .when_some(icon, |element, icon| {
 8181                element.child(
 8182                    div()
 8183                        .mt(px(1.5))
 8184                        .child(Icon::new(icon).size(IconSize::Small)),
 8185                )
 8186            });
 8187
 8188        Some(result)
 8189    }
 8190
 8191    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8192        let accent_color = cx.theme().colors().text_accent;
 8193        let editor_bg_color = cx.theme().colors().editor_background;
 8194        editor_bg_color.blend(accent_color.opacity(0.1))
 8195    }
 8196
 8197    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8198        let accent_color = cx.theme().colors().text_accent;
 8199        let editor_bg_color = cx.theme().colors().editor_background;
 8200        editor_bg_color.blend(accent_color.opacity(0.6))
 8201    }
 8202
 8203    fn render_edit_prediction_cursor_popover(
 8204        &self,
 8205        min_width: Pixels,
 8206        max_width: Pixels,
 8207        cursor_point: Point,
 8208        style: &EditorStyle,
 8209        accept_keystroke: Option<&gpui::Keystroke>,
 8210        _window: &Window,
 8211        cx: &mut Context<Editor>,
 8212    ) -> Option<AnyElement> {
 8213        let provider = self.edit_prediction_provider.as_ref()?;
 8214
 8215        if provider.provider.needs_terms_acceptance(cx) {
 8216            return Some(
 8217                h_flex()
 8218                    .min_w(min_width)
 8219                    .flex_1()
 8220                    .px_2()
 8221                    .py_1()
 8222                    .gap_3()
 8223                    .elevation_2(cx)
 8224                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8225                    .id("accept-terms")
 8226                    .cursor_pointer()
 8227                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8228                    .on_click(cx.listener(|this, _event, window, cx| {
 8229                        cx.stop_propagation();
 8230                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8231                        window.dispatch_action(
 8232                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8233                            cx,
 8234                        );
 8235                    }))
 8236                    .child(
 8237                        h_flex()
 8238                            .flex_1()
 8239                            .gap_2()
 8240                            .child(Icon::new(IconName::ZedPredict))
 8241                            .child(Label::new("Accept Terms of Service"))
 8242                            .child(div().w_full())
 8243                            .child(
 8244                                Icon::new(IconName::ArrowUpRight)
 8245                                    .color(Color::Muted)
 8246                                    .size(IconSize::Small),
 8247                            )
 8248                            .into_any_element(),
 8249                    )
 8250                    .into_any(),
 8251            );
 8252        }
 8253
 8254        let is_refreshing = provider.provider.is_refreshing(cx);
 8255
 8256        fn pending_completion_container() -> Div {
 8257            h_flex()
 8258                .h_full()
 8259                .flex_1()
 8260                .gap_2()
 8261                .child(Icon::new(IconName::ZedPredict))
 8262        }
 8263
 8264        let completion = match &self.active_inline_completion {
 8265            Some(prediction) => {
 8266                if !self.has_visible_completions_menu() {
 8267                    const RADIUS: Pixels = px(6.);
 8268                    const BORDER_WIDTH: Pixels = px(1.);
 8269
 8270                    return Some(
 8271                        h_flex()
 8272                            .elevation_2(cx)
 8273                            .border(BORDER_WIDTH)
 8274                            .border_color(cx.theme().colors().border)
 8275                            .when(accept_keystroke.is_none(), |el| {
 8276                                el.border_color(cx.theme().status().error)
 8277                            })
 8278                            .rounded(RADIUS)
 8279                            .rounded_tl(px(0.))
 8280                            .overflow_hidden()
 8281                            .child(div().px_1p5().child(match &prediction.completion {
 8282                                InlineCompletion::Move { target, snapshot } => {
 8283                                    use text::ToPoint as _;
 8284                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8285                                    {
 8286                                        Icon::new(IconName::ZedPredictDown)
 8287                                    } else {
 8288                                        Icon::new(IconName::ZedPredictUp)
 8289                                    }
 8290                                }
 8291                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8292                            }))
 8293                            .child(
 8294                                h_flex()
 8295                                    .gap_1()
 8296                                    .py_1()
 8297                                    .px_2()
 8298                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8299                                    .border_l_1()
 8300                                    .border_color(cx.theme().colors().border)
 8301                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8302                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8303                                        el.child(
 8304                                            Label::new("Hold")
 8305                                                .size(LabelSize::Small)
 8306                                                .when(accept_keystroke.is_none(), |el| {
 8307                                                    el.strikethrough()
 8308                                                })
 8309                                                .line_height_style(LineHeightStyle::UiLabel),
 8310                                        )
 8311                                    })
 8312                                    .id("edit_prediction_cursor_popover_keybind")
 8313                                    .when(accept_keystroke.is_none(), |el| {
 8314                                        let status_colors = cx.theme().status();
 8315
 8316                                        el.bg(status_colors.error_background)
 8317                                            .border_color(status_colors.error.opacity(0.6))
 8318                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8319                                            .cursor_default()
 8320                                            .hoverable_tooltip(move |_window, cx| {
 8321                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8322                                                    .into()
 8323                                            })
 8324                                    })
 8325                                    .when_some(
 8326                                        accept_keystroke.as_ref(),
 8327                                        |el, accept_keystroke| {
 8328                                            el.child(h_flex().children(ui::render_modifiers(
 8329                                                &accept_keystroke.modifiers,
 8330                                                PlatformStyle::platform(),
 8331                                                Some(Color::Default),
 8332                                                Some(IconSize::XSmall.rems().into()),
 8333                                                false,
 8334                                            )))
 8335                                        },
 8336                                    ),
 8337                            )
 8338                            .into_any(),
 8339                    );
 8340                }
 8341
 8342                self.render_edit_prediction_cursor_popover_preview(
 8343                    prediction,
 8344                    cursor_point,
 8345                    style,
 8346                    cx,
 8347                )?
 8348            }
 8349
 8350            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8351                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8352                    stale_completion,
 8353                    cursor_point,
 8354                    style,
 8355                    cx,
 8356                )?,
 8357
 8358                None => {
 8359                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8360                }
 8361            },
 8362
 8363            None => pending_completion_container().child(Label::new("No Prediction")),
 8364        };
 8365
 8366        let completion = if is_refreshing {
 8367            completion
 8368                .with_animation(
 8369                    "loading-completion",
 8370                    Animation::new(Duration::from_secs(2))
 8371                        .repeat()
 8372                        .with_easing(pulsating_between(0.4, 0.8)),
 8373                    |label, delta| label.opacity(delta),
 8374                )
 8375                .into_any_element()
 8376        } else {
 8377            completion.into_any_element()
 8378        };
 8379
 8380        let has_completion = self.active_inline_completion.is_some();
 8381
 8382        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8383        Some(
 8384            h_flex()
 8385                .min_w(min_width)
 8386                .max_w(max_width)
 8387                .flex_1()
 8388                .elevation_2(cx)
 8389                .border_color(cx.theme().colors().border)
 8390                .child(
 8391                    div()
 8392                        .flex_1()
 8393                        .py_1()
 8394                        .px_2()
 8395                        .overflow_hidden()
 8396                        .child(completion),
 8397                )
 8398                .when_some(accept_keystroke, |el, accept_keystroke| {
 8399                    if !accept_keystroke.modifiers.modified() {
 8400                        return el;
 8401                    }
 8402
 8403                    el.child(
 8404                        h_flex()
 8405                            .h_full()
 8406                            .border_l_1()
 8407                            .rounded_r_lg()
 8408                            .border_color(cx.theme().colors().border)
 8409                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8410                            .gap_1()
 8411                            .py_1()
 8412                            .px_2()
 8413                            .child(
 8414                                h_flex()
 8415                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8416                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8417                                    .child(h_flex().children(ui::render_modifiers(
 8418                                        &accept_keystroke.modifiers,
 8419                                        PlatformStyle::platform(),
 8420                                        Some(if !has_completion {
 8421                                            Color::Muted
 8422                                        } else {
 8423                                            Color::Default
 8424                                        }),
 8425                                        None,
 8426                                        false,
 8427                                    ))),
 8428                            )
 8429                            .child(Label::new("Preview").into_any_element())
 8430                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8431                    )
 8432                })
 8433                .into_any(),
 8434        )
 8435    }
 8436
 8437    fn render_edit_prediction_cursor_popover_preview(
 8438        &self,
 8439        completion: &InlineCompletionState,
 8440        cursor_point: Point,
 8441        style: &EditorStyle,
 8442        cx: &mut Context<Editor>,
 8443    ) -> Option<Div> {
 8444        use text::ToPoint as _;
 8445
 8446        fn render_relative_row_jump(
 8447            prefix: impl Into<String>,
 8448            current_row: u32,
 8449            target_row: u32,
 8450        ) -> Div {
 8451            let (row_diff, arrow) = if target_row < current_row {
 8452                (current_row - target_row, IconName::ArrowUp)
 8453            } else {
 8454                (target_row - current_row, IconName::ArrowDown)
 8455            };
 8456
 8457            h_flex()
 8458                .child(
 8459                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8460                        .color(Color::Muted)
 8461                        .size(LabelSize::Small),
 8462                )
 8463                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8464        }
 8465
 8466        match &completion.completion {
 8467            InlineCompletion::Move {
 8468                target, snapshot, ..
 8469            } => Some(
 8470                h_flex()
 8471                    .px_2()
 8472                    .gap_2()
 8473                    .flex_1()
 8474                    .child(
 8475                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8476                            Icon::new(IconName::ZedPredictDown)
 8477                        } else {
 8478                            Icon::new(IconName::ZedPredictUp)
 8479                        },
 8480                    )
 8481                    .child(Label::new("Jump to Edit")),
 8482            ),
 8483
 8484            InlineCompletion::Edit {
 8485                edits,
 8486                edit_preview,
 8487                snapshot,
 8488                display_mode: _,
 8489            } => {
 8490                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8491
 8492                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8493                    &snapshot,
 8494                    &edits,
 8495                    edit_preview.as_ref()?,
 8496                    true,
 8497                    cx,
 8498                )
 8499                .first_line_preview();
 8500
 8501                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8502                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8503
 8504                let preview = h_flex()
 8505                    .gap_1()
 8506                    .min_w_16()
 8507                    .child(styled_text)
 8508                    .when(has_more_lines, |parent| parent.child(""));
 8509
 8510                let left = if first_edit_row != cursor_point.row {
 8511                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8512                        .into_any_element()
 8513                } else {
 8514                    Icon::new(IconName::ZedPredict).into_any_element()
 8515                };
 8516
 8517                Some(
 8518                    h_flex()
 8519                        .h_full()
 8520                        .flex_1()
 8521                        .gap_2()
 8522                        .pr_1()
 8523                        .overflow_x_hidden()
 8524                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8525                        .child(left)
 8526                        .child(preview),
 8527                )
 8528            }
 8529        }
 8530    }
 8531
 8532    fn render_context_menu(
 8533        &self,
 8534        style: &EditorStyle,
 8535        max_height_in_lines: u32,
 8536        window: &mut Window,
 8537        cx: &mut Context<Editor>,
 8538    ) -> Option<AnyElement> {
 8539        let menu = self.context_menu.borrow();
 8540        let menu = menu.as_ref()?;
 8541        if !menu.visible() {
 8542            return None;
 8543        };
 8544        Some(menu.render(style, max_height_in_lines, window, cx))
 8545    }
 8546
 8547    fn render_context_menu_aside(
 8548        &mut self,
 8549        max_size: Size<Pixels>,
 8550        window: &mut Window,
 8551        cx: &mut Context<Editor>,
 8552    ) -> Option<AnyElement> {
 8553        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8554            if menu.visible() {
 8555                menu.render_aside(self, max_size, window, cx)
 8556            } else {
 8557                None
 8558            }
 8559        })
 8560    }
 8561
 8562    fn hide_context_menu(
 8563        &mut self,
 8564        window: &mut Window,
 8565        cx: &mut Context<Self>,
 8566    ) -> Option<CodeContextMenu> {
 8567        cx.notify();
 8568        self.completion_tasks.clear();
 8569        let context_menu = self.context_menu.borrow_mut().take();
 8570        self.stale_inline_completion_in_menu.take();
 8571        self.update_visible_inline_completion(window, cx);
 8572        context_menu
 8573    }
 8574
 8575    fn show_snippet_choices(
 8576        &mut self,
 8577        choices: &Vec<String>,
 8578        selection: Range<Anchor>,
 8579        cx: &mut Context<Self>,
 8580    ) {
 8581        if selection.start.buffer_id.is_none() {
 8582            return;
 8583        }
 8584        let buffer_id = selection.start.buffer_id.unwrap();
 8585        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8586        let id = post_inc(&mut self.next_completion_id);
 8587        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8588
 8589        if let Some(buffer) = buffer {
 8590            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8591                CompletionsMenu::new_snippet_choices(
 8592                    id,
 8593                    true,
 8594                    choices,
 8595                    selection,
 8596                    buffer,
 8597                    snippet_sort_order,
 8598                ),
 8599            ));
 8600        }
 8601    }
 8602
 8603    pub fn insert_snippet(
 8604        &mut self,
 8605        insertion_ranges: &[Range<usize>],
 8606        snippet: Snippet,
 8607        window: &mut Window,
 8608        cx: &mut Context<Self>,
 8609    ) -> Result<()> {
 8610        struct Tabstop<T> {
 8611            is_end_tabstop: bool,
 8612            ranges: Vec<Range<T>>,
 8613            choices: Option<Vec<String>>,
 8614        }
 8615
 8616        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8617            let snippet_text: Arc<str> = snippet.text.clone().into();
 8618            let edits = insertion_ranges
 8619                .iter()
 8620                .cloned()
 8621                .map(|range| (range, snippet_text.clone()));
 8622            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8623
 8624            let snapshot = &*buffer.read(cx);
 8625            let snippet = &snippet;
 8626            snippet
 8627                .tabstops
 8628                .iter()
 8629                .map(|tabstop| {
 8630                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8631                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8632                    });
 8633                    let mut tabstop_ranges = tabstop
 8634                        .ranges
 8635                        .iter()
 8636                        .flat_map(|tabstop_range| {
 8637                            let mut delta = 0_isize;
 8638                            insertion_ranges.iter().map(move |insertion_range| {
 8639                                let insertion_start = insertion_range.start as isize + delta;
 8640                                delta +=
 8641                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8642
 8643                                let start = ((insertion_start + tabstop_range.start) as usize)
 8644                                    .min(snapshot.len());
 8645                                let end = ((insertion_start + tabstop_range.end) as usize)
 8646                                    .min(snapshot.len());
 8647                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8648                            })
 8649                        })
 8650                        .collect::<Vec<_>>();
 8651                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8652
 8653                    Tabstop {
 8654                        is_end_tabstop,
 8655                        ranges: tabstop_ranges,
 8656                        choices: tabstop.choices.clone(),
 8657                    }
 8658                })
 8659                .collect::<Vec<_>>()
 8660        });
 8661        if let Some(tabstop) = tabstops.first() {
 8662            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8663                s.select_ranges(tabstop.ranges.iter().cloned());
 8664            });
 8665
 8666            if let Some(choices) = &tabstop.choices {
 8667                if let Some(selection) = tabstop.ranges.first() {
 8668                    self.show_snippet_choices(choices, selection.clone(), cx)
 8669                }
 8670            }
 8671
 8672            // If we're already at the last tabstop and it's at the end of the snippet,
 8673            // we're done, we don't need to keep the state around.
 8674            if !tabstop.is_end_tabstop {
 8675                let choices = tabstops
 8676                    .iter()
 8677                    .map(|tabstop| tabstop.choices.clone())
 8678                    .collect();
 8679
 8680                let ranges = tabstops
 8681                    .into_iter()
 8682                    .map(|tabstop| tabstop.ranges)
 8683                    .collect::<Vec<_>>();
 8684
 8685                self.snippet_stack.push(SnippetState {
 8686                    active_index: 0,
 8687                    ranges,
 8688                    choices,
 8689                });
 8690            }
 8691
 8692            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8693            if self.autoclose_regions.is_empty() {
 8694                let snapshot = self.buffer.read(cx).snapshot(cx);
 8695                for selection in &mut self.selections.all::<Point>(cx) {
 8696                    let selection_head = selection.head();
 8697                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8698                        continue;
 8699                    };
 8700
 8701                    let mut bracket_pair = None;
 8702                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8703                    let prev_chars = snapshot
 8704                        .reversed_chars_at(selection_head)
 8705                        .collect::<String>();
 8706                    for (pair, enabled) in scope.brackets() {
 8707                        if enabled
 8708                            && pair.close
 8709                            && prev_chars.starts_with(pair.start.as_str())
 8710                            && next_chars.starts_with(pair.end.as_str())
 8711                        {
 8712                            bracket_pair = Some(pair.clone());
 8713                            break;
 8714                        }
 8715                    }
 8716                    if let Some(pair) = bracket_pair {
 8717                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8718                        let autoclose_enabled =
 8719                            self.use_autoclose && snapshot_settings.use_autoclose;
 8720                        if autoclose_enabled {
 8721                            let start = snapshot.anchor_after(selection_head);
 8722                            let end = snapshot.anchor_after(selection_head);
 8723                            self.autoclose_regions.push(AutocloseRegion {
 8724                                selection_id: selection.id,
 8725                                range: start..end,
 8726                                pair,
 8727                            });
 8728                        }
 8729                    }
 8730                }
 8731            }
 8732        }
 8733        Ok(())
 8734    }
 8735
 8736    pub fn move_to_next_snippet_tabstop(
 8737        &mut self,
 8738        window: &mut Window,
 8739        cx: &mut Context<Self>,
 8740    ) -> bool {
 8741        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8742    }
 8743
 8744    pub fn move_to_prev_snippet_tabstop(
 8745        &mut self,
 8746        window: &mut Window,
 8747        cx: &mut Context<Self>,
 8748    ) -> bool {
 8749        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8750    }
 8751
 8752    pub fn move_to_snippet_tabstop(
 8753        &mut self,
 8754        bias: Bias,
 8755        window: &mut Window,
 8756        cx: &mut Context<Self>,
 8757    ) -> bool {
 8758        if let Some(mut snippet) = self.snippet_stack.pop() {
 8759            match bias {
 8760                Bias::Left => {
 8761                    if snippet.active_index > 0 {
 8762                        snippet.active_index -= 1;
 8763                    } else {
 8764                        self.snippet_stack.push(snippet);
 8765                        return false;
 8766                    }
 8767                }
 8768                Bias::Right => {
 8769                    if snippet.active_index + 1 < snippet.ranges.len() {
 8770                        snippet.active_index += 1;
 8771                    } else {
 8772                        self.snippet_stack.push(snippet);
 8773                        return false;
 8774                    }
 8775                }
 8776            }
 8777            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8778                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8779                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8780                });
 8781
 8782                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8783                    if let Some(selection) = current_ranges.first() {
 8784                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8785                    }
 8786                }
 8787
 8788                // If snippet state is not at the last tabstop, push it back on the stack
 8789                if snippet.active_index + 1 < snippet.ranges.len() {
 8790                    self.snippet_stack.push(snippet);
 8791                }
 8792                return true;
 8793            }
 8794        }
 8795
 8796        false
 8797    }
 8798
 8799    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8800        self.transact(window, cx, |this, window, cx| {
 8801            this.select_all(&SelectAll, window, cx);
 8802            this.insert("", window, cx);
 8803        });
 8804    }
 8805
 8806    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8807        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8808        self.transact(window, cx, |this, window, cx| {
 8809            this.select_autoclose_pair(window, cx);
 8810            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8811            if !this.linked_edit_ranges.is_empty() {
 8812                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8813                let snapshot = this.buffer.read(cx).snapshot(cx);
 8814
 8815                for selection in selections.iter() {
 8816                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8817                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8818                    if selection_start.buffer_id != selection_end.buffer_id {
 8819                        continue;
 8820                    }
 8821                    if let Some(ranges) =
 8822                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8823                    {
 8824                        for (buffer, entries) in ranges {
 8825                            linked_ranges.entry(buffer).or_default().extend(entries);
 8826                        }
 8827                    }
 8828                }
 8829            }
 8830
 8831            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8832            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8833            for selection in &mut selections {
 8834                if selection.is_empty() {
 8835                    let old_head = selection.head();
 8836                    let mut new_head =
 8837                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8838                            .to_point(&display_map);
 8839                    if let Some((buffer, line_buffer_range)) = display_map
 8840                        .buffer_snapshot
 8841                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8842                    {
 8843                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8844                        let indent_len = match indent_size.kind {
 8845                            IndentKind::Space => {
 8846                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8847                            }
 8848                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8849                        };
 8850                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8851                            let indent_len = indent_len.get();
 8852                            new_head = cmp::min(
 8853                                new_head,
 8854                                MultiBufferPoint::new(
 8855                                    old_head.row,
 8856                                    ((old_head.column - 1) / indent_len) * indent_len,
 8857                                ),
 8858                            );
 8859                        }
 8860                    }
 8861
 8862                    selection.set_head(new_head, SelectionGoal::None);
 8863                }
 8864            }
 8865
 8866            this.signature_help_state.set_backspace_pressed(true);
 8867            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8868                s.select(selections)
 8869            });
 8870            this.insert("", window, cx);
 8871            let empty_str: Arc<str> = Arc::from("");
 8872            for (buffer, edits) in linked_ranges {
 8873                let snapshot = buffer.read(cx).snapshot();
 8874                use text::ToPoint as TP;
 8875
 8876                let edits = edits
 8877                    .into_iter()
 8878                    .map(|range| {
 8879                        let end_point = TP::to_point(&range.end, &snapshot);
 8880                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8881
 8882                        if end_point == start_point {
 8883                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8884                                .saturating_sub(1);
 8885                            start_point =
 8886                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8887                        };
 8888
 8889                        (start_point..end_point, empty_str.clone())
 8890                    })
 8891                    .sorted_by_key(|(range, _)| range.start)
 8892                    .collect::<Vec<_>>();
 8893                buffer.update(cx, |this, cx| {
 8894                    this.edit(edits, None, cx);
 8895                })
 8896            }
 8897            this.refresh_inline_completion(true, false, window, cx);
 8898            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8899        });
 8900    }
 8901
 8902    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8903        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8904        self.transact(window, cx, |this, window, cx| {
 8905            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8906                s.move_with(|map, selection| {
 8907                    if selection.is_empty() {
 8908                        let cursor = movement::right(map, selection.head());
 8909                        selection.end = cursor;
 8910                        selection.reversed = true;
 8911                        selection.goal = SelectionGoal::None;
 8912                    }
 8913                })
 8914            });
 8915            this.insert("", window, cx);
 8916            this.refresh_inline_completion(true, false, window, cx);
 8917        });
 8918    }
 8919
 8920    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8921        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8922        if self.move_to_prev_snippet_tabstop(window, cx) {
 8923            return;
 8924        }
 8925        self.outdent(&Outdent, window, cx);
 8926    }
 8927
 8928    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8929        if self.move_to_next_snippet_tabstop(window, cx) {
 8930            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8931            return;
 8932        }
 8933        if self.read_only(cx) {
 8934            return;
 8935        }
 8936        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8937        let mut selections = self.selections.all_adjusted(cx);
 8938        let buffer = self.buffer.read(cx);
 8939        let snapshot = buffer.snapshot(cx);
 8940        let rows_iter = selections.iter().map(|s| s.head().row);
 8941        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8942
 8943        let has_some_cursor_in_whitespace = selections
 8944            .iter()
 8945            .filter(|selection| selection.is_empty())
 8946            .any(|selection| {
 8947                let cursor = selection.head();
 8948                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8949                cursor.column < current_indent.len
 8950            });
 8951
 8952        let mut edits = Vec::new();
 8953        let mut prev_edited_row = 0;
 8954        let mut row_delta = 0;
 8955        for selection in &mut selections {
 8956            if selection.start.row != prev_edited_row {
 8957                row_delta = 0;
 8958            }
 8959            prev_edited_row = selection.end.row;
 8960
 8961            // If the selection is non-empty, then increase the indentation of the selected lines.
 8962            if !selection.is_empty() {
 8963                row_delta =
 8964                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8965                continue;
 8966            }
 8967
 8968            let cursor = selection.head();
 8969            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8970            if let Some(suggested_indent) =
 8971                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8972            {
 8973                // Don't do anything if already at suggested indent
 8974                // and there is any other cursor which is not
 8975                if has_some_cursor_in_whitespace
 8976                    && cursor.column == current_indent.len
 8977                    && current_indent.len == suggested_indent.len
 8978                {
 8979                    continue;
 8980                }
 8981
 8982                // Adjust line and move cursor to suggested indent
 8983                // if cursor is not at suggested indent
 8984                if cursor.column < suggested_indent.len
 8985                    && cursor.column <= current_indent.len
 8986                    && current_indent.len <= suggested_indent.len
 8987                {
 8988                    selection.start = Point::new(cursor.row, suggested_indent.len);
 8989                    selection.end = selection.start;
 8990                    if row_delta == 0 {
 8991                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 8992                            cursor.row,
 8993                            current_indent,
 8994                            suggested_indent,
 8995                        ));
 8996                        row_delta = suggested_indent.len - current_indent.len;
 8997                    }
 8998                    continue;
 8999                }
 9000
 9001                // If current indent is more than suggested indent
 9002                // only move cursor to current indent and skip indent
 9003                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9004                    selection.start = Point::new(cursor.row, current_indent.len);
 9005                    selection.end = selection.start;
 9006                    continue;
 9007                }
 9008            }
 9009
 9010            // Otherwise, insert a hard or soft tab.
 9011            let settings = buffer.language_settings_at(cursor, cx);
 9012            let tab_size = if settings.hard_tabs {
 9013                IndentSize::tab()
 9014            } else {
 9015                let tab_size = settings.tab_size.get();
 9016                let indent_remainder = snapshot
 9017                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9018                    .flat_map(str::chars)
 9019                    .fold(row_delta % tab_size, |counter: u32, c| {
 9020                        if c == '\t' {
 9021                            0
 9022                        } else {
 9023                            (counter + 1) % tab_size
 9024                        }
 9025                    });
 9026
 9027                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9028                IndentSize::spaces(chars_to_next_tab_stop)
 9029            };
 9030            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9031            selection.end = selection.start;
 9032            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9033            row_delta += tab_size.len;
 9034        }
 9035
 9036        self.transact(window, cx, |this, window, cx| {
 9037            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9038            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9039                s.select(selections)
 9040            });
 9041            this.refresh_inline_completion(true, false, window, cx);
 9042        });
 9043    }
 9044
 9045    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9046        if self.read_only(cx) {
 9047            return;
 9048        }
 9049        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9050        let mut selections = self.selections.all::<Point>(cx);
 9051        let mut prev_edited_row = 0;
 9052        let mut row_delta = 0;
 9053        let mut edits = Vec::new();
 9054        let buffer = self.buffer.read(cx);
 9055        let snapshot = buffer.snapshot(cx);
 9056        for selection in &mut selections {
 9057            if selection.start.row != prev_edited_row {
 9058                row_delta = 0;
 9059            }
 9060            prev_edited_row = selection.end.row;
 9061
 9062            row_delta =
 9063                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9064        }
 9065
 9066        self.transact(window, cx, |this, window, cx| {
 9067            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9068            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9069                s.select(selections)
 9070            });
 9071        });
 9072    }
 9073
 9074    fn indent_selection(
 9075        buffer: &MultiBuffer,
 9076        snapshot: &MultiBufferSnapshot,
 9077        selection: &mut Selection<Point>,
 9078        edits: &mut Vec<(Range<Point>, String)>,
 9079        delta_for_start_row: u32,
 9080        cx: &App,
 9081    ) -> u32 {
 9082        let settings = buffer.language_settings_at(selection.start, cx);
 9083        let tab_size = settings.tab_size.get();
 9084        let indent_kind = if settings.hard_tabs {
 9085            IndentKind::Tab
 9086        } else {
 9087            IndentKind::Space
 9088        };
 9089        let mut start_row = selection.start.row;
 9090        let mut end_row = selection.end.row + 1;
 9091
 9092        // If a selection ends at the beginning of a line, don't indent
 9093        // that last line.
 9094        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9095            end_row -= 1;
 9096        }
 9097
 9098        // Avoid re-indenting a row that has already been indented by a
 9099        // previous selection, but still update this selection's column
 9100        // to reflect that indentation.
 9101        if delta_for_start_row > 0 {
 9102            start_row += 1;
 9103            selection.start.column += delta_for_start_row;
 9104            if selection.end.row == selection.start.row {
 9105                selection.end.column += delta_for_start_row;
 9106            }
 9107        }
 9108
 9109        let mut delta_for_end_row = 0;
 9110        let has_multiple_rows = start_row + 1 != end_row;
 9111        for row in start_row..end_row {
 9112            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9113            let indent_delta = match (current_indent.kind, indent_kind) {
 9114                (IndentKind::Space, IndentKind::Space) => {
 9115                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9116                    IndentSize::spaces(columns_to_next_tab_stop)
 9117                }
 9118                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9119                (_, IndentKind::Tab) => IndentSize::tab(),
 9120            };
 9121
 9122            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9123                0
 9124            } else {
 9125                selection.start.column
 9126            };
 9127            let row_start = Point::new(row, start);
 9128            edits.push((
 9129                row_start..row_start,
 9130                indent_delta.chars().collect::<String>(),
 9131            ));
 9132
 9133            // Update this selection's endpoints to reflect the indentation.
 9134            if row == selection.start.row {
 9135                selection.start.column += indent_delta.len;
 9136            }
 9137            if row == selection.end.row {
 9138                selection.end.column += indent_delta.len;
 9139                delta_for_end_row = indent_delta.len;
 9140            }
 9141        }
 9142
 9143        if selection.start.row == selection.end.row {
 9144            delta_for_start_row + delta_for_end_row
 9145        } else {
 9146            delta_for_end_row
 9147        }
 9148    }
 9149
 9150    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9151        if self.read_only(cx) {
 9152            return;
 9153        }
 9154        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9155        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9156        let selections = self.selections.all::<Point>(cx);
 9157        let mut deletion_ranges = Vec::new();
 9158        let mut last_outdent = None;
 9159        {
 9160            let buffer = self.buffer.read(cx);
 9161            let snapshot = buffer.snapshot(cx);
 9162            for selection in &selections {
 9163                let settings = buffer.language_settings_at(selection.start, cx);
 9164                let tab_size = settings.tab_size.get();
 9165                let mut rows = selection.spanned_rows(false, &display_map);
 9166
 9167                // Avoid re-outdenting a row that has already been outdented by a
 9168                // previous selection.
 9169                if let Some(last_row) = last_outdent {
 9170                    if last_row == rows.start {
 9171                        rows.start = rows.start.next_row();
 9172                    }
 9173                }
 9174                let has_multiple_rows = rows.len() > 1;
 9175                for row in rows.iter_rows() {
 9176                    let indent_size = snapshot.indent_size_for_line(row);
 9177                    if indent_size.len > 0 {
 9178                        let deletion_len = match indent_size.kind {
 9179                            IndentKind::Space => {
 9180                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9181                                if columns_to_prev_tab_stop == 0 {
 9182                                    tab_size
 9183                                } else {
 9184                                    columns_to_prev_tab_stop
 9185                                }
 9186                            }
 9187                            IndentKind::Tab => 1,
 9188                        };
 9189                        let start = if has_multiple_rows
 9190                            || deletion_len > selection.start.column
 9191                            || indent_size.len < selection.start.column
 9192                        {
 9193                            0
 9194                        } else {
 9195                            selection.start.column - deletion_len
 9196                        };
 9197                        deletion_ranges.push(
 9198                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9199                        );
 9200                        last_outdent = Some(row);
 9201                    }
 9202                }
 9203            }
 9204        }
 9205
 9206        self.transact(window, cx, |this, window, cx| {
 9207            this.buffer.update(cx, |buffer, cx| {
 9208                let empty_str: Arc<str> = Arc::default();
 9209                buffer.edit(
 9210                    deletion_ranges
 9211                        .into_iter()
 9212                        .map(|range| (range, empty_str.clone())),
 9213                    None,
 9214                    cx,
 9215                );
 9216            });
 9217            let selections = this.selections.all::<usize>(cx);
 9218            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9219                s.select(selections)
 9220            });
 9221        });
 9222    }
 9223
 9224    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9225        if self.read_only(cx) {
 9226            return;
 9227        }
 9228        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9229        let selections = self
 9230            .selections
 9231            .all::<usize>(cx)
 9232            .into_iter()
 9233            .map(|s| s.range());
 9234
 9235        self.transact(window, cx, |this, window, cx| {
 9236            this.buffer.update(cx, |buffer, cx| {
 9237                buffer.autoindent_ranges(selections, cx);
 9238            });
 9239            let selections = this.selections.all::<usize>(cx);
 9240            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9241                s.select(selections)
 9242            });
 9243        });
 9244    }
 9245
 9246    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9247        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9248        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9249        let selections = self.selections.all::<Point>(cx);
 9250
 9251        let mut new_cursors = Vec::new();
 9252        let mut edit_ranges = Vec::new();
 9253        let mut selections = selections.iter().peekable();
 9254        while let Some(selection) = selections.next() {
 9255            let mut rows = selection.spanned_rows(false, &display_map);
 9256            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9257
 9258            // Accumulate contiguous regions of rows that we want to delete.
 9259            while let Some(next_selection) = selections.peek() {
 9260                let next_rows = next_selection.spanned_rows(false, &display_map);
 9261                if next_rows.start <= rows.end {
 9262                    rows.end = next_rows.end;
 9263                    selections.next().unwrap();
 9264                } else {
 9265                    break;
 9266                }
 9267            }
 9268
 9269            let buffer = &display_map.buffer_snapshot;
 9270            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9271            let edit_end;
 9272            let cursor_buffer_row;
 9273            if buffer.max_point().row >= rows.end.0 {
 9274                // If there's a line after the range, delete the \n from the end of the row range
 9275                // and position the cursor on the next line.
 9276                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9277                cursor_buffer_row = rows.end;
 9278            } else {
 9279                // If there isn't a line after the range, delete the \n from the line before the
 9280                // start of the row range and position the cursor there.
 9281                edit_start = edit_start.saturating_sub(1);
 9282                edit_end = buffer.len();
 9283                cursor_buffer_row = rows.start.previous_row();
 9284            }
 9285
 9286            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9287            *cursor.column_mut() =
 9288                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9289
 9290            new_cursors.push((
 9291                selection.id,
 9292                buffer.anchor_after(cursor.to_point(&display_map)),
 9293            ));
 9294            edit_ranges.push(edit_start..edit_end);
 9295        }
 9296
 9297        self.transact(window, cx, |this, window, cx| {
 9298            let buffer = this.buffer.update(cx, |buffer, cx| {
 9299                let empty_str: Arc<str> = Arc::default();
 9300                buffer.edit(
 9301                    edit_ranges
 9302                        .into_iter()
 9303                        .map(|range| (range, empty_str.clone())),
 9304                    None,
 9305                    cx,
 9306                );
 9307                buffer.snapshot(cx)
 9308            });
 9309            let new_selections = new_cursors
 9310                .into_iter()
 9311                .map(|(id, cursor)| {
 9312                    let cursor = cursor.to_point(&buffer);
 9313                    Selection {
 9314                        id,
 9315                        start: cursor,
 9316                        end: cursor,
 9317                        reversed: false,
 9318                        goal: SelectionGoal::None,
 9319                    }
 9320                })
 9321                .collect();
 9322
 9323            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9324                s.select(new_selections);
 9325            });
 9326        });
 9327    }
 9328
 9329    pub fn join_lines_impl(
 9330        &mut self,
 9331        insert_whitespace: bool,
 9332        window: &mut Window,
 9333        cx: &mut Context<Self>,
 9334    ) {
 9335        if self.read_only(cx) {
 9336            return;
 9337        }
 9338        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9339        for selection in self.selections.all::<Point>(cx) {
 9340            let start = MultiBufferRow(selection.start.row);
 9341            // Treat single line selections as if they include the next line. Otherwise this action
 9342            // would do nothing for single line selections individual cursors.
 9343            let end = if selection.start.row == selection.end.row {
 9344                MultiBufferRow(selection.start.row + 1)
 9345            } else {
 9346                MultiBufferRow(selection.end.row)
 9347            };
 9348
 9349            if let Some(last_row_range) = row_ranges.last_mut() {
 9350                if start <= last_row_range.end {
 9351                    last_row_range.end = end;
 9352                    continue;
 9353                }
 9354            }
 9355            row_ranges.push(start..end);
 9356        }
 9357
 9358        let snapshot = self.buffer.read(cx).snapshot(cx);
 9359        let mut cursor_positions = Vec::new();
 9360        for row_range in &row_ranges {
 9361            let anchor = snapshot.anchor_before(Point::new(
 9362                row_range.end.previous_row().0,
 9363                snapshot.line_len(row_range.end.previous_row()),
 9364            ));
 9365            cursor_positions.push(anchor..anchor);
 9366        }
 9367
 9368        self.transact(window, cx, |this, window, cx| {
 9369            for row_range in row_ranges.into_iter().rev() {
 9370                for row in row_range.iter_rows().rev() {
 9371                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9372                    let next_line_row = row.next_row();
 9373                    let indent = snapshot.indent_size_for_line(next_line_row);
 9374                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9375
 9376                    let replace =
 9377                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9378                            " "
 9379                        } else {
 9380                            ""
 9381                        };
 9382
 9383                    this.buffer.update(cx, |buffer, cx| {
 9384                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9385                    });
 9386                }
 9387            }
 9388
 9389            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9390                s.select_anchor_ranges(cursor_positions)
 9391            });
 9392        });
 9393    }
 9394
 9395    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9396        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9397        self.join_lines_impl(true, window, cx);
 9398    }
 9399
 9400    pub fn sort_lines_case_sensitive(
 9401        &mut self,
 9402        _: &SortLinesCaseSensitive,
 9403        window: &mut Window,
 9404        cx: &mut Context<Self>,
 9405    ) {
 9406        self.manipulate_lines(window, cx, |lines| lines.sort())
 9407    }
 9408
 9409    pub fn sort_lines_case_insensitive(
 9410        &mut self,
 9411        _: &SortLinesCaseInsensitive,
 9412        window: &mut Window,
 9413        cx: &mut Context<Self>,
 9414    ) {
 9415        self.manipulate_lines(window, cx, |lines| {
 9416            lines.sort_by_key(|line| line.to_lowercase())
 9417        })
 9418    }
 9419
 9420    pub fn unique_lines_case_insensitive(
 9421        &mut self,
 9422        _: &UniqueLinesCaseInsensitive,
 9423        window: &mut Window,
 9424        cx: &mut Context<Self>,
 9425    ) {
 9426        self.manipulate_lines(window, cx, |lines| {
 9427            let mut seen = HashSet::default();
 9428            lines.retain(|line| seen.insert(line.to_lowercase()));
 9429        })
 9430    }
 9431
 9432    pub fn unique_lines_case_sensitive(
 9433        &mut self,
 9434        _: &UniqueLinesCaseSensitive,
 9435        window: &mut Window,
 9436        cx: &mut Context<Self>,
 9437    ) {
 9438        self.manipulate_lines(window, cx, |lines| {
 9439            let mut seen = HashSet::default();
 9440            lines.retain(|line| seen.insert(*line));
 9441        })
 9442    }
 9443
 9444    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9445        let Some(project) = self.project.clone() else {
 9446            return;
 9447        };
 9448        self.reload(project, window, cx)
 9449            .detach_and_notify_err(window, cx);
 9450    }
 9451
 9452    pub fn restore_file(
 9453        &mut self,
 9454        _: &::git::RestoreFile,
 9455        window: &mut Window,
 9456        cx: &mut Context<Self>,
 9457    ) {
 9458        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9459        let mut buffer_ids = HashSet::default();
 9460        let snapshot = self.buffer().read(cx).snapshot(cx);
 9461        for selection in self.selections.all::<usize>(cx) {
 9462            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9463        }
 9464
 9465        let buffer = self.buffer().read(cx);
 9466        let ranges = buffer_ids
 9467            .into_iter()
 9468            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9469            .collect::<Vec<_>>();
 9470
 9471        self.restore_hunks_in_ranges(ranges, window, cx);
 9472    }
 9473
 9474    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9475        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9476        let selections = self
 9477            .selections
 9478            .all(cx)
 9479            .into_iter()
 9480            .map(|s| s.range())
 9481            .collect();
 9482        self.restore_hunks_in_ranges(selections, window, cx);
 9483    }
 9484
 9485    pub fn restore_hunks_in_ranges(
 9486        &mut self,
 9487        ranges: Vec<Range<Point>>,
 9488        window: &mut Window,
 9489        cx: &mut Context<Editor>,
 9490    ) {
 9491        let mut revert_changes = HashMap::default();
 9492        let chunk_by = self
 9493            .snapshot(window, cx)
 9494            .hunks_for_ranges(ranges)
 9495            .into_iter()
 9496            .chunk_by(|hunk| hunk.buffer_id);
 9497        for (buffer_id, hunks) in &chunk_by {
 9498            let hunks = hunks.collect::<Vec<_>>();
 9499            for hunk in &hunks {
 9500                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9501            }
 9502            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9503        }
 9504        drop(chunk_by);
 9505        if !revert_changes.is_empty() {
 9506            self.transact(window, cx, |editor, window, cx| {
 9507                editor.restore(revert_changes, window, cx);
 9508            });
 9509        }
 9510    }
 9511
 9512    pub fn open_active_item_in_terminal(
 9513        &mut self,
 9514        _: &OpenInTerminal,
 9515        window: &mut Window,
 9516        cx: &mut Context<Self>,
 9517    ) {
 9518        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9519            let project_path = buffer.read(cx).project_path(cx)?;
 9520            let project = self.project.as_ref()?.read(cx);
 9521            let entry = project.entry_for_path(&project_path, cx)?;
 9522            let parent = match &entry.canonical_path {
 9523                Some(canonical_path) => canonical_path.to_path_buf(),
 9524                None => project.absolute_path(&project_path, cx)?,
 9525            }
 9526            .parent()?
 9527            .to_path_buf();
 9528            Some(parent)
 9529        }) {
 9530            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9531        }
 9532    }
 9533
 9534    fn set_breakpoint_context_menu(
 9535        &mut self,
 9536        display_row: DisplayRow,
 9537        position: Option<Anchor>,
 9538        clicked_point: gpui::Point<Pixels>,
 9539        window: &mut Window,
 9540        cx: &mut Context<Self>,
 9541    ) {
 9542        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9543            return;
 9544        }
 9545        let source = self
 9546            .buffer
 9547            .read(cx)
 9548            .snapshot(cx)
 9549            .anchor_before(Point::new(display_row.0, 0u32));
 9550
 9551        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9552
 9553        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9554            self,
 9555            source,
 9556            clicked_point,
 9557            context_menu,
 9558            window,
 9559            cx,
 9560        );
 9561    }
 9562
 9563    fn add_edit_breakpoint_block(
 9564        &mut self,
 9565        anchor: Anchor,
 9566        breakpoint: &Breakpoint,
 9567        edit_action: BreakpointPromptEditAction,
 9568        window: &mut Window,
 9569        cx: &mut Context<Self>,
 9570    ) {
 9571        let weak_editor = cx.weak_entity();
 9572        let bp_prompt = cx.new(|cx| {
 9573            BreakpointPromptEditor::new(
 9574                weak_editor,
 9575                anchor,
 9576                breakpoint.clone(),
 9577                edit_action,
 9578                window,
 9579                cx,
 9580            )
 9581        });
 9582
 9583        let height = bp_prompt.update(cx, |this, cx| {
 9584            this.prompt
 9585                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9586        });
 9587        let cloned_prompt = bp_prompt.clone();
 9588        let blocks = vec![BlockProperties {
 9589            style: BlockStyle::Sticky,
 9590            placement: BlockPlacement::Above(anchor),
 9591            height: Some(height),
 9592            render: Arc::new(move |cx| {
 9593                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9594                cloned_prompt.clone().into_any_element()
 9595            }),
 9596            priority: 0,
 9597            render_in_minimap: true,
 9598        }];
 9599
 9600        let focus_handle = bp_prompt.focus_handle(cx);
 9601        window.focus(&focus_handle);
 9602
 9603        let block_ids = self.insert_blocks(blocks, None, cx);
 9604        bp_prompt.update(cx, |prompt, _| {
 9605            prompt.add_block_ids(block_ids);
 9606        });
 9607    }
 9608
 9609    pub(crate) fn breakpoint_at_row(
 9610        &self,
 9611        row: u32,
 9612        window: &mut Window,
 9613        cx: &mut Context<Self>,
 9614    ) -> Option<(Anchor, Breakpoint)> {
 9615        let snapshot = self.snapshot(window, cx);
 9616        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9617
 9618        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9619    }
 9620
 9621    pub(crate) fn breakpoint_at_anchor(
 9622        &self,
 9623        breakpoint_position: Anchor,
 9624        snapshot: &EditorSnapshot,
 9625        cx: &mut Context<Self>,
 9626    ) -> Option<(Anchor, Breakpoint)> {
 9627        let project = self.project.clone()?;
 9628
 9629        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9630            snapshot
 9631                .buffer_snapshot
 9632                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9633        })?;
 9634
 9635        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9636        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9637        let buffer_snapshot = buffer.read(cx).snapshot();
 9638
 9639        let row = buffer_snapshot
 9640            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9641            .row;
 9642
 9643        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9644        let anchor_end = snapshot
 9645            .buffer_snapshot
 9646            .anchor_after(Point::new(row, line_len));
 9647
 9648        let bp = self
 9649            .breakpoint_store
 9650            .as_ref()?
 9651            .read_with(cx, |breakpoint_store, cx| {
 9652                breakpoint_store
 9653                    .breakpoints(
 9654                        &buffer,
 9655                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9656                        &buffer_snapshot,
 9657                        cx,
 9658                    )
 9659                    .next()
 9660                    .and_then(|(bp, _)| {
 9661                        let breakpoint_row = buffer_snapshot
 9662                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9663                            .row;
 9664
 9665                        if breakpoint_row == row {
 9666                            snapshot
 9667                                .buffer_snapshot
 9668                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9669                                .map(|position| (position, bp.bp.clone()))
 9670                        } else {
 9671                            None
 9672                        }
 9673                    })
 9674            });
 9675        bp
 9676    }
 9677
 9678    pub fn edit_log_breakpoint(
 9679        &mut self,
 9680        _: &EditLogBreakpoint,
 9681        window: &mut Window,
 9682        cx: &mut Context<Self>,
 9683    ) {
 9684        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9685            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9686                message: None,
 9687                state: BreakpointState::Enabled,
 9688                condition: None,
 9689                hit_condition: None,
 9690            });
 9691
 9692            self.add_edit_breakpoint_block(
 9693                anchor,
 9694                &breakpoint,
 9695                BreakpointPromptEditAction::Log,
 9696                window,
 9697                cx,
 9698            );
 9699        }
 9700    }
 9701
 9702    fn breakpoints_at_cursors(
 9703        &self,
 9704        window: &mut Window,
 9705        cx: &mut Context<Self>,
 9706    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9707        let snapshot = self.snapshot(window, cx);
 9708        let cursors = self
 9709            .selections
 9710            .disjoint_anchors()
 9711            .into_iter()
 9712            .map(|selection| {
 9713                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9714
 9715                let breakpoint_position = self
 9716                    .breakpoint_at_row(cursor_position.row, window, cx)
 9717                    .map(|bp| bp.0)
 9718                    .unwrap_or_else(|| {
 9719                        snapshot
 9720                            .display_snapshot
 9721                            .buffer_snapshot
 9722                            .anchor_after(Point::new(cursor_position.row, 0))
 9723                    });
 9724
 9725                let breakpoint = self
 9726                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9727                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9728
 9729                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9730            })
 9731            // 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.
 9732            .collect::<HashMap<Anchor, _>>();
 9733
 9734        cursors.into_iter().collect()
 9735    }
 9736
 9737    pub fn enable_breakpoint(
 9738        &mut self,
 9739        _: &crate::actions::EnableBreakpoint,
 9740        window: &mut Window,
 9741        cx: &mut Context<Self>,
 9742    ) {
 9743        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9744            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9745                continue;
 9746            };
 9747            self.edit_breakpoint_at_anchor(
 9748                anchor,
 9749                breakpoint,
 9750                BreakpointEditAction::InvertState,
 9751                cx,
 9752            );
 9753        }
 9754    }
 9755
 9756    pub fn disable_breakpoint(
 9757        &mut self,
 9758        _: &crate::actions::DisableBreakpoint,
 9759        window: &mut Window,
 9760        cx: &mut Context<Self>,
 9761    ) {
 9762        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9763            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9764                continue;
 9765            };
 9766            self.edit_breakpoint_at_anchor(
 9767                anchor,
 9768                breakpoint,
 9769                BreakpointEditAction::InvertState,
 9770                cx,
 9771            );
 9772        }
 9773    }
 9774
 9775    pub fn toggle_breakpoint(
 9776        &mut self,
 9777        _: &crate::actions::ToggleBreakpoint,
 9778        window: &mut Window,
 9779        cx: &mut Context<Self>,
 9780    ) {
 9781        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9782            if let Some(breakpoint) = breakpoint {
 9783                self.edit_breakpoint_at_anchor(
 9784                    anchor,
 9785                    breakpoint,
 9786                    BreakpointEditAction::Toggle,
 9787                    cx,
 9788                );
 9789            } else {
 9790                self.edit_breakpoint_at_anchor(
 9791                    anchor,
 9792                    Breakpoint::new_standard(),
 9793                    BreakpointEditAction::Toggle,
 9794                    cx,
 9795                );
 9796            }
 9797        }
 9798    }
 9799
 9800    pub fn edit_breakpoint_at_anchor(
 9801        &mut self,
 9802        breakpoint_position: Anchor,
 9803        breakpoint: Breakpoint,
 9804        edit_action: BreakpointEditAction,
 9805        cx: &mut Context<Self>,
 9806    ) {
 9807        let Some(breakpoint_store) = &self.breakpoint_store else {
 9808            return;
 9809        };
 9810
 9811        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9812            if breakpoint_position == Anchor::min() {
 9813                self.buffer()
 9814                    .read(cx)
 9815                    .excerpt_buffer_ids()
 9816                    .into_iter()
 9817                    .next()
 9818            } else {
 9819                None
 9820            }
 9821        }) else {
 9822            return;
 9823        };
 9824
 9825        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9826            return;
 9827        };
 9828
 9829        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9830            breakpoint_store.toggle_breakpoint(
 9831                buffer,
 9832                BreakpointWithPosition {
 9833                    position: breakpoint_position.text_anchor,
 9834                    bp: breakpoint,
 9835                },
 9836                edit_action,
 9837                cx,
 9838            );
 9839        });
 9840
 9841        cx.notify();
 9842    }
 9843
 9844    #[cfg(any(test, feature = "test-support"))]
 9845    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9846        self.breakpoint_store.clone()
 9847    }
 9848
 9849    pub fn prepare_restore_change(
 9850        &self,
 9851        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9852        hunk: &MultiBufferDiffHunk,
 9853        cx: &mut App,
 9854    ) -> Option<()> {
 9855        if hunk.is_created_file() {
 9856            return None;
 9857        }
 9858        let buffer = self.buffer.read(cx);
 9859        let diff = buffer.diff_for(hunk.buffer_id)?;
 9860        let buffer = buffer.buffer(hunk.buffer_id)?;
 9861        let buffer = buffer.read(cx);
 9862        let original_text = diff
 9863            .read(cx)
 9864            .base_text()
 9865            .as_rope()
 9866            .slice(hunk.diff_base_byte_range.clone());
 9867        let buffer_snapshot = buffer.snapshot();
 9868        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9869        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9870            probe
 9871                .0
 9872                .start
 9873                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9874                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9875        }) {
 9876            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9877            Some(())
 9878        } else {
 9879            None
 9880        }
 9881    }
 9882
 9883    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9884        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9885    }
 9886
 9887    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9888        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9889    }
 9890
 9891    fn manipulate_lines<Fn>(
 9892        &mut self,
 9893        window: &mut Window,
 9894        cx: &mut Context<Self>,
 9895        mut callback: Fn,
 9896    ) where
 9897        Fn: FnMut(&mut Vec<&str>),
 9898    {
 9899        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9900
 9901        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9902        let buffer = self.buffer.read(cx).snapshot(cx);
 9903
 9904        let mut edits = Vec::new();
 9905
 9906        let selections = self.selections.all::<Point>(cx);
 9907        let mut selections = selections.iter().peekable();
 9908        let mut contiguous_row_selections = Vec::new();
 9909        let mut new_selections = Vec::new();
 9910        let mut added_lines = 0;
 9911        let mut removed_lines = 0;
 9912
 9913        while let Some(selection) = selections.next() {
 9914            let (start_row, end_row) = consume_contiguous_rows(
 9915                &mut contiguous_row_selections,
 9916                selection,
 9917                &display_map,
 9918                &mut selections,
 9919            );
 9920
 9921            let start_point = Point::new(start_row.0, 0);
 9922            let end_point = Point::new(
 9923                end_row.previous_row().0,
 9924                buffer.line_len(end_row.previous_row()),
 9925            );
 9926            let text = buffer
 9927                .text_for_range(start_point..end_point)
 9928                .collect::<String>();
 9929
 9930            let mut lines = text.split('\n').collect_vec();
 9931
 9932            let lines_before = lines.len();
 9933            callback(&mut lines);
 9934            let lines_after = lines.len();
 9935
 9936            edits.push((start_point..end_point, lines.join("\n")));
 9937
 9938            // Selections must change based on added and removed line count
 9939            let start_row =
 9940                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9941            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9942            new_selections.push(Selection {
 9943                id: selection.id,
 9944                start: start_row,
 9945                end: end_row,
 9946                goal: SelectionGoal::None,
 9947                reversed: selection.reversed,
 9948            });
 9949
 9950            if lines_after > lines_before {
 9951                added_lines += lines_after - lines_before;
 9952            } else if lines_before > lines_after {
 9953                removed_lines += lines_before - lines_after;
 9954            }
 9955        }
 9956
 9957        self.transact(window, cx, |this, window, cx| {
 9958            let buffer = this.buffer.update(cx, |buffer, cx| {
 9959                buffer.edit(edits, None, cx);
 9960                buffer.snapshot(cx)
 9961            });
 9962
 9963            // Recalculate offsets on newly edited buffer
 9964            let new_selections = new_selections
 9965                .iter()
 9966                .map(|s| {
 9967                    let start_point = Point::new(s.start.0, 0);
 9968                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9969                    Selection {
 9970                        id: s.id,
 9971                        start: buffer.point_to_offset(start_point),
 9972                        end: buffer.point_to_offset(end_point),
 9973                        goal: s.goal,
 9974                        reversed: s.reversed,
 9975                    }
 9976                })
 9977                .collect();
 9978
 9979            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9980                s.select(new_selections);
 9981            });
 9982
 9983            this.request_autoscroll(Autoscroll::fit(), cx);
 9984        });
 9985    }
 9986
 9987    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9988        self.manipulate_text(window, cx, |text| {
 9989            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
 9990            if has_upper_case_characters {
 9991                text.to_lowercase()
 9992            } else {
 9993                text.to_uppercase()
 9994            }
 9995        })
 9996    }
 9997
 9998    pub fn convert_to_upper_case(
 9999        &mut self,
10000        _: &ConvertToUpperCase,
10001        window: &mut Window,
10002        cx: &mut Context<Self>,
10003    ) {
10004        self.manipulate_text(window, cx, |text| text.to_uppercase())
10005    }
10006
10007    pub fn convert_to_lower_case(
10008        &mut self,
10009        _: &ConvertToLowerCase,
10010        window: &mut Window,
10011        cx: &mut Context<Self>,
10012    ) {
10013        self.manipulate_text(window, cx, |text| text.to_lowercase())
10014    }
10015
10016    pub fn convert_to_title_case(
10017        &mut self,
10018        _: &ConvertToTitleCase,
10019        window: &mut Window,
10020        cx: &mut Context<Self>,
10021    ) {
10022        self.manipulate_text(window, cx, |text| {
10023            text.split('\n')
10024                .map(|line| line.to_case(Case::Title))
10025                .join("\n")
10026        })
10027    }
10028
10029    pub fn convert_to_snake_case(
10030        &mut self,
10031        _: &ConvertToSnakeCase,
10032        window: &mut Window,
10033        cx: &mut Context<Self>,
10034    ) {
10035        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10036    }
10037
10038    pub fn convert_to_kebab_case(
10039        &mut self,
10040        _: &ConvertToKebabCase,
10041        window: &mut Window,
10042        cx: &mut Context<Self>,
10043    ) {
10044        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10045    }
10046
10047    pub fn convert_to_upper_camel_case(
10048        &mut self,
10049        _: &ConvertToUpperCamelCase,
10050        window: &mut Window,
10051        cx: &mut Context<Self>,
10052    ) {
10053        self.manipulate_text(window, cx, |text| {
10054            text.split('\n')
10055                .map(|line| line.to_case(Case::UpperCamel))
10056                .join("\n")
10057        })
10058    }
10059
10060    pub fn convert_to_lower_camel_case(
10061        &mut self,
10062        _: &ConvertToLowerCamelCase,
10063        window: &mut Window,
10064        cx: &mut Context<Self>,
10065    ) {
10066        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10067    }
10068
10069    pub fn convert_to_opposite_case(
10070        &mut self,
10071        _: &ConvertToOppositeCase,
10072        window: &mut Window,
10073        cx: &mut Context<Self>,
10074    ) {
10075        self.manipulate_text(window, cx, |text| {
10076            text.chars()
10077                .fold(String::with_capacity(text.len()), |mut t, c| {
10078                    if c.is_uppercase() {
10079                        t.extend(c.to_lowercase());
10080                    } else {
10081                        t.extend(c.to_uppercase());
10082                    }
10083                    t
10084                })
10085        })
10086    }
10087
10088    pub fn convert_to_rot13(
10089        &mut self,
10090        _: &ConvertToRot13,
10091        window: &mut Window,
10092        cx: &mut Context<Self>,
10093    ) {
10094        self.manipulate_text(window, cx, |text| {
10095            text.chars()
10096                .map(|c| match c {
10097                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10098                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10099                    _ => c,
10100                })
10101                .collect()
10102        })
10103    }
10104
10105    pub fn convert_to_rot47(
10106        &mut self,
10107        _: &ConvertToRot47,
10108        window: &mut Window,
10109        cx: &mut Context<Self>,
10110    ) {
10111        self.manipulate_text(window, cx, |text| {
10112            text.chars()
10113                .map(|c| {
10114                    let code_point = c as u32;
10115                    if code_point >= 33 && code_point <= 126 {
10116                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10117                    }
10118                    c
10119                })
10120                .collect()
10121        })
10122    }
10123
10124    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10125    where
10126        Fn: FnMut(&str) -> String,
10127    {
10128        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10129        let buffer = self.buffer.read(cx).snapshot(cx);
10130
10131        let mut new_selections = Vec::new();
10132        let mut edits = Vec::new();
10133        let mut selection_adjustment = 0i32;
10134
10135        for selection in self.selections.all::<usize>(cx) {
10136            let selection_is_empty = selection.is_empty();
10137
10138            let (start, end) = if selection_is_empty {
10139                let word_range = movement::surrounding_word(
10140                    &display_map,
10141                    selection.start.to_display_point(&display_map),
10142                );
10143                let start = word_range.start.to_offset(&display_map, Bias::Left);
10144                let end = word_range.end.to_offset(&display_map, Bias::Left);
10145                (start, end)
10146            } else {
10147                (selection.start, selection.end)
10148            };
10149
10150            let text = buffer.text_for_range(start..end).collect::<String>();
10151            let old_length = text.len() as i32;
10152            let text = callback(&text);
10153
10154            new_selections.push(Selection {
10155                start: (start as i32 - selection_adjustment) as usize,
10156                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10157                goal: SelectionGoal::None,
10158                ..selection
10159            });
10160
10161            selection_adjustment += old_length - text.len() as i32;
10162
10163            edits.push((start..end, text));
10164        }
10165
10166        self.transact(window, cx, |this, window, cx| {
10167            this.buffer.update(cx, |buffer, cx| {
10168                buffer.edit(edits, None, cx);
10169            });
10170
10171            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10172                s.select(new_selections);
10173            });
10174
10175            this.request_autoscroll(Autoscroll::fit(), cx);
10176        });
10177    }
10178
10179    pub fn duplicate(
10180        &mut self,
10181        upwards: bool,
10182        whole_lines: bool,
10183        window: &mut Window,
10184        cx: &mut Context<Self>,
10185    ) {
10186        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10187
10188        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10189        let buffer = &display_map.buffer_snapshot;
10190        let selections = self.selections.all::<Point>(cx);
10191
10192        let mut edits = Vec::new();
10193        let mut selections_iter = selections.iter().peekable();
10194        while let Some(selection) = selections_iter.next() {
10195            let mut rows = selection.spanned_rows(false, &display_map);
10196            // duplicate line-wise
10197            if whole_lines || selection.start == selection.end {
10198                // Avoid duplicating the same lines twice.
10199                while let Some(next_selection) = selections_iter.peek() {
10200                    let next_rows = next_selection.spanned_rows(false, &display_map);
10201                    if next_rows.start < rows.end {
10202                        rows.end = next_rows.end;
10203                        selections_iter.next().unwrap();
10204                    } else {
10205                        break;
10206                    }
10207                }
10208
10209                // Copy the text from the selected row region and splice it either at the start
10210                // or end of the region.
10211                let start = Point::new(rows.start.0, 0);
10212                let end = Point::new(
10213                    rows.end.previous_row().0,
10214                    buffer.line_len(rows.end.previous_row()),
10215                );
10216                let text = buffer
10217                    .text_for_range(start..end)
10218                    .chain(Some("\n"))
10219                    .collect::<String>();
10220                let insert_location = if upwards {
10221                    Point::new(rows.end.0, 0)
10222                } else {
10223                    start
10224                };
10225                edits.push((insert_location..insert_location, text));
10226            } else {
10227                // duplicate character-wise
10228                let start = selection.start;
10229                let end = selection.end;
10230                let text = buffer.text_for_range(start..end).collect::<String>();
10231                edits.push((selection.end..selection.end, text));
10232            }
10233        }
10234
10235        self.transact(window, cx, |this, _, cx| {
10236            this.buffer.update(cx, |buffer, cx| {
10237                buffer.edit(edits, None, cx);
10238            });
10239
10240            this.request_autoscroll(Autoscroll::fit(), cx);
10241        });
10242    }
10243
10244    pub fn duplicate_line_up(
10245        &mut self,
10246        _: &DuplicateLineUp,
10247        window: &mut Window,
10248        cx: &mut Context<Self>,
10249    ) {
10250        self.duplicate(true, true, window, cx);
10251    }
10252
10253    pub fn duplicate_line_down(
10254        &mut self,
10255        _: &DuplicateLineDown,
10256        window: &mut Window,
10257        cx: &mut Context<Self>,
10258    ) {
10259        self.duplicate(false, true, window, cx);
10260    }
10261
10262    pub fn duplicate_selection(
10263        &mut self,
10264        _: &DuplicateSelection,
10265        window: &mut Window,
10266        cx: &mut Context<Self>,
10267    ) {
10268        self.duplicate(false, false, window, cx);
10269    }
10270
10271    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10272        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10273
10274        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10275        let buffer = self.buffer.read(cx).snapshot(cx);
10276
10277        let mut edits = Vec::new();
10278        let mut unfold_ranges = Vec::new();
10279        let mut refold_creases = Vec::new();
10280
10281        let selections = self.selections.all::<Point>(cx);
10282        let mut selections = selections.iter().peekable();
10283        let mut contiguous_row_selections = Vec::new();
10284        let mut new_selections = Vec::new();
10285
10286        while let Some(selection) = selections.next() {
10287            // Find all the selections that span a contiguous row range
10288            let (start_row, end_row) = consume_contiguous_rows(
10289                &mut contiguous_row_selections,
10290                selection,
10291                &display_map,
10292                &mut selections,
10293            );
10294
10295            // Move the text spanned by the row range to be before the line preceding the row range
10296            if start_row.0 > 0 {
10297                let range_to_move = Point::new(
10298                    start_row.previous_row().0,
10299                    buffer.line_len(start_row.previous_row()),
10300                )
10301                    ..Point::new(
10302                        end_row.previous_row().0,
10303                        buffer.line_len(end_row.previous_row()),
10304                    );
10305                let insertion_point = display_map
10306                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10307                    .0;
10308
10309                // Don't move lines across excerpts
10310                if buffer
10311                    .excerpt_containing(insertion_point..range_to_move.end)
10312                    .is_some()
10313                {
10314                    let text = buffer
10315                        .text_for_range(range_to_move.clone())
10316                        .flat_map(|s| s.chars())
10317                        .skip(1)
10318                        .chain(['\n'])
10319                        .collect::<String>();
10320
10321                    edits.push((
10322                        buffer.anchor_after(range_to_move.start)
10323                            ..buffer.anchor_before(range_to_move.end),
10324                        String::new(),
10325                    ));
10326                    let insertion_anchor = buffer.anchor_after(insertion_point);
10327                    edits.push((insertion_anchor..insertion_anchor, text));
10328
10329                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10330
10331                    // Move selections up
10332                    new_selections.extend(contiguous_row_selections.drain(..).map(
10333                        |mut selection| {
10334                            selection.start.row -= row_delta;
10335                            selection.end.row -= row_delta;
10336                            selection
10337                        },
10338                    ));
10339
10340                    // Move folds up
10341                    unfold_ranges.push(range_to_move.clone());
10342                    for fold in display_map.folds_in_range(
10343                        buffer.anchor_before(range_to_move.start)
10344                            ..buffer.anchor_after(range_to_move.end),
10345                    ) {
10346                        let mut start = fold.range.start.to_point(&buffer);
10347                        let mut end = fold.range.end.to_point(&buffer);
10348                        start.row -= row_delta;
10349                        end.row -= row_delta;
10350                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10351                    }
10352                }
10353            }
10354
10355            // If we didn't move line(s), preserve the existing selections
10356            new_selections.append(&mut contiguous_row_selections);
10357        }
10358
10359        self.transact(window, cx, |this, window, cx| {
10360            this.unfold_ranges(&unfold_ranges, true, true, cx);
10361            this.buffer.update(cx, |buffer, cx| {
10362                for (range, text) in edits {
10363                    buffer.edit([(range, text)], None, cx);
10364                }
10365            });
10366            this.fold_creases(refold_creases, true, window, cx);
10367            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10368                s.select(new_selections);
10369            })
10370        });
10371    }
10372
10373    pub fn move_line_down(
10374        &mut self,
10375        _: &MoveLineDown,
10376        window: &mut Window,
10377        cx: &mut Context<Self>,
10378    ) {
10379        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10380
10381        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10382        let buffer = self.buffer.read(cx).snapshot(cx);
10383
10384        let mut edits = Vec::new();
10385        let mut unfold_ranges = Vec::new();
10386        let mut refold_creases = Vec::new();
10387
10388        let selections = self.selections.all::<Point>(cx);
10389        let mut selections = selections.iter().peekable();
10390        let mut contiguous_row_selections = Vec::new();
10391        let mut new_selections = Vec::new();
10392
10393        while let Some(selection) = selections.next() {
10394            // Find all the selections that span a contiguous row range
10395            let (start_row, end_row) = consume_contiguous_rows(
10396                &mut contiguous_row_selections,
10397                selection,
10398                &display_map,
10399                &mut selections,
10400            );
10401
10402            // Move the text spanned by the row range to be after the last line of the row range
10403            if end_row.0 <= buffer.max_point().row {
10404                let range_to_move =
10405                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10406                let insertion_point = display_map
10407                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10408                    .0;
10409
10410                // Don't move lines across excerpt boundaries
10411                if buffer
10412                    .excerpt_containing(range_to_move.start..insertion_point)
10413                    .is_some()
10414                {
10415                    let mut text = String::from("\n");
10416                    text.extend(buffer.text_for_range(range_to_move.clone()));
10417                    text.pop(); // Drop trailing newline
10418                    edits.push((
10419                        buffer.anchor_after(range_to_move.start)
10420                            ..buffer.anchor_before(range_to_move.end),
10421                        String::new(),
10422                    ));
10423                    let insertion_anchor = buffer.anchor_after(insertion_point);
10424                    edits.push((insertion_anchor..insertion_anchor, text));
10425
10426                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10427
10428                    // Move selections down
10429                    new_selections.extend(contiguous_row_selections.drain(..).map(
10430                        |mut selection| {
10431                            selection.start.row += row_delta;
10432                            selection.end.row += row_delta;
10433                            selection
10434                        },
10435                    ));
10436
10437                    // Move folds down
10438                    unfold_ranges.push(range_to_move.clone());
10439                    for fold in display_map.folds_in_range(
10440                        buffer.anchor_before(range_to_move.start)
10441                            ..buffer.anchor_after(range_to_move.end),
10442                    ) {
10443                        let mut start = fold.range.start.to_point(&buffer);
10444                        let mut end = fold.range.end.to_point(&buffer);
10445                        start.row += row_delta;
10446                        end.row += row_delta;
10447                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10448                    }
10449                }
10450            }
10451
10452            // If we didn't move line(s), preserve the existing selections
10453            new_selections.append(&mut contiguous_row_selections);
10454        }
10455
10456        self.transact(window, cx, |this, window, cx| {
10457            this.unfold_ranges(&unfold_ranges, true, true, cx);
10458            this.buffer.update(cx, |buffer, cx| {
10459                for (range, text) in edits {
10460                    buffer.edit([(range, text)], None, cx);
10461                }
10462            });
10463            this.fold_creases(refold_creases, true, window, cx);
10464            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10465                s.select(new_selections)
10466            });
10467        });
10468    }
10469
10470    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10471        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10472        let text_layout_details = &self.text_layout_details(window);
10473        self.transact(window, cx, |this, window, cx| {
10474            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10475                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10476                s.move_with(|display_map, selection| {
10477                    if !selection.is_empty() {
10478                        return;
10479                    }
10480
10481                    let mut head = selection.head();
10482                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10483                    if head.column() == display_map.line_len(head.row()) {
10484                        transpose_offset = display_map
10485                            .buffer_snapshot
10486                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10487                    }
10488
10489                    if transpose_offset == 0 {
10490                        return;
10491                    }
10492
10493                    *head.column_mut() += 1;
10494                    head = display_map.clip_point(head, Bias::Right);
10495                    let goal = SelectionGoal::HorizontalPosition(
10496                        display_map
10497                            .x_for_display_point(head, text_layout_details)
10498                            .into(),
10499                    );
10500                    selection.collapse_to(head, goal);
10501
10502                    let transpose_start = display_map
10503                        .buffer_snapshot
10504                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10505                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10506                        let transpose_end = display_map
10507                            .buffer_snapshot
10508                            .clip_offset(transpose_offset + 1, Bias::Right);
10509                        if let Some(ch) =
10510                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10511                        {
10512                            edits.push((transpose_start..transpose_offset, String::new()));
10513                            edits.push((transpose_end..transpose_end, ch.to_string()));
10514                        }
10515                    }
10516                });
10517                edits
10518            });
10519            this.buffer
10520                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10521            let selections = this.selections.all::<usize>(cx);
10522            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10523                s.select(selections);
10524            });
10525        });
10526    }
10527
10528    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10529        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10530        self.rewrap_impl(RewrapOptions::default(), cx)
10531    }
10532
10533    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10534        let buffer = self.buffer.read(cx).snapshot(cx);
10535        let selections = self.selections.all::<Point>(cx);
10536        let mut selections = selections.iter().peekable();
10537
10538        let mut edits = Vec::new();
10539        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10540
10541        while let Some(selection) = selections.next() {
10542            let mut start_row = selection.start.row;
10543            let mut end_row = selection.end.row;
10544
10545            // Skip selections that overlap with a range that has already been rewrapped.
10546            let selection_range = start_row..end_row;
10547            if rewrapped_row_ranges
10548                .iter()
10549                .any(|range| range.overlaps(&selection_range))
10550            {
10551                continue;
10552            }
10553
10554            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10555
10556            // Since not all lines in the selection may be at the same indent
10557            // level, choose the indent size that is the most common between all
10558            // of the lines.
10559            //
10560            // If there is a tie, we use the deepest indent.
10561            let (indent_size, indent_end) = {
10562                let mut indent_size_occurrences = HashMap::default();
10563                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10564
10565                for row in start_row..=end_row {
10566                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10567                    rows_by_indent_size.entry(indent).or_default().push(row);
10568                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10569                }
10570
10571                let indent_size = indent_size_occurrences
10572                    .into_iter()
10573                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10574                    .map(|(indent, _)| indent)
10575                    .unwrap_or_default();
10576                let row = rows_by_indent_size[&indent_size][0];
10577                let indent_end = Point::new(row, indent_size.len);
10578
10579                (indent_size, indent_end)
10580            };
10581
10582            let mut line_prefix = indent_size.chars().collect::<String>();
10583
10584            let mut inside_comment = false;
10585            if let Some(comment_prefix) =
10586                buffer
10587                    .language_scope_at(selection.head())
10588                    .and_then(|language| {
10589                        language
10590                            .line_comment_prefixes()
10591                            .iter()
10592                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10593                            .cloned()
10594                    })
10595            {
10596                line_prefix.push_str(&comment_prefix);
10597                inside_comment = true;
10598            }
10599
10600            let language_settings = buffer.language_settings_at(selection.head(), cx);
10601            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10602                RewrapBehavior::InComments => inside_comment,
10603                RewrapBehavior::InSelections => !selection.is_empty(),
10604                RewrapBehavior::Anywhere => true,
10605            };
10606
10607            let should_rewrap = options.override_language_settings
10608                || allow_rewrap_based_on_language
10609                || self.hard_wrap.is_some();
10610            if !should_rewrap {
10611                continue;
10612            }
10613
10614            if selection.is_empty() {
10615                'expand_upwards: while start_row > 0 {
10616                    let prev_row = start_row - 1;
10617                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10618                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10619                    {
10620                        start_row = prev_row;
10621                    } else {
10622                        break 'expand_upwards;
10623                    }
10624                }
10625
10626                'expand_downwards: while end_row < buffer.max_point().row {
10627                    let next_row = end_row + 1;
10628                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10629                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10630                    {
10631                        end_row = next_row;
10632                    } else {
10633                        break 'expand_downwards;
10634                    }
10635                }
10636            }
10637
10638            let start = Point::new(start_row, 0);
10639            let start_offset = start.to_offset(&buffer);
10640            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10641            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10642            let Some(lines_without_prefixes) = selection_text
10643                .lines()
10644                .map(|line| {
10645                    line.strip_prefix(&line_prefix)
10646                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10647                        .with_context(|| {
10648                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10649                        })
10650                })
10651                .collect::<Result<Vec<_>, _>>()
10652                .log_err()
10653            else {
10654                continue;
10655            };
10656
10657            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10658                buffer
10659                    .language_settings_at(Point::new(start_row, 0), cx)
10660                    .preferred_line_length as usize
10661            });
10662            let wrapped_text = wrap_with_prefix(
10663                line_prefix,
10664                lines_without_prefixes.join("\n"),
10665                wrap_column,
10666                tab_size,
10667                options.preserve_existing_whitespace,
10668            );
10669
10670            // TODO: should always use char-based diff while still supporting cursor behavior that
10671            // matches vim.
10672            let mut diff_options = DiffOptions::default();
10673            if options.override_language_settings {
10674                diff_options.max_word_diff_len = 0;
10675                diff_options.max_word_diff_line_count = 0;
10676            } else {
10677                diff_options.max_word_diff_len = usize::MAX;
10678                diff_options.max_word_diff_line_count = usize::MAX;
10679            }
10680
10681            for (old_range, new_text) in
10682                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10683            {
10684                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10685                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10686                edits.push((edit_start..edit_end, new_text));
10687            }
10688
10689            rewrapped_row_ranges.push(start_row..=end_row);
10690        }
10691
10692        self.buffer
10693            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10694    }
10695
10696    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10697        let mut text = String::new();
10698        let buffer = self.buffer.read(cx).snapshot(cx);
10699        let mut selections = self.selections.all::<Point>(cx);
10700        let mut clipboard_selections = Vec::with_capacity(selections.len());
10701        {
10702            let max_point = buffer.max_point();
10703            let mut is_first = true;
10704            for selection in &mut selections {
10705                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10706                if is_entire_line {
10707                    selection.start = Point::new(selection.start.row, 0);
10708                    if !selection.is_empty() && selection.end.column == 0 {
10709                        selection.end = cmp::min(max_point, selection.end);
10710                    } else {
10711                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10712                    }
10713                    selection.goal = SelectionGoal::None;
10714                }
10715                if is_first {
10716                    is_first = false;
10717                } else {
10718                    text += "\n";
10719                }
10720                let mut len = 0;
10721                for chunk in buffer.text_for_range(selection.start..selection.end) {
10722                    text.push_str(chunk);
10723                    len += chunk.len();
10724                }
10725                clipboard_selections.push(ClipboardSelection {
10726                    len,
10727                    is_entire_line,
10728                    first_line_indent: buffer
10729                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10730                        .len,
10731                });
10732            }
10733        }
10734
10735        self.transact(window, cx, |this, window, cx| {
10736            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10737                s.select(selections);
10738            });
10739            this.insert("", window, cx);
10740        });
10741        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10742    }
10743
10744    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10745        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10746        let item = self.cut_common(window, cx);
10747        cx.write_to_clipboard(item);
10748    }
10749
10750    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10751        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10752        self.change_selections(None, window, cx, |s| {
10753            s.move_with(|snapshot, sel| {
10754                if sel.is_empty() {
10755                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10756                }
10757            });
10758        });
10759        let item = self.cut_common(window, cx);
10760        cx.set_global(KillRing(item))
10761    }
10762
10763    pub fn kill_ring_yank(
10764        &mut self,
10765        _: &KillRingYank,
10766        window: &mut Window,
10767        cx: &mut Context<Self>,
10768    ) {
10769        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10770        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10771            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10772                (kill_ring.text().to_string(), kill_ring.metadata_json())
10773            } else {
10774                return;
10775            }
10776        } else {
10777            return;
10778        };
10779        self.do_paste(&text, metadata, false, window, cx);
10780    }
10781
10782    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10783        self.do_copy(true, cx);
10784    }
10785
10786    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10787        self.do_copy(false, cx);
10788    }
10789
10790    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10791        let selections = self.selections.all::<Point>(cx);
10792        let buffer = self.buffer.read(cx).read(cx);
10793        let mut text = String::new();
10794
10795        let mut clipboard_selections = Vec::with_capacity(selections.len());
10796        {
10797            let max_point = buffer.max_point();
10798            let mut is_first = true;
10799            for selection in &selections {
10800                let mut start = selection.start;
10801                let mut end = selection.end;
10802                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10803                if is_entire_line {
10804                    start = Point::new(start.row, 0);
10805                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10806                }
10807
10808                let mut trimmed_selections = Vec::new();
10809                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10810                    let row = MultiBufferRow(start.row);
10811                    let first_indent = buffer.indent_size_for_line(row);
10812                    if first_indent.len == 0 || start.column > first_indent.len {
10813                        trimmed_selections.push(start..end);
10814                    } else {
10815                        trimmed_selections.push(
10816                            Point::new(row.0, first_indent.len)
10817                                ..Point::new(row.0, buffer.line_len(row)),
10818                        );
10819                        for row in start.row + 1..=end.row {
10820                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10821                            if row == end.row {
10822                                line_len = end.column;
10823                            }
10824                            if line_len == 0 {
10825                                trimmed_selections
10826                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10827                                continue;
10828                            }
10829                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10830                            if row_indent_size.len >= first_indent.len {
10831                                trimmed_selections.push(
10832                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10833                                );
10834                            } else {
10835                                trimmed_selections.clear();
10836                                trimmed_selections.push(start..end);
10837                                break;
10838                            }
10839                        }
10840                    }
10841                } else {
10842                    trimmed_selections.push(start..end);
10843                }
10844
10845                for trimmed_range in trimmed_selections {
10846                    if is_first {
10847                        is_first = false;
10848                    } else {
10849                        text += "\n";
10850                    }
10851                    let mut len = 0;
10852                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10853                        text.push_str(chunk);
10854                        len += chunk.len();
10855                    }
10856                    clipboard_selections.push(ClipboardSelection {
10857                        len,
10858                        is_entire_line,
10859                        first_line_indent: buffer
10860                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10861                            .len,
10862                    });
10863                }
10864            }
10865        }
10866
10867        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10868            text,
10869            clipboard_selections,
10870        ));
10871    }
10872
10873    pub fn do_paste(
10874        &mut self,
10875        text: &String,
10876        clipboard_selections: Option<Vec<ClipboardSelection>>,
10877        handle_entire_lines: bool,
10878        window: &mut Window,
10879        cx: &mut Context<Self>,
10880    ) {
10881        if self.read_only(cx) {
10882            return;
10883        }
10884
10885        let clipboard_text = Cow::Borrowed(text);
10886
10887        self.transact(window, cx, |this, window, cx| {
10888            if let Some(mut clipboard_selections) = clipboard_selections {
10889                let old_selections = this.selections.all::<usize>(cx);
10890                let all_selections_were_entire_line =
10891                    clipboard_selections.iter().all(|s| s.is_entire_line);
10892                let first_selection_indent_column =
10893                    clipboard_selections.first().map(|s| s.first_line_indent);
10894                if clipboard_selections.len() != old_selections.len() {
10895                    clipboard_selections.drain(..);
10896                }
10897                let cursor_offset = this.selections.last::<usize>(cx).head();
10898                let mut auto_indent_on_paste = true;
10899
10900                this.buffer.update(cx, |buffer, cx| {
10901                    let snapshot = buffer.read(cx);
10902                    auto_indent_on_paste = snapshot
10903                        .language_settings_at(cursor_offset, cx)
10904                        .auto_indent_on_paste;
10905
10906                    let mut start_offset = 0;
10907                    let mut edits = Vec::new();
10908                    let mut original_indent_columns = Vec::new();
10909                    for (ix, selection) in old_selections.iter().enumerate() {
10910                        let to_insert;
10911                        let entire_line;
10912                        let original_indent_column;
10913                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10914                            let end_offset = start_offset + clipboard_selection.len;
10915                            to_insert = &clipboard_text[start_offset..end_offset];
10916                            entire_line = clipboard_selection.is_entire_line;
10917                            start_offset = end_offset + 1;
10918                            original_indent_column = Some(clipboard_selection.first_line_indent);
10919                        } else {
10920                            to_insert = clipboard_text.as_str();
10921                            entire_line = all_selections_were_entire_line;
10922                            original_indent_column = first_selection_indent_column
10923                        }
10924
10925                        // If the corresponding selection was empty when this slice of the
10926                        // clipboard text was written, then the entire line containing the
10927                        // selection was copied. If this selection is also currently empty,
10928                        // then paste the line before the current line of the buffer.
10929                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10930                            let column = selection.start.to_point(&snapshot).column as usize;
10931                            let line_start = selection.start - column;
10932                            line_start..line_start
10933                        } else {
10934                            selection.range()
10935                        };
10936
10937                        edits.push((range, to_insert));
10938                        original_indent_columns.push(original_indent_column);
10939                    }
10940                    drop(snapshot);
10941
10942                    buffer.edit(
10943                        edits,
10944                        if auto_indent_on_paste {
10945                            Some(AutoindentMode::Block {
10946                                original_indent_columns,
10947                            })
10948                        } else {
10949                            None
10950                        },
10951                        cx,
10952                    );
10953                });
10954
10955                let selections = this.selections.all::<usize>(cx);
10956                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10957                    s.select(selections)
10958                });
10959            } else {
10960                this.insert(&clipboard_text, window, cx);
10961            }
10962        });
10963    }
10964
10965    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10966        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10967        if let Some(item) = cx.read_from_clipboard() {
10968            let entries = item.entries();
10969
10970            match entries.first() {
10971                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10972                // of all the pasted entries.
10973                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10974                    .do_paste(
10975                        clipboard_string.text(),
10976                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10977                        true,
10978                        window,
10979                        cx,
10980                    ),
10981                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10982            }
10983        }
10984    }
10985
10986    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10987        if self.read_only(cx) {
10988            return;
10989        }
10990
10991        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10992
10993        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
10994            if let Some((selections, _)) =
10995                self.selection_history.transaction(transaction_id).cloned()
10996            {
10997                self.change_selections(None, window, cx, |s| {
10998                    s.select_anchors(selections.to_vec());
10999                });
11000            } else {
11001                log::error!(
11002                    "No entry in selection_history found for undo. \
11003                     This may correspond to a bug where undo does not update the selection. \
11004                     If this is occurring, please add details to \
11005                     https://github.com/zed-industries/zed/issues/22692"
11006                );
11007            }
11008            self.request_autoscroll(Autoscroll::fit(), cx);
11009            self.unmark_text(window, cx);
11010            self.refresh_inline_completion(true, false, window, cx);
11011            cx.emit(EditorEvent::Edited { transaction_id });
11012            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11013        }
11014    }
11015
11016    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11017        if self.read_only(cx) {
11018            return;
11019        }
11020
11021        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11022
11023        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11024            if let Some((_, Some(selections))) =
11025                self.selection_history.transaction(transaction_id).cloned()
11026            {
11027                self.change_selections(None, window, cx, |s| {
11028                    s.select_anchors(selections.to_vec());
11029                });
11030            } else {
11031                log::error!(
11032                    "No entry in selection_history found for redo. \
11033                     This may correspond to a bug where undo does not update the selection. \
11034                     If this is occurring, please add details to \
11035                     https://github.com/zed-industries/zed/issues/22692"
11036                );
11037            }
11038            self.request_autoscroll(Autoscroll::fit(), cx);
11039            self.unmark_text(window, cx);
11040            self.refresh_inline_completion(true, false, window, cx);
11041            cx.emit(EditorEvent::Edited { transaction_id });
11042        }
11043    }
11044
11045    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11046        self.buffer
11047            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11048    }
11049
11050    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11051        self.buffer
11052            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11053    }
11054
11055    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11056        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11057        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11058            s.move_with(|map, selection| {
11059                let cursor = if selection.is_empty() {
11060                    movement::left(map, selection.start)
11061                } else {
11062                    selection.start
11063                };
11064                selection.collapse_to(cursor, SelectionGoal::None);
11065            });
11066        })
11067    }
11068
11069    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11070        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11071        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11072            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11073        })
11074    }
11075
11076    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11077        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11078        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11079            s.move_with(|map, selection| {
11080                let cursor = if selection.is_empty() {
11081                    movement::right(map, selection.end)
11082                } else {
11083                    selection.end
11084                };
11085                selection.collapse_to(cursor, SelectionGoal::None)
11086            });
11087        })
11088    }
11089
11090    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11091        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11092        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11093            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11094        })
11095    }
11096
11097    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11098        if self.take_rename(true, window, cx).is_some() {
11099            return;
11100        }
11101
11102        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11103            cx.propagate();
11104            return;
11105        }
11106
11107        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11108
11109        let text_layout_details = &self.text_layout_details(window);
11110        let selection_count = self.selections.count();
11111        let first_selection = self.selections.first_anchor();
11112
11113        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11114            s.move_with(|map, selection| {
11115                if !selection.is_empty() {
11116                    selection.goal = SelectionGoal::None;
11117                }
11118                let (cursor, goal) = movement::up(
11119                    map,
11120                    selection.start,
11121                    selection.goal,
11122                    false,
11123                    text_layout_details,
11124                );
11125                selection.collapse_to(cursor, goal);
11126            });
11127        });
11128
11129        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11130        {
11131            cx.propagate();
11132        }
11133    }
11134
11135    pub fn move_up_by_lines(
11136        &mut self,
11137        action: &MoveUpByLines,
11138        window: &mut Window,
11139        cx: &mut Context<Self>,
11140    ) {
11141        if self.take_rename(true, window, cx).is_some() {
11142            return;
11143        }
11144
11145        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11146            cx.propagate();
11147            return;
11148        }
11149
11150        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11151
11152        let text_layout_details = &self.text_layout_details(window);
11153
11154        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11155            s.move_with(|map, selection| {
11156                if !selection.is_empty() {
11157                    selection.goal = SelectionGoal::None;
11158                }
11159                let (cursor, goal) = movement::up_by_rows(
11160                    map,
11161                    selection.start,
11162                    action.lines,
11163                    selection.goal,
11164                    false,
11165                    text_layout_details,
11166                );
11167                selection.collapse_to(cursor, goal);
11168            });
11169        })
11170    }
11171
11172    pub fn move_down_by_lines(
11173        &mut self,
11174        action: &MoveDownByLines,
11175        window: &mut Window,
11176        cx: &mut Context<Self>,
11177    ) {
11178        if self.take_rename(true, window, cx).is_some() {
11179            return;
11180        }
11181
11182        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11183            cx.propagate();
11184            return;
11185        }
11186
11187        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11188
11189        let text_layout_details = &self.text_layout_details(window);
11190
11191        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11192            s.move_with(|map, selection| {
11193                if !selection.is_empty() {
11194                    selection.goal = SelectionGoal::None;
11195                }
11196                let (cursor, goal) = movement::down_by_rows(
11197                    map,
11198                    selection.start,
11199                    action.lines,
11200                    selection.goal,
11201                    false,
11202                    text_layout_details,
11203                );
11204                selection.collapse_to(cursor, goal);
11205            });
11206        })
11207    }
11208
11209    pub fn select_down_by_lines(
11210        &mut self,
11211        action: &SelectDownByLines,
11212        window: &mut Window,
11213        cx: &mut Context<Self>,
11214    ) {
11215        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11216        let text_layout_details = &self.text_layout_details(window);
11217        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11218            s.move_heads_with(|map, head, goal| {
11219                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11220            })
11221        })
11222    }
11223
11224    pub fn select_up_by_lines(
11225        &mut self,
11226        action: &SelectUpByLines,
11227        window: &mut Window,
11228        cx: &mut Context<Self>,
11229    ) {
11230        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11231        let text_layout_details = &self.text_layout_details(window);
11232        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11233            s.move_heads_with(|map, head, goal| {
11234                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11235            })
11236        })
11237    }
11238
11239    pub fn select_page_up(
11240        &mut self,
11241        _: &SelectPageUp,
11242        window: &mut Window,
11243        cx: &mut Context<Self>,
11244    ) {
11245        let Some(row_count) = self.visible_row_count() else {
11246            return;
11247        };
11248
11249        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11250
11251        let text_layout_details = &self.text_layout_details(window);
11252
11253        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11254            s.move_heads_with(|map, head, goal| {
11255                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11256            })
11257        })
11258    }
11259
11260    pub fn move_page_up(
11261        &mut self,
11262        action: &MovePageUp,
11263        window: &mut Window,
11264        cx: &mut Context<Self>,
11265    ) {
11266        if self.take_rename(true, window, cx).is_some() {
11267            return;
11268        }
11269
11270        if self
11271            .context_menu
11272            .borrow_mut()
11273            .as_mut()
11274            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11275            .unwrap_or(false)
11276        {
11277            return;
11278        }
11279
11280        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11281            cx.propagate();
11282            return;
11283        }
11284
11285        let Some(row_count) = self.visible_row_count() else {
11286            return;
11287        };
11288
11289        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11290
11291        let autoscroll = if action.center_cursor {
11292            Autoscroll::center()
11293        } else {
11294            Autoscroll::fit()
11295        };
11296
11297        let text_layout_details = &self.text_layout_details(window);
11298
11299        self.change_selections(Some(autoscroll), window, cx, |s| {
11300            s.move_with(|map, selection| {
11301                if !selection.is_empty() {
11302                    selection.goal = SelectionGoal::None;
11303                }
11304                let (cursor, goal) = movement::up_by_rows(
11305                    map,
11306                    selection.end,
11307                    row_count,
11308                    selection.goal,
11309                    false,
11310                    text_layout_details,
11311                );
11312                selection.collapse_to(cursor, goal);
11313            });
11314        });
11315    }
11316
11317    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11318        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11319        let text_layout_details = &self.text_layout_details(window);
11320        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11321            s.move_heads_with(|map, head, goal| {
11322                movement::up(map, head, goal, false, text_layout_details)
11323            })
11324        })
11325    }
11326
11327    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11328        self.take_rename(true, window, cx);
11329
11330        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11331            cx.propagate();
11332            return;
11333        }
11334
11335        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11336
11337        let text_layout_details = &self.text_layout_details(window);
11338        let selection_count = self.selections.count();
11339        let first_selection = self.selections.first_anchor();
11340
11341        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11342            s.move_with(|map, selection| {
11343                if !selection.is_empty() {
11344                    selection.goal = SelectionGoal::None;
11345                }
11346                let (cursor, goal) = movement::down(
11347                    map,
11348                    selection.end,
11349                    selection.goal,
11350                    false,
11351                    text_layout_details,
11352                );
11353                selection.collapse_to(cursor, goal);
11354            });
11355        });
11356
11357        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11358        {
11359            cx.propagate();
11360        }
11361    }
11362
11363    pub fn select_page_down(
11364        &mut self,
11365        _: &SelectPageDown,
11366        window: &mut Window,
11367        cx: &mut Context<Self>,
11368    ) {
11369        let Some(row_count) = self.visible_row_count() else {
11370            return;
11371        };
11372
11373        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11374
11375        let text_layout_details = &self.text_layout_details(window);
11376
11377        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11378            s.move_heads_with(|map, head, goal| {
11379                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11380            })
11381        })
11382    }
11383
11384    pub fn move_page_down(
11385        &mut self,
11386        action: &MovePageDown,
11387        window: &mut Window,
11388        cx: &mut Context<Self>,
11389    ) {
11390        if self.take_rename(true, window, cx).is_some() {
11391            return;
11392        }
11393
11394        if self
11395            .context_menu
11396            .borrow_mut()
11397            .as_mut()
11398            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11399            .unwrap_or(false)
11400        {
11401            return;
11402        }
11403
11404        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11405            cx.propagate();
11406            return;
11407        }
11408
11409        let Some(row_count) = self.visible_row_count() else {
11410            return;
11411        };
11412
11413        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11414
11415        let autoscroll = if action.center_cursor {
11416            Autoscroll::center()
11417        } else {
11418            Autoscroll::fit()
11419        };
11420
11421        let text_layout_details = &self.text_layout_details(window);
11422        self.change_selections(Some(autoscroll), window, cx, |s| {
11423            s.move_with(|map, selection| {
11424                if !selection.is_empty() {
11425                    selection.goal = SelectionGoal::None;
11426                }
11427                let (cursor, goal) = movement::down_by_rows(
11428                    map,
11429                    selection.end,
11430                    row_count,
11431                    selection.goal,
11432                    false,
11433                    text_layout_details,
11434                );
11435                selection.collapse_to(cursor, goal);
11436            });
11437        });
11438    }
11439
11440    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11441        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11442        let text_layout_details = &self.text_layout_details(window);
11443        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11444            s.move_heads_with(|map, head, goal| {
11445                movement::down(map, head, goal, false, text_layout_details)
11446            })
11447        });
11448    }
11449
11450    pub fn context_menu_first(
11451        &mut self,
11452        _: &ContextMenuFirst,
11453        _window: &mut Window,
11454        cx: &mut Context<Self>,
11455    ) {
11456        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11457            context_menu.select_first(self.completion_provider.as_deref(), cx);
11458        }
11459    }
11460
11461    pub fn context_menu_prev(
11462        &mut self,
11463        _: &ContextMenuPrevious,
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_prev(self.completion_provider.as_deref(), cx);
11469        }
11470    }
11471
11472    pub fn context_menu_next(
11473        &mut self,
11474        _: &ContextMenuNext,
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_next(self.completion_provider.as_deref(), cx);
11480        }
11481    }
11482
11483    pub fn context_menu_last(
11484        &mut self,
11485        _: &ContextMenuLast,
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_last(self.completion_provider.as_deref(), cx);
11491        }
11492    }
11493
11494    pub fn move_to_previous_word_start(
11495        &mut self,
11496        _: &MoveToPreviousWordStart,
11497        window: &mut Window,
11498        cx: &mut Context<Self>,
11499    ) {
11500        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11501        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11502            s.move_cursors_with(|map, head, _| {
11503                (
11504                    movement::previous_word_start(map, head),
11505                    SelectionGoal::None,
11506                )
11507            });
11508        })
11509    }
11510
11511    pub fn move_to_previous_subword_start(
11512        &mut self,
11513        _: &MoveToPreviousSubwordStart,
11514        window: &mut Window,
11515        cx: &mut Context<Self>,
11516    ) {
11517        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11518        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11519            s.move_cursors_with(|map, head, _| {
11520                (
11521                    movement::previous_subword_start(map, head),
11522                    SelectionGoal::None,
11523                )
11524            });
11525        })
11526    }
11527
11528    pub fn select_to_previous_word_start(
11529        &mut self,
11530        _: &SelectToPreviousWordStart,
11531        window: &mut Window,
11532        cx: &mut Context<Self>,
11533    ) {
11534        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11535        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11536            s.move_heads_with(|map, head, _| {
11537                (
11538                    movement::previous_word_start(map, head),
11539                    SelectionGoal::None,
11540                )
11541            });
11542        })
11543    }
11544
11545    pub fn select_to_previous_subword_start(
11546        &mut self,
11547        _: &SelectToPreviousSubwordStart,
11548        window: &mut Window,
11549        cx: &mut Context<Self>,
11550    ) {
11551        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11552        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11553            s.move_heads_with(|map, head, _| {
11554                (
11555                    movement::previous_subword_start(map, head),
11556                    SelectionGoal::None,
11557                )
11558            });
11559        })
11560    }
11561
11562    pub fn delete_to_previous_word_start(
11563        &mut self,
11564        action: &DeleteToPreviousWordStart,
11565        window: &mut Window,
11566        cx: &mut Context<Self>,
11567    ) {
11568        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11569        self.transact(window, cx, |this, window, cx| {
11570            this.select_autoclose_pair(window, cx);
11571            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11572                s.move_with(|map, selection| {
11573                    if selection.is_empty() {
11574                        let cursor = if action.ignore_newlines {
11575                            movement::previous_word_start(map, selection.head())
11576                        } else {
11577                            movement::previous_word_start_or_newline(map, selection.head())
11578                        };
11579                        selection.set_head(cursor, SelectionGoal::None);
11580                    }
11581                });
11582            });
11583            this.insert("", window, cx);
11584        });
11585    }
11586
11587    pub fn delete_to_previous_subword_start(
11588        &mut self,
11589        _: &DeleteToPreviousSubwordStart,
11590        window: &mut Window,
11591        cx: &mut Context<Self>,
11592    ) {
11593        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11594        self.transact(window, cx, |this, window, cx| {
11595            this.select_autoclose_pair(window, cx);
11596            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11597                s.move_with(|map, selection| {
11598                    if selection.is_empty() {
11599                        let cursor = movement::previous_subword_start(map, selection.head());
11600                        selection.set_head(cursor, SelectionGoal::None);
11601                    }
11602                });
11603            });
11604            this.insert("", window, cx);
11605        });
11606    }
11607
11608    pub fn move_to_next_word_end(
11609        &mut self,
11610        _: &MoveToNextWordEnd,
11611        window: &mut Window,
11612        cx: &mut Context<Self>,
11613    ) {
11614        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11615        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11616            s.move_cursors_with(|map, head, _| {
11617                (movement::next_word_end(map, head), SelectionGoal::None)
11618            });
11619        })
11620    }
11621
11622    pub fn move_to_next_subword_end(
11623        &mut self,
11624        _: &MoveToNextSubwordEnd,
11625        window: &mut Window,
11626        cx: &mut Context<Self>,
11627    ) {
11628        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11629        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11630            s.move_cursors_with(|map, head, _| {
11631                (movement::next_subword_end(map, head), SelectionGoal::None)
11632            });
11633        })
11634    }
11635
11636    pub fn select_to_next_word_end(
11637        &mut self,
11638        _: &SelectToNextWordEnd,
11639        window: &mut Window,
11640        cx: &mut Context<Self>,
11641    ) {
11642        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11643        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11644            s.move_heads_with(|map, head, _| {
11645                (movement::next_word_end(map, head), SelectionGoal::None)
11646            });
11647        })
11648    }
11649
11650    pub fn select_to_next_subword_end(
11651        &mut self,
11652        _: &SelectToNextSubwordEnd,
11653        window: &mut Window,
11654        cx: &mut Context<Self>,
11655    ) {
11656        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11657        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11658            s.move_heads_with(|map, head, _| {
11659                (movement::next_subword_end(map, head), SelectionGoal::None)
11660            });
11661        })
11662    }
11663
11664    pub fn delete_to_next_word_end(
11665        &mut self,
11666        action: &DeleteToNextWordEnd,
11667        window: &mut Window,
11668        cx: &mut Context<Self>,
11669    ) {
11670        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11671        self.transact(window, cx, |this, window, cx| {
11672            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11673                s.move_with(|map, selection| {
11674                    if selection.is_empty() {
11675                        let cursor = if action.ignore_newlines {
11676                            movement::next_word_end(map, selection.head())
11677                        } else {
11678                            movement::next_word_end_or_newline(map, selection.head())
11679                        };
11680                        selection.set_head(cursor, SelectionGoal::None);
11681                    }
11682                });
11683            });
11684            this.insert("", window, cx);
11685        });
11686    }
11687
11688    pub fn delete_to_next_subword_end(
11689        &mut self,
11690        _: &DeleteToNextSubwordEnd,
11691        window: &mut Window,
11692        cx: &mut Context<Self>,
11693    ) {
11694        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11695        self.transact(window, cx, |this, window, cx| {
11696            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11697                s.move_with(|map, selection| {
11698                    if selection.is_empty() {
11699                        let cursor = movement::next_subword_end(map, selection.head());
11700                        selection.set_head(cursor, SelectionGoal::None);
11701                    }
11702                });
11703            });
11704            this.insert("", window, cx);
11705        });
11706    }
11707
11708    pub fn move_to_beginning_of_line(
11709        &mut self,
11710        action: &MoveToBeginningOfLine,
11711        window: &mut Window,
11712        cx: &mut Context<Self>,
11713    ) {
11714        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11715        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11716            s.move_cursors_with(|map, head, _| {
11717                (
11718                    movement::indented_line_beginning(
11719                        map,
11720                        head,
11721                        action.stop_at_soft_wraps,
11722                        action.stop_at_indent,
11723                    ),
11724                    SelectionGoal::None,
11725                )
11726            });
11727        })
11728    }
11729
11730    pub fn select_to_beginning_of_line(
11731        &mut self,
11732        action: &SelectToBeginningOfLine,
11733        window: &mut Window,
11734        cx: &mut Context<Self>,
11735    ) {
11736        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11737        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11738            s.move_heads_with(|map, head, _| {
11739                (
11740                    movement::indented_line_beginning(
11741                        map,
11742                        head,
11743                        action.stop_at_soft_wraps,
11744                        action.stop_at_indent,
11745                    ),
11746                    SelectionGoal::None,
11747                )
11748            });
11749        });
11750    }
11751
11752    pub fn delete_to_beginning_of_line(
11753        &mut self,
11754        action: &DeleteToBeginningOfLine,
11755        window: &mut Window,
11756        cx: &mut Context<Self>,
11757    ) {
11758        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11759        self.transact(window, cx, |this, window, cx| {
11760            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11761                s.move_with(|_, selection| {
11762                    selection.reversed = true;
11763                });
11764            });
11765
11766            this.select_to_beginning_of_line(
11767                &SelectToBeginningOfLine {
11768                    stop_at_soft_wraps: false,
11769                    stop_at_indent: action.stop_at_indent,
11770                },
11771                window,
11772                cx,
11773            );
11774            this.backspace(&Backspace, window, cx);
11775        });
11776    }
11777
11778    pub fn move_to_end_of_line(
11779        &mut self,
11780        action: &MoveToEndOfLine,
11781        window: &mut Window,
11782        cx: &mut Context<Self>,
11783    ) {
11784        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11785        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11786            s.move_cursors_with(|map, head, _| {
11787                (
11788                    movement::line_end(map, head, action.stop_at_soft_wraps),
11789                    SelectionGoal::None,
11790                )
11791            });
11792        })
11793    }
11794
11795    pub fn select_to_end_of_line(
11796        &mut self,
11797        action: &SelectToEndOfLine,
11798        window: &mut Window,
11799        cx: &mut Context<Self>,
11800    ) {
11801        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11802        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11803            s.move_heads_with(|map, head, _| {
11804                (
11805                    movement::line_end(map, head, action.stop_at_soft_wraps),
11806                    SelectionGoal::None,
11807                )
11808            });
11809        })
11810    }
11811
11812    pub fn delete_to_end_of_line(
11813        &mut self,
11814        _: &DeleteToEndOfLine,
11815        window: &mut Window,
11816        cx: &mut Context<Self>,
11817    ) {
11818        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11819        self.transact(window, cx, |this, window, cx| {
11820            this.select_to_end_of_line(
11821                &SelectToEndOfLine {
11822                    stop_at_soft_wraps: false,
11823                },
11824                window,
11825                cx,
11826            );
11827            this.delete(&Delete, window, cx);
11828        });
11829    }
11830
11831    pub fn cut_to_end_of_line(
11832        &mut self,
11833        _: &CutToEndOfLine,
11834        window: &mut Window,
11835        cx: &mut Context<Self>,
11836    ) {
11837        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11838        self.transact(window, cx, |this, window, cx| {
11839            this.select_to_end_of_line(
11840                &SelectToEndOfLine {
11841                    stop_at_soft_wraps: false,
11842                },
11843                window,
11844                cx,
11845            );
11846            this.cut(&Cut, window, cx);
11847        });
11848    }
11849
11850    pub fn move_to_start_of_paragraph(
11851        &mut self,
11852        _: &MoveToStartOfParagraph,
11853        window: &mut Window,
11854        cx: &mut Context<Self>,
11855    ) {
11856        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11857            cx.propagate();
11858            return;
11859        }
11860        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11861        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11862            s.move_with(|map, selection| {
11863                selection.collapse_to(
11864                    movement::start_of_paragraph(map, selection.head(), 1),
11865                    SelectionGoal::None,
11866                )
11867            });
11868        })
11869    }
11870
11871    pub fn move_to_end_of_paragraph(
11872        &mut self,
11873        _: &MoveToEndOfParagraph,
11874        window: &mut Window,
11875        cx: &mut Context<Self>,
11876    ) {
11877        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11878            cx.propagate();
11879            return;
11880        }
11881        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11882        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11883            s.move_with(|map, selection| {
11884                selection.collapse_to(
11885                    movement::end_of_paragraph(map, selection.head(), 1),
11886                    SelectionGoal::None,
11887                )
11888            });
11889        })
11890    }
11891
11892    pub fn select_to_start_of_paragraph(
11893        &mut self,
11894        _: &SelectToStartOfParagraph,
11895        window: &mut Window,
11896        cx: &mut Context<Self>,
11897    ) {
11898        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11899            cx.propagate();
11900            return;
11901        }
11902        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11903        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11904            s.move_heads_with(|map, head, _| {
11905                (
11906                    movement::start_of_paragraph(map, head, 1),
11907                    SelectionGoal::None,
11908                )
11909            });
11910        })
11911    }
11912
11913    pub fn select_to_end_of_paragraph(
11914        &mut self,
11915        _: &SelectToEndOfParagraph,
11916        window: &mut Window,
11917        cx: &mut Context<Self>,
11918    ) {
11919        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11920            cx.propagate();
11921            return;
11922        }
11923        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11924        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11925            s.move_heads_with(|map, head, _| {
11926                (
11927                    movement::end_of_paragraph(map, head, 1),
11928                    SelectionGoal::None,
11929                )
11930            });
11931        })
11932    }
11933
11934    pub fn move_to_start_of_excerpt(
11935        &mut self,
11936        _: &MoveToStartOfExcerpt,
11937        window: &mut Window,
11938        cx: &mut Context<Self>,
11939    ) {
11940        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11941            cx.propagate();
11942            return;
11943        }
11944        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11945        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11946            s.move_with(|map, selection| {
11947                selection.collapse_to(
11948                    movement::start_of_excerpt(
11949                        map,
11950                        selection.head(),
11951                        workspace::searchable::Direction::Prev,
11952                    ),
11953                    SelectionGoal::None,
11954                )
11955            });
11956        })
11957    }
11958
11959    pub fn move_to_start_of_next_excerpt(
11960        &mut self,
11961        _: &MoveToStartOfNextExcerpt,
11962        window: &mut Window,
11963        cx: &mut Context<Self>,
11964    ) {
11965        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11966            cx.propagate();
11967            return;
11968        }
11969
11970        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11971            s.move_with(|map, selection| {
11972                selection.collapse_to(
11973                    movement::start_of_excerpt(
11974                        map,
11975                        selection.head(),
11976                        workspace::searchable::Direction::Next,
11977                    ),
11978                    SelectionGoal::None,
11979                )
11980            });
11981        })
11982    }
11983
11984    pub fn move_to_end_of_excerpt(
11985        &mut self,
11986        _: &MoveToEndOfExcerpt,
11987        window: &mut Window,
11988        cx: &mut Context<Self>,
11989    ) {
11990        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11991            cx.propagate();
11992            return;
11993        }
11994        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11995        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11996            s.move_with(|map, selection| {
11997                selection.collapse_to(
11998                    movement::end_of_excerpt(
11999                        map,
12000                        selection.head(),
12001                        workspace::searchable::Direction::Next,
12002                    ),
12003                    SelectionGoal::None,
12004                )
12005            });
12006        })
12007    }
12008
12009    pub fn move_to_end_of_previous_excerpt(
12010        &mut self,
12011        _: &MoveToEndOfPreviousExcerpt,
12012        window: &mut Window,
12013        cx: &mut Context<Self>,
12014    ) {
12015        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12016            cx.propagate();
12017            return;
12018        }
12019        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12020        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12021            s.move_with(|map, selection| {
12022                selection.collapse_to(
12023                    movement::end_of_excerpt(
12024                        map,
12025                        selection.head(),
12026                        workspace::searchable::Direction::Prev,
12027                    ),
12028                    SelectionGoal::None,
12029                )
12030            });
12031        })
12032    }
12033
12034    pub fn select_to_start_of_excerpt(
12035        &mut self,
12036        _: &SelectToStartOfExcerpt,
12037        window: &mut Window,
12038        cx: &mut Context<Self>,
12039    ) {
12040        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12041            cx.propagate();
12042            return;
12043        }
12044        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12045        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12046            s.move_heads_with(|map, head, _| {
12047                (
12048                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12049                    SelectionGoal::None,
12050                )
12051            });
12052        })
12053    }
12054
12055    pub fn select_to_start_of_next_excerpt(
12056        &mut self,
12057        _: &SelectToStartOfNextExcerpt,
12058        window: &mut Window,
12059        cx: &mut Context<Self>,
12060    ) {
12061        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12062            cx.propagate();
12063            return;
12064        }
12065        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12066        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12067            s.move_heads_with(|map, head, _| {
12068                (
12069                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12070                    SelectionGoal::None,
12071                )
12072            });
12073        })
12074    }
12075
12076    pub fn select_to_end_of_excerpt(
12077        &mut self,
12078        _: &SelectToEndOfExcerpt,
12079        window: &mut Window,
12080        cx: &mut Context<Self>,
12081    ) {
12082        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12083            cx.propagate();
12084            return;
12085        }
12086        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12087        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12088            s.move_heads_with(|map, head, _| {
12089                (
12090                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12091                    SelectionGoal::None,
12092                )
12093            });
12094        })
12095    }
12096
12097    pub fn select_to_end_of_previous_excerpt(
12098        &mut self,
12099        _: &SelectToEndOfPreviousExcerpt,
12100        window: &mut Window,
12101        cx: &mut Context<Self>,
12102    ) {
12103        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12104            cx.propagate();
12105            return;
12106        }
12107        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12108        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12109            s.move_heads_with(|map, head, _| {
12110                (
12111                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12112                    SelectionGoal::None,
12113                )
12114            });
12115        })
12116    }
12117
12118    pub fn move_to_beginning(
12119        &mut self,
12120        _: &MoveToBeginning,
12121        window: &mut Window,
12122        cx: &mut Context<Self>,
12123    ) {
12124        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12125            cx.propagate();
12126            return;
12127        }
12128        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12129        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12130            s.select_ranges(vec![0..0]);
12131        });
12132    }
12133
12134    pub fn select_to_beginning(
12135        &mut self,
12136        _: &SelectToBeginning,
12137        window: &mut Window,
12138        cx: &mut Context<Self>,
12139    ) {
12140        let mut selection = self.selections.last::<Point>(cx);
12141        selection.set_head(Point::zero(), SelectionGoal::None);
12142        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12143        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12144            s.select(vec![selection]);
12145        });
12146    }
12147
12148    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12149        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12150            cx.propagate();
12151            return;
12152        }
12153        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12154        let cursor = self.buffer.read(cx).read(cx).len();
12155        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12156            s.select_ranges(vec![cursor..cursor])
12157        });
12158    }
12159
12160    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12161        self.nav_history = nav_history;
12162    }
12163
12164    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12165        self.nav_history.as_ref()
12166    }
12167
12168    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12169        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12170    }
12171
12172    fn push_to_nav_history(
12173        &mut self,
12174        cursor_anchor: Anchor,
12175        new_position: Option<Point>,
12176        is_deactivate: bool,
12177        cx: &mut Context<Self>,
12178    ) {
12179        if let Some(nav_history) = self.nav_history.as_mut() {
12180            let buffer = self.buffer.read(cx).read(cx);
12181            let cursor_position = cursor_anchor.to_point(&buffer);
12182            let scroll_state = self.scroll_manager.anchor();
12183            let scroll_top_row = scroll_state.top_row(&buffer);
12184            drop(buffer);
12185
12186            if let Some(new_position) = new_position {
12187                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12188                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12189                    return;
12190                }
12191            }
12192
12193            nav_history.push(
12194                Some(NavigationData {
12195                    cursor_anchor,
12196                    cursor_position,
12197                    scroll_anchor: scroll_state,
12198                    scroll_top_row,
12199                }),
12200                cx,
12201            );
12202            cx.emit(EditorEvent::PushedToNavHistory {
12203                anchor: cursor_anchor,
12204                is_deactivate,
12205            })
12206        }
12207    }
12208
12209    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12210        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12211        let buffer = self.buffer.read(cx).snapshot(cx);
12212        let mut selection = self.selections.first::<usize>(cx);
12213        selection.set_head(buffer.len(), SelectionGoal::None);
12214        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12215            s.select(vec![selection]);
12216        });
12217    }
12218
12219    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12220        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12221        let end = self.buffer.read(cx).read(cx).len();
12222        self.change_selections(None, window, cx, |s| {
12223            s.select_ranges(vec![0..end]);
12224        });
12225    }
12226
12227    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12228        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12229        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12230        let mut selections = self.selections.all::<Point>(cx);
12231        let max_point = display_map.buffer_snapshot.max_point();
12232        for selection in &mut selections {
12233            let rows = selection.spanned_rows(true, &display_map);
12234            selection.start = Point::new(rows.start.0, 0);
12235            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12236            selection.reversed = false;
12237        }
12238        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12239            s.select(selections);
12240        });
12241    }
12242
12243    pub fn split_selection_into_lines(
12244        &mut self,
12245        _: &SplitSelectionIntoLines,
12246        window: &mut Window,
12247        cx: &mut Context<Self>,
12248    ) {
12249        let selections = self
12250            .selections
12251            .all::<Point>(cx)
12252            .into_iter()
12253            .map(|selection| selection.start..selection.end)
12254            .collect::<Vec<_>>();
12255        self.unfold_ranges(&selections, true, true, cx);
12256
12257        let mut new_selection_ranges = Vec::new();
12258        {
12259            let buffer = self.buffer.read(cx).read(cx);
12260            for selection in selections {
12261                for row in selection.start.row..selection.end.row {
12262                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12263                    new_selection_ranges.push(cursor..cursor);
12264                }
12265
12266                let is_multiline_selection = selection.start.row != selection.end.row;
12267                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12268                // so this action feels more ergonomic when paired with other selection operations
12269                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12270                if !should_skip_last {
12271                    new_selection_ranges.push(selection.end..selection.end);
12272                }
12273            }
12274        }
12275        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12276            s.select_ranges(new_selection_ranges);
12277        });
12278    }
12279
12280    pub fn add_selection_above(
12281        &mut self,
12282        _: &AddSelectionAbove,
12283        window: &mut Window,
12284        cx: &mut Context<Self>,
12285    ) {
12286        self.add_selection(true, window, cx);
12287    }
12288
12289    pub fn add_selection_below(
12290        &mut self,
12291        _: &AddSelectionBelow,
12292        window: &mut Window,
12293        cx: &mut Context<Self>,
12294    ) {
12295        self.add_selection(false, window, cx);
12296    }
12297
12298    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12299        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12300
12301        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12302        let mut selections = self.selections.all::<Point>(cx);
12303        let text_layout_details = self.text_layout_details(window);
12304        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12305            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12306            let range = oldest_selection.display_range(&display_map).sorted();
12307
12308            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12309            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12310            let positions = start_x.min(end_x)..start_x.max(end_x);
12311
12312            selections.clear();
12313            let mut stack = Vec::new();
12314            for row in range.start.row().0..=range.end.row().0 {
12315                if let Some(selection) = self.selections.build_columnar_selection(
12316                    &display_map,
12317                    DisplayRow(row),
12318                    &positions,
12319                    oldest_selection.reversed,
12320                    &text_layout_details,
12321                ) {
12322                    stack.push(selection.id);
12323                    selections.push(selection);
12324                }
12325            }
12326
12327            if above {
12328                stack.reverse();
12329            }
12330
12331            AddSelectionsState { above, stack }
12332        });
12333
12334        let last_added_selection = *state.stack.last().unwrap();
12335        let mut new_selections = Vec::new();
12336        if above == state.above {
12337            let end_row = if above {
12338                DisplayRow(0)
12339            } else {
12340                display_map.max_point().row()
12341            };
12342
12343            'outer: for selection in selections {
12344                if selection.id == last_added_selection {
12345                    let range = selection.display_range(&display_map).sorted();
12346                    debug_assert_eq!(range.start.row(), range.end.row());
12347                    let mut row = range.start.row();
12348                    let positions =
12349                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12350                            px(start)..px(end)
12351                        } else {
12352                            let start_x =
12353                                display_map.x_for_display_point(range.start, &text_layout_details);
12354                            let end_x =
12355                                display_map.x_for_display_point(range.end, &text_layout_details);
12356                            start_x.min(end_x)..start_x.max(end_x)
12357                        };
12358
12359                    while row != end_row {
12360                        if above {
12361                            row.0 -= 1;
12362                        } else {
12363                            row.0 += 1;
12364                        }
12365
12366                        if let Some(new_selection) = self.selections.build_columnar_selection(
12367                            &display_map,
12368                            row,
12369                            &positions,
12370                            selection.reversed,
12371                            &text_layout_details,
12372                        ) {
12373                            state.stack.push(new_selection.id);
12374                            if above {
12375                                new_selections.push(new_selection);
12376                                new_selections.push(selection);
12377                            } else {
12378                                new_selections.push(selection);
12379                                new_selections.push(new_selection);
12380                            }
12381
12382                            continue 'outer;
12383                        }
12384                    }
12385                }
12386
12387                new_selections.push(selection);
12388            }
12389        } else {
12390            new_selections = selections;
12391            new_selections.retain(|s| s.id != last_added_selection);
12392            state.stack.pop();
12393        }
12394
12395        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12396            s.select(new_selections);
12397        });
12398        if state.stack.len() > 1 {
12399            self.add_selections_state = Some(state);
12400        }
12401    }
12402
12403    fn select_match_ranges(
12404        &mut self,
12405        range: Range<usize>,
12406        reversed: bool,
12407        replace_newest: bool,
12408        auto_scroll: Option<Autoscroll>,
12409        window: &mut Window,
12410        cx: &mut Context<Editor>,
12411    ) {
12412        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12413        self.change_selections(auto_scroll, window, cx, |s| {
12414            if replace_newest {
12415                s.delete(s.newest_anchor().id);
12416            }
12417            if reversed {
12418                s.insert_range(range.end..range.start);
12419            } else {
12420                s.insert_range(range);
12421            }
12422        });
12423    }
12424
12425    pub fn select_next_match_internal(
12426        &mut self,
12427        display_map: &DisplaySnapshot,
12428        replace_newest: bool,
12429        autoscroll: Option<Autoscroll>,
12430        window: &mut Window,
12431        cx: &mut Context<Self>,
12432    ) -> Result<()> {
12433        let buffer = &display_map.buffer_snapshot;
12434        let mut selections = self.selections.all::<usize>(cx);
12435        if let Some(mut select_next_state) = self.select_next_state.take() {
12436            let query = &select_next_state.query;
12437            if !select_next_state.done {
12438                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12439                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12440                let mut next_selected_range = None;
12441
12442                let bytes_after_last_selection =
12443                    buffer.bytes_in_range(last_selection.end..buffer.len());
12444                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12445                let query_matches = query
12446                    .stream_find_iter(bytes_after_last_selection)
12447                    .map(|result| (last_selection.end, result))
12448                    .chain(
12449                        query
12450                            .stream_find_iter(bytes_before_first_selection)
12451                            .map(|result| (0, result)),
12452                    );
12453
12454                for (start_offset, query_match) in query_matches {
12455                    let query_match = query_match.unwrap(); // can only fail due to I/O
12456                    let offset_range =
12457                        start_offset + query_match.start()..start_offset + query_match.end();
12458                    let display_range = offset_range.start.to_display_point(display_map)
12459                        ..offset_range.end.to_display_point(display_map);
12460
12461                    if !select_next_state.wordwise
12462                        || (!movement::is_inside_word(display_map, display_range.start)
12463                            && !movement::is_inside_word(display_map, display_range.end))
12464                    {
12465                        // TODO: This is n^2, because we might check all the selections
12466                        if !selections
12467                            .iter()
12468                            .any(|selection| selection.range().overlaps(&offset_range))
12469                        {
12470                            next_selected_range = Some(offset_range);
12471                            break;
12472                        }
12473                    }
12474                }
12475
12476                if let Some(next_selected_range) = next_selected_range {
12477                    self.select_match_ranges(
12478                        next_selected_range,
12479                        last_selection.reversed,
12480                        replace_newest,
12481                        autoscroll,
12482                        window,
12483                        cx,
12484                    );
12485                } else {
12486                    select_next_state.done = true;
12487                }
12488            }
12489
12490            self.select_next_state = Some(select_next_state);
12491        } else {
12492            let mut only_carets = true;
12493            let mut same_text_selected = true;
12494            let mut selected_text = None;
12495
12496            let mut selections_iter = selections.iter().peekable();
12497            while let Some(selection) = selections_iter.next() {
12498                if selection.start != selection.end {
12499                    only_carets = false;
12500                }
12501
12502                if same_text_selected {
12503                    if selected_text.is_none() {
12504                        selected_text =
12505                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12506                    }
12507
12508                    if let Some(next_selection) = selections_iter.peek() {
12509                        if next_selection.range().len() == selection.range().len() {
12510                            let next_selected_text = buffer
12511                                .text_for_range(next_selection.range())
12512                                .collect::<String>();
12513                            if Some(next_selected_text) != selected_text {
12514                                same_text_selected = false;
12515                                selected_text = None;
12516                            }
12517                        } else {
12518                            same_text_selected = false;
12519                            selected_text = None;
12520                        }
12521                    }
12522                }
12523            }
12524
12525            if only_carets {
12526                for selection in &mut selections {
12527                    let word_range = movement::surrounding_word(
12528                        display_map,
12529                        selection.start.to_display_point(display_map),
12530                    );
12531                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12532                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12533                    selection.goal = SelectionGoal::None;
12534                    selection.reversed = false;
12535                    self.select_match_ranges(
12536                        selection.start..selection.end,
12537                        selection.reversed,
12538                        replace_newest,
12539                        autoscroll,
12540                        window,
12541                        cx,
12542                    );
12543                }
12544
12545                if selections.len() == 1 {
12546                    let selection = selections
12547                        .last()
12548                        .expect("ensured that there's only one selection");
12549                    let query = buffer
12550                        .text_for_range(selection.start..selection.end)
12551                        .collect::<String>();
12552                    let is_empty = query.is_empty();
12553                    let select_state = SelectNextState {
12554                        query: AhoCorasick::new(&[query])?,
12555                        wordwise: true,
12556                        done: is_empty,
12557                    };
12558                    self.select_next_state = Some(select_state);
12559                } else {
12560                    self.select_next_state = None;
12561                }
12562            } else if let Some(selected_text) = selected_text {
12563                self.select_next_state = Some(SelectNextState {
12564                    query: AhoCorasick::new(&[selected_text])?,
12565                    wordwise: false,
12566                    done: false,
12567                });
12568                self.select_next_match_internal(
12569                    display_map,
12570                    replace_newest,
12571                    autoscroll,
12572                    window,
12573                    cx,
12574                )?;
12575            }
12576        }
12577        Ok(())
12578    }
12579
12580    pub fn select_all_matches(
12581        &mut self,
12582        _action: &SelectAllMatches,
12583        window: &mut Window,
12584        cx: &mut Context<Self>,
12585    ) -> Result<()> {
12586        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12587
12588        self.push_to_selection_history();
12589        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12590
12591        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12592        let Some(select_next_state) = self.select_next_state.as_mut() else {
12593            return Ok(());
12594        };
12595        if select_next_state.done {
12596            return Ok(());
12597        }
12598
12599        let mut new_selections = Vec::new();
12600
12601        let reversed = self.selections.oldest::<usize>(cx).reversed;
12602        let buffer = &display_map.buffer_snapshot;
12603        let query_matches = select_next_state
12604            .query
12605            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12606
12607        for query_match in query_matches.into_iter() {
12608            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12609            let offset_range = if reversed {
12610                query_match.end()..query_match.start()
12611            } else {
12612                query_match.start()..query_match.end()
12613            };
12614            let display_range = offset_range.start.to_display_point(&display_map)
12615                ..offset_range.end.to_display_point(&display_map);
12616
12617            if !select_next_state.wordwise
12618                || (!movement::is_inside_word(&display_map, display_range.start)
12619                    && !movement::is_inside_word(&display_map, display_range.end))
12620            {
12621                new_selections.push(offset_range.start..offset_range.end);
12622            }
12623        }
12624
12625        select_next_state.done = true;
12626        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12627        self.change_selections(None, window, cx, |selections| {
12628            selections.select_ranges(new_selections)
12629        });
12630
12631        Ok(())
12632    }
12633
12634    pub fn select_next(
12635        &mut self,
12636        action: &SelectNext,
12637        window: &mut Window,
12638        cx: &mut Context<Self>,
12639    ) -> Result<()> {
12640        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12641        self.push_to_selection_history();
12642        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12643        self.select_next_match_internal(
12644            &display_map,
12645            action.replace_newest,
12646            Some(Autoscroll::newest()),
12647            window,
12648            cx,
12649        )?;
12650        Ok(())
12651    }
12652
12653    pub fn select_previous(
12654        &mut self,
12655        action: &SelectPrevious,
12656        window: &mut Window,
12657        cx: &mut Context<Self>,
12658    ) -> Result<()> {
12659        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12660        self.push_to_selection_history();
12661        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12662        let buffer = &display_map.buffer_snapshot;
12663        let mut selections = self.selections.all::<usize>(cx);
12664        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12665            let query = &select_prev_state.query;
12666            if !select_prev_state.done {
12667                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12668                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12669                let mut next_selected_range = None;
12670                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12671                let bytes_before_last_selection =
12672                    buffer.reversed_bytes_in_range(0..last_selection.start);
12673                let bytes_after_first_selection =
12674                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12675                let query_matches = query
12676                    .stream_find_iter(bytes_before_last_selection)
12677                    .map(|result| (last_selection.start, result))
12678                    .chain(
12679                        query
12680                            .stream_find_iter(bytes_after_first_selection)
12681                            .map(|result| (buffer.len(), result)),
12682                    );
12683                for (end_offset, query_match) in query_matches {
12684                    let query_match = query_match.unwrap(); // can only fail due to I/O
12685                    let offset_range =
12686                        end_offset - query_match.end()..end_offset - query_match.start();
12687                    let display_range = offset_range.start.to_display_point(&display_map)
12688                        ..offset_range.end.to_display_point(&display_map);
12689
12690                    if !select_prev_state.wordwise
12691                        || (!movement::is_inside_word(&display_map, display_range.start)
12692                            && !movement::is_inside_word(&display_map, display_range.end))
12693                    {
12694                        next_selected_range = Some(offset_range);
12695                        break;
12696                    }
12697                }
12698
12699                if let Some(next_selected_range) = next_selected_range {
12700                    self.select_match_ranges(
12701                        next_selected_range,
12702                        last_selection.reversed,
12703                        action.replace_newest,
12704                        Some(Autoscroll::newest()),
12705                        window,
12706                        cx,
12707                    );
12708                } else {
12709                    select_prev_state.done = true;
12710                }
12711            }
12712
12713            self.select_prev_state = Some(select_prev_state);
12714        } else {
12715            let mut only_carets = true;
12716            let mut same_text_selected = true;
12717            let mut selected_text = None;
12718
12719            let mut selections_iter = selections.iter().peekable();
12720            while let Some(selection) = selections_iter.next() {
12721                if selection.start != selection.end {
12722                    only_carets = false;
12723                }
12724
12725                if same_text_selected {
12726                    if selected_text.is_none() {
12727                        selected_text =
12728                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12729                    }
12730
12731                    if let Some(next_selection) = selections_iter.peek() {
12732                        if next_selection.range().len() == selection.range().len() {
12733                            let next_selected_text = buffer
12734                                .text_for_range(next_selection.range())
12735                                .collect::<String>();
12736                            if Some(next_selected_text) != selected_text {
12737                                same_text_selected = false;
12738                                selected_text = None;
12739                            }
12740                        } else {
12741                            same_text_selected = false;
12742                            selected_text = None;
12743                        }
12744                    }
12745                }
12746            }
12747
12748            if only_carets {
12749                for selection in &mut selections {
12750                    let word_range = movement::surrounding_word(
12751                        &display_map,
12752                        selection.start.to_display_point(&display_map),
12753                    );
12754                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12755                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12756                    selection.goal = SelectionGoal::None;
12757                    selection.reversed = false;
12758                    self.select_match_ranges(
12759                        selection.start..selection.end,
12760                        selection.reversed,
12761                        action.replace_newest,
12762                        Some(Autoscroll::newest()),
12763                        window,
12764                        cx,
12765                    );
12766                }
12767                if selections.len() == 1 {
12768                    let selection = selections
12769                        .last()
12770                        .expect("ensured that there's only one selection");
12771                    let query = buffer
12772                        .text_for_range(selection.start..selection.end)
12773                        .collect::<String>();
12774                    let is_empty = query.is_empty();
12775                    let select_state = SelectNextState {
12776                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12777                        wordwise: true,
12778                        done: is_empty,
12779                    };
12780                    self.select_prev_state = Some(select_state);
12781                } else {
12782                    self.select_prev_state = None;
12783                }
12784            } else if let Some(selected_text) = selected_text {
12785                self.select_prev_state = Some(SelectNextState {
12786                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12787                    wordwise: false,
12788                    done: false,
12789                });
12790                self.select_previous(action, window, cx)?;
12791            }
12792        }
12793        Ok(())
12794    }
12795
12796    pub fn find_next_match(
12797        &mut self,
12798        _: &FindNextMatch,
12799        window: &mut Window,
12800        cx: &mut Context<Self>,
12801    ) -> Result<()> {
12802        let selections = self.selections.disjoint_anchors();
12803        match selections.first() {
12804            Some(first) if selections.len() >= 2 => {
12805                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12806                    s.select_ranges([first.range()]);
12807                });
12808            }
12809            _ => self.select_next(
12810                &SelectNext {
12811                    replace_newest: true,
12812                },
12813                window,
12814                cx,
12815            )?,
12816        }
12817        Ok(())
12818    }
12819
12820    pub fn find_previous_match(
12821        &mut self,
12822        _: &FindPreviousMatch,
12823        window: &mut Window,
12824        cx: &mut Context<Self>,
12825    ) -> Result<()> {
12826        let selections = self.selections.disjoint_anchors();
12827        match selections.last() {
12828            Some(last) if selections.len() >= 2 => {
12829                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12830                    s.select_ranges([last.range()]);
12831                });
12832            }
12833            _ => self.select_previous(
12834                &SelectPrevious {
12835                    replace_newest: true,
12836                },
12837                window,
12838                cx,
12839            )?,
12840        }
12841        Ok(())
12842    }
12843
12844    pub fn toggle_comments(
12845        &mut self,
12846        action: &ToggleComments,
12847        window: &mut Window,
12848        cx: &mut Context<Self>,
12849    ) {
12850        if self.read_only(cx) {
12851            return;
12852        }
12853        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12854        let text_layout_details = &self.text_layout_details(window);
12855        self.transact(window, cx, |this, window, cx| {
12856            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12857            let mut edits = Vec::new();
12858            let mut selection_edit_ranges = Vec::new();
12859            let mut last_toggled_row = None;
12860            let snapshot = this.buffer.read(cx).read(cx);
12861            let empty_str: Arc<str> = Arc::default();
12862            let mut suffixes_inserted = Vec::new();
12863            let ignore_indent = action.ignore_indent;
12864
12865            fn comment_prefix_range(
12866                snapshot: &MultiBufferSnapshot,
12867                row: MultiBufferRow,
12868                comment_prefix: &str,
12869                comment_prefix_whitespace: &str,
12870                ignore_indent: bool,
12871            ) -> Range<Point> {
12872                let indent_size = if ignore_indent {
12873                    0
12874                } else {
12875                    snapshot.indent_size_for_line(row).len
12876                };
12877
12878                let start = Point::new(row.0, indent_size);
12879
12880                let mut line_bytes = snapshot
12881                    .bytes_in_range(start..snapshot.max_point())
12882                    .flatten()
12883                    .copied();
12884
12885                // If this line currently begins with the line comment prefix, then record
12886                // the range containing the prefix.
12887                if line_bytes
12888                    .by_ref()
12889                    .take(comment_prefix.len())
12890                    .eq(comment_prefix.bytes())
12891                {
12892                    // Include any whitespace that matches the comment prefix.
12893                    let matching_whitespace_len = line_bytes
12894                        .zip(comment_prefix_whitespace.bytes())
12895                        .take_while(|(a, b)| a == b)
12896                        .count() as u32;
12897                    let end = Point::new(
12898                        start.row,
12899                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12900                    );
12901                    start..end
12902                } else {
12903                    start..start
12904                }
12905            }
12906
12907            fn comment_suffix_range(
12908                snapshot: &MultiBufferSnapshot,
12909                row: MultiBufferRow,
12910                comment_suffix: &str,
12911                comment_suffix_has_leading_space: bool,
12912            ) -> Range<Point> {
12913                let end = Point::new(row.0, snapshot.line_len(row));
12914                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12915
12916                let mut line_end_bytes = snapshot
12917                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12918                    .flatten()
12919                    .copied();
12920
12921                let leading_space_len = if suffix_start_column > 0
12922                    && line_end_bytes.next() == Some(b' ')
12923                    && comment_suffix_has_leading_space
12924                {
12925                    1
12926                } else {
12927                    0
12928                };
12929
12930                // If this line currently begins with the line comment prefix, then record
12931                // the range containing the prefix.
12932                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12933                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12934                    start..end
12935                } else {
12936                    end..end
12937                }
12938            }
12939
12940            // TODO: Handle selections that cross excerpts
12941            for selection in &mut selections {
12942                let start_column = snapshot
12943                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12944                    .len;
12945                let language = if let Some(language) =
12946                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12947                {
12948                    language
12949                } else {
12950                    continue;
12951                };
12952
12953                selection_edit_ranges.clear();
12954
12955                // If multiple selections contain a given row, avoid processing that
12956                // row more than once.
12957                let mut start_row = MultiBufferRow(selection.start.row);
12958                if last_toggled_row == Some(start_row) {
12959                    start_row = start_row.next_row();
12960                }
12961                let end_row =
12962                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12963                        MultiBufferRow(selection.end.row - 1)
12964                    } else {
12965                        MultiBufferRow(selection.end.row)
12966                    };
12967                last_toggled_row = Some(end_row);
12968
12969                if start_row > end_row {
12970                    continue;
12971                }
12972
12973                // If the language has line comments, toggle those.
12974                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12975
12976                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12977                if ignore_indent {
12978                    full_comment_prefixes = full_comment_prefixes
12979                        .into_iter()
12980                        .map(|s| Arc::from(s.trim_end()))
12981                        .collect();
12982                }
12983
12984                if !full_comment_prefixes.is_empty() {
12985                    let first_prefix = full_comment_prefixes
12986                        .first()
12987                        .expect("prefixes is non-empty");
12988                    let prefix_trimmed_lengths = full_comment_prefixes
12989                        .iter()
12990                        .map(|p| p.trim_end_matches(' ').len())
12991                        .collect::<SmallVec<[usize; 4]>>();
12992
12993                    let mut all_selection_lines_are_comments = true;
12994
12995                    for row in start_row.0..=end_row.0 {
12996                        let row = MultiBufferRow(row);
12997                        if start_row < end_row && snapshot.is_line_blank(row) {
12998                            continue;
12999                        }
13000
13001                        let prefix_range = full_comment_prefixes
13002                            .iter()
13003                            .zip(prefix_trimmed_lengths.iter().copied())
13004                            .map(|(prefix, trimmed_prefix_len)| {
13005                                comment_prefix_range(
13006                                    snapshot.deref(),
13007                                    row,
13008                                    &prefix[..trimmed_prefix_len],
13009                                    &prefix[trimmed_prefix_len..],
13010                                    ignore_indent,
13011                                )
13012                            })
13013                            .max_by_key(|range| range.end.column - range.start.column)
13014                            .expect("prefixes is non-empty");
13015
13016                        if prefix_range.is_empty() {
13017                            all_selection_lines_are_comments = false;
13018                        }
13019
13020                        selection_edit_ranges.push(prefix_range);
13021                    }
13022
13023                    if all_selection_lines_are_comments {
13024                        edits.extend(
13025                            selection_edit_ranges
13026                                .iter()
13027                                .cloned()
13028                                .map(|range| (range, empty_str.clone())),
13029                        );
13030                    } else {
13031                        let min_column = selection_edit_ranges
13032                            .iter()
13033                            .map(|range| range.start.column)
13034                            .min()
13035                            .unwrap_or(0);
13036                        edits.extend(selection_edit_ranges.iter().map(|range| {
13037                            let position = Point::new(range.start.row, min_column);
13038                            (position..position, first_prefix.clone())
13039                        }));
13040                    }
13041                } else if let Some((full_comment_prefix, comment_suffix)) =
13042                    language.block_comment_delimiters()
13043                {
13044                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13045                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13046                    let prefix_range = comment_prefix_range(
13047                        snapshot.deref(),
13048                        start_row,
13049                        comment_prefix,
13050                        comment_prefix_whitespace,
13051                        ignore_indent,
13052                    );
13053                    let suffix_range = comment_suffix_range(
13054                        snapshot.deref(),
13055                        end_row,
13056                        comment_suffix.trim_start_matches(' '),
13057                        comment_suffix.starts_with(' '),
13058                    );
13059
13060                    if prefix_range.is_empty() || suffix_range.is_empty() {
13061                        edits.push((
13062                            prefix_range.start..prefix_range.start,
13063                            full_comment_prefix.clone(),
13064                        ));
13065                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13066                        suffixes_inserted.push((end_row, comment_suffix.len()));
13067                    } else {
13068                        edits.push((prefix_range, empty_str.clone()));
13069                        edits.push((suffix_range, empty_str.clone()));
13070                    }
13071                } else {
13072                    continue;
13073                }
13074            }
13075
13076            drop(snapshot);
13077            this.buffer.update(cx, |buffer, cx| {
13078                buffer.edit(edits, None, cx);
13079            });
13080
13081            // Adjust selections so that they end before any comment suffixes that
13082            // were inserted.
13083            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13084            let mut selections = this.selections.all::<Point>(cx);
13085            let snapshot = this.buffer.read(cx).read(cx);
13086            for selection in &mut selections {
13087                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13088                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13089                        Ordering::Less => {
13090                            suffixes_inserted.next();
13091                            continue;
13092                        }
13093                        Ordering::Greater => break,
13094                        Ordering::Equal => {
13095                            if selection.end.column == snapshot.line_len(row) {
13096                                if selection.is_empty() {
13097                                    selection.start.column -= suffix_len as u32;
13098                                }
13099                                selection.end.column -= suffix_len as u32;
13100                            }
13101                            break;
13102                        }
13103                    }
13104                }
13105            }
13106
13107            drop(snapshot);
13108            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13109                s.select(selections)
13110            });
13111
13112            let selections = this.selections.all::<Point>(cx);
13113            let selections_on_single_row = selections.windows(2).all(|selections| {
13114                selections[0].start.row == selections[1].start.row
13115                    && selections[0].end.row == selections[1].end.row
13116                    && selections[0].start.row == selections[0].end.row
13117            });
13118            let selections_selecting = selections
13119                .iter()
13120                .any(|selection| selection.start != selection.end);
13121            let advance_downwards = action.advance_downwards
13122                && selections_on_single_row
13123                && !selections_selecting
13124                && !matches!(this.mode, EditorMode::SingleLine { .. });
13125
13126            if advance_downwards {
13127                let snapshot = this.buffer.read(cx).snapshot(cx);
13128
13129                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13130                    s.move_cursors_with(|display_snapshot, display_point, _| {
13131                        let mut point = display_point.to_point(display_snapshot);
13132                        point.row += 1;
13133                        point = snapshot.clip_point(point, Bias::Left);
13134                        let display_point = point.to_display_point(display_snapshot);
13135                        let goal = SelectionGoal::HorizontalPosition(
13136                            display_snapshot
13137                                .x_for_display_point(display_point, text_layout_details)
13138                                .into(),
13139                        );
13140                        (display_point, goal)
13141                    })
13142                });
13143            }
13144        });
13145    }
13146
13147    pub fn select_enclosing_symbol(
13148        &mut self,
13149        _: &SelectEnclosingSymbol,
13150        window: &mut Window,
13151        cx: &mut Context<Self>,
13152    ) {
13153        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13154
13155        let buffer = self.buffer.read(cx).snapshot(cx);
13156        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13157
13158        fn update_selection(
13159            selection: &Selection<usize>,
13160            buffer_snap: &MultiBufferSnapshot,
13161        ) -> Option<Selection<usize>> {
13162            let cursor = selection.head();
13163            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13164            for symbol in symbols.iter().rev() {
13165                let start = symbol.range.start.to_offset(buffer_snap);
13166                let end = symbol.range.end.to_offset(buffer_snap);
13167                let new_range = start..end;
13168                if start < selection.start || end > selection.end {
13169                    return Some(Selection {
13170                        id: selection.id,
13171                        start: new_range.start,
13172                        end: new_range.end,
13173                        goal: SelectionGoal::None,
13174                        reversed: selection.reversed,
13175                    });
13176                }
13177            }
13178            None
13179        }
13180
13181        let mut selected_larger_symbol = false;
13182        let new_selections = old_selections
13183            .iter()
13184            .map(|selection| match update_selection(selection, &buffer) {
13185                Some(new_selection) => {
13186                    if new_selection.range() != selection.range() {
13187                        selected_larger_symbol = true;
13188                    }
13189                    new_selection
13190                }
13191                None => selection.clone(),
13192            })
13193            .collect::<Vec<_>>();
13194
13195        if selected_larger_symbol {
13196            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13197                s.select(new_selections);
13198            });
13199        }
13200    }
13201
13202    pub fn select_larger_syntax_node(
13203        &mut self,
13204        _: &SelectLargerSyntaxNode,
13205        window: &mut Window,
13206        cx: &mut Context<Self>,
13207    ) {
13208        let Some(visible_row_count) = self.visible_row_count() else {
13209            return;
13210        };
13211        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13212        if old_selections.is_empty() {
13213            return;
13214        }
13215
13216        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13217
13218        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13219        let buffer = self.buffer.read(cx).snapshot(cx);
13220
13221        let mut selected_larger_node = false;
13222        let mut new_selections = old_selections
13223            .iter()
13224            .map(|selection| {
13225                let old_range = selection.start..selection.end;
13226
13227                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13228                    // manually select word at selection
13229                    if ["string_content", "inline"].contains(&node.kind()) {
13230                        let word_range = {
13231                            let display_point = buffer
13232                                .offset_to_point(old_range.start)
13233                                .to_display_point(&display_map);
13234                            let Range { start, end } =
13235                                movement::surrounding_word(&display_map, display_point);
13236                            start.to_point(&display_map).to_offset(&buffer)
13237                                ..end.to_point(&display_map).to_offset(&buffer)
13238                        };
13239                        // ignore if word is already selected
13240                        if !word_range.is_empty() && old_range != word_range {
13241                            let last_word_range = {
13242                                let display_point = buffer
13243                                    .offset_to_point(old_range.end)
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                            // only select word if start and end point belongs to same word
13251                            if word_range == last_word_range {
13252                                selected_larger_node = true;
13253                                return Selection {
13254                                    id: selection.id,
13255                                    start: word_range.start,
13256                                    end: word_range.end,
13257                                    goal: SelectionGoal::None,
13258                                    reversed: selection.reversed,
13259                                };
13260                            }
13261                        }
13262                    }
13263                }
13264
13265                let mut new_range = old_range.clone();
13266                while let Some((_node, containing_range)) =
13267                    buffer.syntax_ancestor(new_range.clone())
13268                {
13269                    new_range = match containing_range {
13270                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13271                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13272                    };
13273                    if !display_map.intersects_fold(new_range.start)
13274                        && !display_map.intersects_fold(new_range.end)
13275                    {
13276                        break;
13277                    }
13278                }
13279
13280                selected_larger_node |= new_range != old_range;
13281                Selection {
13282                    id: selection.id,
13283                    start: new_range.start,
13284                    end: new_range.end,
13285                    goal: SelectionGoal::None,
13286                    reversed: selection.reversed,
13287                }
13288            })
13289            .collect::<Vec<_>>();
13290
13291        if !selected_larger_node {
13292            return; // don't put this call in the history
13293        }
13294
13295        // scroll based on transformation done to the last selection created by the user
13296        let (last_old, last_new) = old_selections
13297            .last()
13298            .zip(new_selections.last().cloned())
13299            .expect("old_selections isn't empty");
13300
13301        // revert selection
13302        let is_selection_reversed = {
13303            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13304            new_selections.last_mut().expect("checked above").reversed =
13305                should_newest_selection_be_reversed;
13306            should_newest_selection_be_reversed
13307        };
13308
13309        if selected_larger_node {
13310            self.select_syntax_node_history.disable_clearing = true;
13311            self.change_selections(None, window, cx, |s| {
13312                s.select(new_selections.clone());
13313            });
13314            self.select_syntax_node_history.disable_clearing = false;
13315        }
13316
13317        let start_row = last_new.start.to_display_point(&display_map).row().0;
13318        let end_row = last_new.end.to_display_point(&display_map).row().0;
13319        let selection_height = end_row - start_row + 1;
13320        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13321
13322        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13323        let scroll_behavior = if fits_on_the_screen {
13324            self.request_autoscroll(Autoscroll::fit(), cx);
13325            SelectSyntaxNodeScrollBehavior::FitSelection
13326        } else if is_selection_reversed {
13327            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13328            SelectSyntaxNodeScrollBehavior::CursorTop
13329        } else {
13330            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13331            SelectSyntaxNodeScrollBehavior::CursorBottom
13332        };
13333
13334        self.select_syntax_node_history.push((
13335            old_selections,
13336            scroll_behavior,
13337            is_selection_reversed,
13338        ));
13339    }
13340
13341    pub fn select_smaller_syntax_node(
13342        &mut self,
13343        _: &SelectSmallerSyntaxNode,
13344        window: &mut Window,
13345        cx: &mut Context<Self>,
13346    ) {
13347        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13348
13349        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13350            self.select_syntax_node_history.pop()
13351        {
13352            if let Some(selection) = selections.last_mut() {
13353                selection.reversed = is_selection_reversed;
13354            }
13355
13356            self.select_syntax_node_history.disable_clearing = true;
13357            self.change_selections(None, window, cx, |s| {
13358                s.select(selections.to_vec());
13359            });
13360            self.select_syntax_node_history.disable_clearing = false;
13361
13362            match scroll_behavior {
13363                SelectSyntaxNodeScrollBehavior::CursorTop => {
13364                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13365                }
13366                SelectSyntaxNodeScrollBehavior::FitSelection => {
13367                    self.request_autoscroll(Autoscroll::fit(), cx);
13368                }
13369                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13370                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13371                }
13372            }
13373        }
13374    }
13375
13376    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13377        if !EditorSettings::get_global(cx).gutter.runnables {
13378            self.clear_tasks();
13379            return Task::ready(());
13380        }
13381        let project = self.project.as_ref().map(Entity::downgrade);
13382        let task_sources = self.lsp_task_sources(cx);
13383        cx.spawn_in(window, async move |editor, cx| {
13384            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13385            let Some(project) = project.and_then(|p| p.upgrade()) else {
13386                return;
13387            };
13388            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13389                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13390            }) else {
13391                return;
13392            };
13393
13394            let hide_runnables = project
13395                .update(cx, |project, cx| {
13396                    // Do not display any test indicators in non-dev server remote projects.
13397                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13398                })
13399                .unwrap_or(true);
13400            if hide_runnables {
13401                return;
13402            }
13403            let new_rows =
13404                cx.background_spawn({
13405                    let snapshot = display_snapshot.clone();
13406                    async move {
13407                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13408                    }
13409                })
13410                    .await;
13411            let Ok(lsp_tasks) =
13412                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13413            else {
13414                return;
13415            };
13416            let lsp_tasks = lsp_tasks.await;
13417
13418            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13419                lsp_tasks
13420                    .into_iter()
13421                    .flat_map(|(kind, tasks)| {
13422                        tasks.into_iter().filter_map(move |(location, task)| {
13423                            Some((kind.clone(), location?, task))
13424                        })
13425                    })
13426                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13427                        let buffer = location.target.buffer;
13428                        let buffer_snapshot = buffer.read(cx).snapshot();
13429                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13430                            |(excerpt_id, snapshot, _)| {
13431                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13432                                    display_snapshot
13433                                        .buffer_snapshot
13434                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13435                                } else {
13436                                    None
13437                                }
13438                            },
13439                        );
13440                        if let Some(offset) = offset {
13441                            let task_buffer_range =
13442                                location.target.range.to_point(&buffer_snapshot);
13443                            let context_buffer_range =
13444                                task_buffer_range.to_offset(&buffer_snapshot);
13445                            let context_range = BufferOffset(context_buffer_range.start)
13446                                ..BufferOffset(context_buffer_range.end);
13447
13448                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13449                                .or_insert_with(|| RunnableTasks {
13450                                    templates: Vec::new(),
13451                                    offset,
13452                                    column: task_buffer_range.start.column,
13453                                    extra_variables: HashMap::default(),
13454                                    context_range,
13455                                })
13456                                .templates
13457                                .push((kind, task.original_task().clone()));
13458                        }
13459
13460                        acc
13461                    })
13462            }) else {
13463                return;
13464            };
13465
13466            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13467            editor
13468                .update(cx, |editor, _| {
13469                    editor.clear_tasks();
13470                    for (key, mut value) in rows {
13471                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13472                            value.templates.extend(lsp_tasks.templates);
13473                        }
13474
13475                        editor.insert_tasks(key, value);
13476                    }
13477                    for (key, value) in lsp_tasks_by_rows {
13478                        editor.insert_tasks(key, value);
13479                    }
13480                })
13481                .ok();
13482        })
13483    }
13484    fn fetch_runnable_ranges(
13485        snapshot: &DisplaySnapshot,
13486        range: Range<Anchor>,
13487    ) -> Vec<language::RunnableRange> {
13488        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13489    }
13490
13491    fn runnable_rows(
13492        project: Entity<Project>,
13493        snapshot: DisplaySnapshot,
13494        runnable_ranges: Vec<RunnableRange>,
13495        mut cx: AsyncWindowContext,
13496    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13497        runnable_ranges
13498            .into_iter()
13499            .filter_map(|mut runnable| {
13500                let tasks = cx
13501                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13502                    .ok()?;
13503                if tasks.is_empty() {
13504                    return None;
13505                }
13506
13507                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13508
13509                let row = snapshot
13510                    .buffer_snapshot
13511                    .buffer_line_for_row(MultiBufferRow(point.row))?
13512                    .1
13513                    .start
13514                    .row;
13515
13516                let context_range =
13517                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13518                Some((
13519                    (runnable.buffer_id, row),
13520                    RunnableTasks {
13521                        templates: tasks,
13522                        offset: snapshot
13523                            .buffer_snapshot
13524                            .anchor_before(runnable.run_range.start),
13525                        context_range,
13526                        column: point.column,
13527                        extra_variables: runnable.extra_captures,
13528                    },
13529                ))
13530            })
13531            .collect()
13532    }
13533
13534    fn templates_with_tags(
13535        project: &Entity<Project>,
13536        runnable: &mut Runnable,
13537        cx: &mut App,
13538    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13539        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13540            let (worktree_id, file) = project
13541                .buffer_for_id(runnable.buffer, cx)
13542                .and_then(|buffer| buffer.read(cx).file())
13543                .map(|file| (file.worktree_id(cx), file.clone()))
13544                .unzip();
13545
13546            (
13547                project.task_store().read(cx).task_inventory().cloned(),
13548                worktree_id,
13549                file,
13550            )
13551        });
13552
13553        let mut templates_with_tags = mem::take(&mut runnable.tags)
13554            .into_iter()
13555            .flat_map(|RunnableTag(tag)| {
13556                inventory
13557                    .as_ref()
13558                    .into_iter()
13559                    .flat_map(|inventory| {
13560                        inventory.read(cx).list_tasks(
13561                            file.clone(),
13562                            Some(runnable.language.clone()),
13563                            worktree_id,
13564                            cx,
13565                        )
13566                    })
13567                    .filter(move |(_, template)| {
13568                        template.tags.iter().any(|source_tag| source_tag == &tag)
13569                    })
13570            })
13571            .sorted_by_key(|(kind, _)| kind.to_owned())
13572            .collect::<Vec<_>>();
13573        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13574            // Strongest source wins; if we have worktree tag binding, prefer that to
13575            // global and language bindings;
13576            // if we have a global binding, prefer that to language binding.
13577            let first_mismatch = templates_with_tags
13578                .iter()
13579                .position(|(tag_source, _)| tag_source != leading_tag_source);
13580            if let Some(index) = first_mismatch {
13581                templates_with_tags.truncate(index);
13582            }
13583        }
13584
13585        templates_with_tags
13586    }
13587
13588    pub fn move_to_enclosing_bracket(
13589        &mut self,
13590        _: &MoveToEnclosingBracket,
13591        window: &mut Window,
13592        cx: &mut Context<Self>,
13593    ) {
13594        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13595        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13596            s.move_offsets_with(|snapshot, selection| {
13597                let Some(enclosing_bracket_ranges) =
13598                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13599                else {
13600                    return;
13601                };
13602
13603                let mut best_length = usize::MAX;
13604                let mut best_inside = false;
13605                let mut best_in_bracket_range = false;
13606                let mut best_destination = None;
13607                for (open, close) in enclosing_bracket_ranges {
13608                    let close = close.to_inclusive();
13609                    let length = close.end() - open.start;
13610                    let inside = selection.start >= open.end && selection.end <= *close.start();
13611                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13612                        || close.contains(&selection.head());
13613
13614                    // If best is next to a bracket and current isn't, skip
13615                    if !in_bracket_range && best_in_bracket_range {
13616                        continue;
13617                    }
13618
13619                    // Prefer smaller lengths unless best is inside and current isn't
13620                    if length > best_length && (best_inside || !inside) {
13621                        continue;
13622                    }
13623
13624                    best_length = length;
13625                    best_inside = inside;
13626                    best_in_bracket_range = in_bracket_range;
13627                    best_destination = Some(
13628                        if close.contains(&selection.start) && close.contains(&selection.end) {
13629                            if inside { open.end } else { open.start }
13630                        } else if inside {
13631                            *close.start()
13632                        } else {
13633                            *close.end()
13634                        },
13635                    );
13636                }
13637
13638                if let Some(destination) = best_destination {
13639                    selection.collapse_to(destination, SelectionGoal::None);
13640                }
13641            })
13642        });
13643    }
13644
13645    pub fn undo_selection(
13646        &mut self,
13647        _: &UndoSelection,
13648        window: &mut Window,
13649        cx: &mut Context<Self>,
13650    ) {
13651        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13652        self.end_selection(window, cx);
13653        self.selection_history.mode = SelectionHistoryMode::Undoing;
13654        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13655            self.change_selections(None, window, cx, |s| {
13656                s.select_anchors(entry.selections.to_vec())
13657            });
13658            self.select_next_state = entry.select_next_state;
13659            self.select_prev_state = entry.select_prev_state;
13660            self.add_selections_state = entry.add_selections_state;
13661            self.request_autoscroll(Autoscroll::newest(), cx);
13662        }
13663        self.selection_history.mode = SelectionHistoryMode::Normal;
13664    }
13665
13666    pub fn redo_selection(
13667        &mut self,
13668        _: &RedoSelection,
13669        window: &mut Window,
13670        cx: &mut Context<Self>,
13671    ) {
13672        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13673        self.end_selection(window, cx);
13674        self.selection_history.mode = SelectionHistoryMode::Redoing;
13675        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13676            self.change_selections(None, window, cx, |s| {
13677                s.select_anchors(entry.selections.to_vec())
13678            });
13679            self.select_next_state = entry.select_next_state;
13680            self.select_prev_state = entry.select_prev_state;
13681            self.add_selections_state = entry.add_selections_state;
13682            self.request_autoscroll(Autoscroll::newest(), cx);
13683        }
13684        self.selection_history.mode = SelectionHistoryMode::Normal;
13685    }
13686
13687    pub fn expand_excerpts(
13688        &mut self,
13689        action: &ExpandExcerpts,
13690        _: &mut Window,
13691        cx: &mut Context<Self>,
13692    ) {
13693        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13694    }
13695
13696    pub fn expand_excerpts_down(
13697        &mut self,
13698        action: &ExpandExcerptsDown,
13699        _: &mut Window,
13700        cx: &mut Context<Self>,
13701    ) {
13702        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13703    }
13704
13705    pub fn expand_excerpts_up(
13706        &mut self,
13707        action: &ExpandExcerptsUp,
13708        _: &mut Window,
13709        cx: &mut Context<Self>,
13710    ) {
13711        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13712    }
13713
13714    pub fn expand_excerpts_for_direction(
13715        &mut self,
13716        lines: u32,
13717        direction: ExpandExcerptDirection,
13718
13719        cx: &mut Context<Self>,
13720    ) {
13721        let selections = self.selections.disjoint_anchors();
13722
13723        let lines = if lines == 0 {
13724            EditorSettings::get_global(cx).expand_excerpt_lines
13725        } else {
13726            lines
13727        };
13728
13729        self.buffer.update(cx, |buffer, cx| {
13730            let snapshot = buffer.snapshot(cx);
13731            let mut excerpt_ids = selections
13732                .iter()
13733                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13734                .collect::<Vec<_>>();
13735            excerpt_ids.sort();
13736            excerpt_ids.dedup();
13737            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13738        })
13739    }
13740
13741    pub fn expand_excerpt(
13742        &mut self,
13743        excerpt: ExcerptId,
13744        direction: ExpandExcerptDirection,
13745        window: &mut Window,
13746        cx: &mut Context<Self>,
13747    ) {
13748        let current_scroll_position = self.scroll_position(cx);
13749        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13750        let mut should_scroll_up = false;
13751
13752        if direction == ExpandExcerptDirection::Down {
13753            let multi_buffer = self.buffer.read(cx);
13754            let snapshot = multi_buffer.snapshot(cx);
13755            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13756                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13757                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13758                        let buffer_snapshot = buffer.read(cx).snapshot();
13759                        let excerpt_end_row =
13760                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13761                        let last_row = buffer_snapshot.max_point().row;
13762                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13763                        should_scroll_up = lines_below >= lines_to_expand;
13764                    }
13765                }
13766            }
13767        }
13768
13769        self.buffer.update(cx, |buffer, cx| {
13770            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13771        });
13772
13773        if should_scroll_up {
13774            let new_scroll_position =
13775                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13776            self.set_scroll_position(new_scroll_position, window, cx);
13777        }
13778    }
13779
13780    pub fn go_to_singleton_buffer_point(
13781        &mut self,
13782        point: Point,
13783        window: &mut Window,
13784        cx: &mut Context<Self>,
13785    ) {
13786        self.go_to_singleton_buffer_range(point..point, window, cx);
13787    }
13788
13789    pub fn go_to_singleton_buffer_range(
13790        &mut self,
13791        range: Range<Point>,
13792        window: &mut Window,
13793        cx: &mut Context<Self>,
13794    ) {
13795        let multibuffer = self.buffer().read(cx);
13796        let Some(buffer) = multibuffer.as_singleton() else {
13797            return;
13798        };
13799        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13800            return;
13801        };
13802        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13803            return;
13804        };
13805        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13806            s.select_anchor_ranges([start..end])
13807        });
13808    }
13809
13810    pub fn go_to_diagnostic(
13811        &mut self,
13812        _: &GoToDiagnostic,
13813        window: &mut Window,
13814        cx: &mut Context<Self>,
13815    ) {
13816        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13817        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13818    }
13819
13820    pub fn go_to_prev_diagnostic(
13821        &mut self,
13822        _: &GoToPreviousDiagnostic,
13823        window: &mut Window,
13824        cx: &mut Context<Self>,
13825    ) {
13826        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13827        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13828    }
13829
13830    pub fn go_to_diagnostic_impl(
13831        &mut self,
13832        direction: Direction,
13833        window: &mut Window,
13834        cx: &mut Context<Self>,
13835    ) {
13836        let buffer = self.buffer.read(cx).snapshot(cx);
13837        let selection = self.selections.newest::<usize>(cx);
13838
13839        let mut active_group_id = None;
13840        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13841            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13842                active_group_id = Some(active_group.group_id);
13843            }
13844        }
13845
13846        fn filtered(
13847            snapshot: EditorSnapshot,
13848            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13849        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13850            diagnostics
13851                .filter(|entry| entry.range.start != entry.range.end)
13852                .filter(|entry| !entry.diagnostic.is_unnecessary)
13853                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13854        }
13855
13856        let snapshot = self.snapshot(window, cx);
13857        let before = filtered(
13858            snapshot.clone(),
13859            buffer
13860                .diagnostics_in_range(0..selection.start)
13861                .filter(|entry| entry.range.start <= selection.start),
13862        );
13863        let after = filtered(
13864            snapshot,
13865            buffer
13866                .diagnostics_in_range(selection.start..buffer.len())
13867                .filter(|entry| entry.range.start >= selection.start),
13868        );
13869
13870        let mut found: Option<DiagnosticEntry<usize>> = None;
13871        if direction == Direction::Prev {
13872            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13873            {
13874                for diagnostic in prev_diagnostics.into_iter().rev() {
13875                    if diagnostic.range.start != selection.start
13876                        || active_group_id
13877                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13878                    {
13879                        found = Some(diagnostic);
13880                        break 'outer;
13881                    }
13882                }
13883            }
13884        } else {
13885            for diagnostic in after.chain(before) {
13886                if diagnostic.range.start != selection.start
13887                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13888                {
13889                    found = Some(diagnostic);
13890                    break;
13891                }
13892            }
13893        }
13894        let Some(next_diagnostic) = found else {
13895            return;
13896        };
13897
13898        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13899            return;
13900        };
13901        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13902            s.select_ranges(vec![
13903                next_diagnostic.range.start..next_diagnostic.range.start,
13904            ])
13905        });
13906        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13907        self.refresh_inline_completion(false, true, window, cx);
13908    }
13909
13910    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13911        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13912        let snapshot = self.snapshot(window, cx);
13913        let selection = self.selections.newest::<Point>(cx);
13914        self.go_to_hunk_before_or_after_position(
13915            &snapshot,
13916            selection.head(),
13917            Direction::Next,
13918            window,
13919            cx,
13920        );
13921    }
13922
13923    pub fn go_to_hunk_before_or_after_position(
13924        &mut self,
13925        snapshot: &EditorSnapshot,
13926        position: Point,
13927        direction: Direction,
13928        window: &mut Window,
13929        cx: &mut Context<Editor>,
13930    ) {
13931        let row = if direction == Direction::Next {
13932            self.hunk_after_position(snapshot, position)
13933                .map(|hunk| hunk.row_range.start)
13934        } else {
13935            self.hunk_before_position(snapshot, position)
13936        };
13937
13938        if let Some(row) = row {
13939            let destination = Point::new(row.0, 0);
13940            let autoscroll = Autoscroll::center();
13941
13942            self.unfold_ranges(&[destination..destination], false, false, cx);
13943            self.change_selections(Some(autoscroll), window, cx, |s| {
13944                s.select_ranges([destination..destination]);
13945            });
13946        }
13947    }
13948
13949    fn hunk_after_position(
13950        &mut self,
13951        snapshot: &EditorSnapshot,
13952        position: Point,
13953    ) -> Option<MultiBufferDiffHunk> {
13954        snapshot
13955            .buffer_snapshot
13956            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13957            .find(|hunk| hunk.row_range.start.0 > position.row)
13958            .or_else(|| {
13959                snapshot
13960                    .buffer_snapshot
13961                    .diff_hunks_in_range(Point::zero()..position)
13962                    .find(|hunk| hunk.row_range.end.0 < position.row)
13963            })
13964    }
13965
13966    fn go_to_prev_hunk(
13967        &mut self,
13968        _: &GoToPreviousHunk,
13969        window: &mut Window,
13970        cx: &mut Context<Self>,
13971    ) {
13972        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13973        let snapshot = self.snapshot(window, cx);
13974        let selection = self.selections.newest::<Point>(cx);
13975        self.go_to_hunk_before_or_after_position(
13976            &snapshot,
13977            selection.head(),
13978            Direction::Prev,
13979            window,
13980            cx,
13981        );
13982    }
13983
13984    fn hunk_before_position(
13985        &mut self,
13986        snapshot: &EditorSnapshot,
13987        position: Point,
13988    ) -> Option<MultiBufferRow> {
13989        snapshot
13990            .buffer_snapshot
13991            .diff_hunk_before(position)
13992            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
13993    }
13994
13995    fn go_to_next_change(
13996        &mut self,
13997        _: &GoToNextChange,
13998        window: &mut Window,
13999        cx: &mut Context<Self>,
14000    ) {
14001        if let Some(selections) = self
14002            .change_list
14003            .next_change(1, Direction::Next)
14004            .map(|s| s.to_vec())
14005        {
14006            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14007                let map = s.display_map();
14008                s.select_display_ranges(selections.iter().map(|a| {
14009                    let point = a.to_display_point(&map);
14010                    point..point
14011                }))
14012            })
14013        }
14014    }
14015
14016    fn go_to_previous_change(
14017        &mut self,
14018        _: &GoToPreviousChange,
14019        window: &mut Window,
14020        cx: &mut Context<Self>,
14021    ) {
14022        if let Some(selections) = self
14023            .change_list
14024            .next_change(1, Direction::Prev)
14025            .map(|s| s.to_vec())
14026        {
14027            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14028                let map = s.display_map();
14029                s.select_display_ranges(selections.iter().map(|a| {
14030                    let point = a.to_display_point(&map);
14031                    point..point
14032                }))
14033            })
14034        }
14035    }
14036
14037    fn go_to_line<T: 'static>(
14038        &mut self,
14039        position: Anchor,
14040        highlight_color: Option<Hsla>,
14041        window: &mut Window,
14042        cx: &mut Context<Self>,
14043    ) {
14044        let snapshot = self.snapshot(window, cx).display_snapshot;
14045        let position = position.to_point(&snapshot.buffer_snapshot);
14046        let start = snapshot
14047            .buffer_snapshot
14048            .clip_point(Point::new(position.row, 0), Bias::Left);
14049        let end = start + Point::new(1, 0);
14050        let start = snapshot.buffer_snapshot.anchor_before(start);
14051        let end = snapshot.buffer_snapshot.anchor_before(end);
14052
14053        self.highlight_rows::<T>(
14054            start..end,
14055            highlight_color
14056                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14057            Default::default(),
14058            cx,
14059        );
14060
14061        if self.buffer.read(cx).is_singleton() {
14062            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14063        }
14064    }
14065
14066    pub fn go_to_definition(
14067        &mut self,
14068        _: &GoToDefinition,
14069        window: &mut Window,
14070        cx: &mut Context<Self>,
14071    ) -> Task<Result<Navigated>> {
14072        let definition =
14073            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14074        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14075        cx.spawn_in(window, async move |editor, cx| {
14076            if definition.await? == Navigated::Yes {
14077                return Ok(Navigated::Yes);
14078            }
14079            match fallback_strategy {
14080                GoToDefinitionFallback::None => Ok(Navigated::No),
14081                GoToDefinitionFallback::FindAllReferences => {
14082                    match editor.update_in(cx, |editor, window, cx| {
14083                        editor.find_all_references(&FindAllReferences, window, cx)
14084                    })? {
14085                        Some(references) => references.await,
14086                        None => Ok(Navigated::No),
14087                    }
14088                }
14089            }
14090        })
14091    }
14092
14093    pub fn go_to_declaration(
14094        &mut self,
14095        _: &GoToDeclaration,
14096        window: &mut Window,
14097        cx: &mut Context<Self>,
14098    ) -> Task<Result<Navigated>> {
14099        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14100    }
14101
14102    pub fn go_to_declaration_split(
14103        &mut self,
14104        _: &GoToDeclaration,
14105        window: &mut Window,
14106        cx: &mut Context<Self>,
14107    ) -> Task<Result<Navigated>> {
14108        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14109    }
14110
14111    pub fn go_to_implementation(
14112        &mut self,
14113        _: &GoToImplementation,
14114        window: &mut Window,
14115        cx: &mut Context<Self>,
14116    ) -> Task<Result<Navigated>> {
14117        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14118    }
14119
14120    pub fn go_to_implementation_split(
14121        &mut self,
14122        _: &GoToImplementationSplit,
14123        window: &mut Window,
14124        cx: &mut Context<Self>,
14125    ) -> Task<Result<Navigated>> {
14126        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14127    }
14128
14129    pub fn go_to_type_definition(
14130        &mut self,
14131        _: &GoToTypeDefinition,
14132        window: &mut Window,
14133        cx: &mut Context<Self>,
14134    ) -> Task<Result<Navigated>> {
14135        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14136    }
14137
14138    pub fn go_to_definition_split(
14139        &mut self,
14140        _: &GoToDefinitionSplit,
14141        window: &mut Window,
14142        cx: &mut Context<Self>,
14143    ) -> Task<Result<Navigated>> {
14144        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14145    }
14146
14147    pub fn go_to_type_definition_split(
14148        &mut self,
14149        _: &GoToTypeDefinitionSplit,
14150        window: &mut Window,
14151        cx: &mut Context<Self>,
14152    ) -> Task<Result<Navigated>> {
14153        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14154    }
14155
14156    fn go_to_definition_of_kind(
14157        &mut self,
14158        kind: GotoDefinitionKind,
14159        split: bool,
14160        window: &mut Window,
14161        cx: &mut Context<Self>,
14162    ) -> Task<Result<Navigated>> {
14163        let Some(provider) = self.semantics_provider.clone() else {
14164            return Task::ready(Ok(Navigated::No));
14165        };
14166        let head = self.selections.newest::<usize>(cx).head();
14167        let buffer = self.buffer.read(cx);
14168        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14169            text_anchor
14170        } else {
14171            return Task::ready(Ok(Navigated::No));
14172        };
14173
14174        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14175            return Task::ready(Ok(Navigated::No));
14176        };
14177
14178        cx.spawn_in(window, async move |editor, cx| {
14179            let definitions = definitions.await?;
14180            let navigated = editor
14181                .update_in(cx, |editor, window, cx| {
14182                    editor.navigate_to_hover_links(
14183                        Some(kind),
14184                        definitions
14185                            .into_iter()
14186                            .filter(|location| {
14187                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14188                            })
14189                            .map(HoverLink::Text)
14190                            .collect::<Vec<_>>(),
14191                        split,
14192                        window,
14193                        cx,
14194                    )
14195                })?
14196                .await?;
14197            anyhow::Ok(navigated)
14198        })
14199    }
14200
14201    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14202        let selection = self.selections.newest_anchor();
14203        let head = selection.head();
14204        let tail = selection.tail();
14205
14206        let Some((buffer, start_position)) =
14207            self.buffer.read(cx).text_anchor_for_position(head, cx)
14208        else {
14209            return;
14210        };
14211
14212        let end_position = if head != tail {
14213            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14214                return;
14215            };
14216            Some(pos)
14217        } else {
14218            None
14219        };
14220
14221        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14222            let url = if let Some(end_pos) = end_position {
14223                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14224            } else {
14225                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14226            };
14227
14228            if let Some(url) = url {
14229                editor.update(cx, |_, cx| {
14230                    cx.open_url(&url);
14231                })
14232            } else {
14233                Ok(())
14234            }
14235        });
14236
14237        url_finder.detach();
14238    }
14239
14240    pub fn open_selected_filename(
14241        &mut self,
14242        _: &OpenSelectedFilename,
14243        window: &mut Window,
14244        cx: &mut Context<Self>,
14245    ) {
14246        let Some(workspace) = self.workspace() else {
14247            return;
14248        };
14249
14250        let position = self.selections.newest_anchor().head();
14251
14252        let Some((buffer, buffer_position)) =
14253            self.buffer.read(cx).text_anchor_for_position(position, cx)
14254        else {
14255            return;
14256        };
14257
14258        let project = self.project.clone();
14259
14260        cx.spawn_in(window, async move |_, cx| {
14261            let result = find_file(&buffer, project, buffer_position, cx).await;
14262
14263            if let Some((_, path)) = result {
14264                workspace
14265                    .update_in(cx, |workspace, window, cx| {
14266                        workspace.open_resolved_path(path, window, cx)
14267                    })?
14268                    .await?;
14269            }
14270            anyhow::Ok(())
14271        })
14272        .detach();
14273    }
14274
14275    pub(crate) fn navigate_to_hover_links(
14276        &mut self,
14277        kind: Option<GotoDefinitionKind>,
14278        mut definitions: Vec<HoverLink>,
14279        split: bool,
14280        window: &mut Window,
14281        cx: &mut Context<Editor>,
14282    ) -> Task<Result<Navigated>> {
14283        // If there is one definition, just open it directly
14284        if definitions.len() == 1 {
14285            let definition = definitions.pop().unwrap();
14286
14287            enum TargetTaskResult {
14288                Location(Option<Location>),
14289                AlreadyNavigated,
14290            }
14291
14292            let target_task = match definition {
14293                HoverLink::Text(link) => {
14294                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14295                }
14296                HoverLink::InlayHint(lsp_location, server_id) => {
14297                    let computation =
14298                        self.compute_target_location(lsp_location, server_id, window, cx);
14299                    cx.background_spawn(async move {
14300                        let location = computation.await?;
14301                        Ok(TargetTaskResult::Location(location))
14302                    })
14303                }
14304                HoverLink::Url(url) => {
14305                    cx.open_url(&url);
14306                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14307                }
14308                HoverLink::File(path) => {
14309                    if let Some(workspace) = self.workspace() {
14310                        cx.spawn_in(window, async move |_, cx| {
14311                            workspace
14312                                .update_in(cx, |workspace, window, cx| {
14313                                    workspace.open_resolved_path(path, window, cx)
14314                                })?
14315                                .await
14316                                .map(|_| TargetTaskResult::AlreadyNavigated)
14317                        })
14318                    } else {
14319                        Task::ready(Ok(TargetTaskResult::Location(None)))
14320                    }
14321                }
14322            };
14323            cx.spawn_in(window, async move |editor, cx| {
14324                let target = match target_task.await.context("target resolution task")? {
14325                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14326                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14327                    TargetTaskResult::Location(Some(target)) => target,
14328                };
14329
14330                editor.update_in(cx, |editor, window, cx| {
14331                    let Some(workspace) = editor.workspace() else {
14332                        return Navigated::No;
14333                    };
14334                    let pane = workspace.read(cx).active_pane().clone();
14335
14336                    let range = target.range.to_point(target.buffer.read(cx));
14337                    let range = editor.range_for_match(&range);
14338                    let range = collapse_multiline_range(range);
14339
14340                    if !split
14341                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14342                    {
14343                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14344                    } else {
14345                        window.defer(cx, move |window, cx| {
14346                            let target_editor: Entity<Self> =
14347                                workspace.update(cx, |workspace, cx| {
14348                                    let pane = if split {
14349                                        workspace.adjacent_pane(window, cx)
14350                                    } else {
14351                                        workspace.active_pane().clone()
14352                                    };
14353
14354                                    workspace.open_project_item(
14355                                        pane,
14356                                        target.buffer.clone(),
14357                                        true,
14358                                        true,
14359                                        window,
14360                                        cx,
14361                                    )
14362                                });
14363                            target_editor.update(cx, |target_editor, cx| {
14364                                // When selecting a definition in a different buffer, disable the nav history
14365                                // to avoid creating a history entry at the previous cursor location.
14366                                pane.update(cx, |pane, _| pane.disable_history());
14367                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14368                                pane.update(cx, |pane, _| pane.enable_history());
14369                            });
14370                        });
14371                    }
14372                    Navigated::Yes
14373                })
14374            })
14375        } else if !definitions.is_empty() {
14376            cx.spawn_in(window, async move |editor, cx| {
14377                let (title, location_tasks, workspace) = editor
14378                    .update_in(cx, |editor, window, cx| {
14379                        let tab_kind = match kind {
14380                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14381                            _ => "Definitions",
14382                        };
14383                        let title = definitions
14384                            .iter()
14385                            .find_map(|definition| match definition {
14386                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14387                                    let buffer = origin.buffer.read(cx);
14388                                    format!(
14389                                        "{} for {}",
14390                                        tab_kind,
14391                                        buffer
14392                                            .text_for_range(origin.range.clone())
14393                                            .collect::<String>()
14394                                    )
14395                                }),
14396                                HoverLink::InlayHint(_, _) => None,
14397                                HoverLink::Url(_) => None,
14398                                HoverLink::File(_) => None,
14399                            })
14400                            .unwrap_or(tab_kind.to_string());
14401                        let location_tasks = definitions
14402                            .into_iter()
14403                            .map(|definition| match definition {
14404                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14405                                HoverLink::InlayHint(lsp_location, server_id) => editor
14406                                    .compute_target_location(lsp_location, server_id, window, cx),
14407                                HoverLink::Url(_) => Task::ready(Ok(None)),
14408                                HoverLink::File(_) => Task::ready(Ok(None)),
14409                            })
14410                            .collect::<Vec<_>>();
14411                        (title, location_tasks, editor.workspace().clone())
14412                    })
14413                    .context("location tasks preparation")?;
14414
14415                let locations = future::join_all(location_tasks)
14416                    .await
14417                    .into_iter()
14418                    .filter_map(|location| location.transpose())
14419                    .collect::<Result<_>>()
14420                    .context("location tasks")?;
14421
14422                let Some(workspace) = workspace else {
14423                    return Ok(Navigated::No);
14424                };
14425                let opened = workspace
14426                    .update_in(cx, |workspace, window, cx| {
14427                        Self::open_locations_in_multibuffer(
14428                            workspace,
14429                            locations,
14430                            title,
14431                            split,
14432                            MultibufferSelectionMode::First,
14433                            window,
14434                            cx,
14435                        )
14436                    })
14437                    .ok();
14438
14439                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14440            })
14441        } else {
14442            Task::ready(Ok(Navigated::No))
14443        }
14444    }
14445
14446    fn compute_target_location(
14447        &self,
14448        lsp_location: lsp::Location,
14449        server_id: LanguageServerId,
14450        window: &mut Window,
14451        cx: &mut Context<Self>,
14452    ) -> Task<anyhow::Result<Option<Location>>> {
14453        let Some(project) = self.project.clone() else {
14454            return Task::ready(Ok(None));
14455        };
14456
14457        cx.spawn_in(window, async move |editor, cx| {
14458            let location_task = editor.update(cx, |_, cx| {
14459                project.update(cx, |project, cx| {
14460                    let language_server_name = project
14461                        .language_server_statuses(cx)
14462                        .find(|(id, _)| server_id == *id)
14463                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14464                    language_server_name.map(|language_server_name| {
14465                        project.open_local_buffer_via_lsp(
14466                            lsp_location.uri.clone(),
14467                            server_id,
14468                            language_server_name,
14469                            cx,
14470                        )
14471                    })
14472                })
14473            })?;
14474            let location = match location_task {
14475                Some(task) => Some({
14476                    let target_buffer_handle = task.await.context("open local buffer")?;
14477                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14478                        let target_start = target_buffer
14479                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14480                        let target_end = target_buffer
14481                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14482                        target_buffer.anchor_after(target_start)
14483                            ..target_buffer.anchor_before(target_end)
14484                    })?;
14485                    Location {
14486                        buffer: target_buffer_handle,
14487                        range,
14488                    }
14489                }),
14490                None => None,
14491            };
14492            Ok(location)
14493        })
14494    }
14495
14496    pub fn find_all_references(
14497        &mut self,
14498        _: &FindAllReferences,
14499        window: &mut Window,
14500        cx: &mut Context<Self>,
14501    ) -> Option<Task<Result<Navigated>>> {
14502        let selection = self.selections.newest::<usize>(cx);
14503        let multi_buffer = self.buffer.read(cx);
14504        let head = selection.head();
14505
14506        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14507        let head_anchor = multi_buffer_snapshot.anchor_at(
14508            head,
14509            if head < selection.tail() {
14510                Bias::Right
14511            } else {
14512                Bias::Left
14513            },
14514        );
14515
14516        match self
14517            .find_all_references_task_sources
14518            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14519        {
14520            Ok(_) => {
14521                log::info!(
14522                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14523                );
14524                return None;
14525            }
14526            Err(i) => {
14527                self.find_all_references_task_sources.insert(i, head_anchor);
14528            }
14529        }
14530
14531        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14532        let workspace = self.workspace()?;
14533        let project = workspace.read(cx).project().clone();
14534        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14535        Some(cx.spawn_in(window, async move |editor, cx| {
14536            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14537                if let Ok(i) = editor
14538                    .find_all_references_task_sources
14539                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14540                {
14541                    editor.find_all_references_task_sources.remove(i);
14542                }
14543            });
14544
14545            let locations = references.await?;
14546            if locations.is_empty() {
14547                return anyhow::Ok(Navigated::No);
14548            }
14549
14550            workspace.update_in(cx, |workspace, window, cx| {
14551                let title = locations
14552                    .first()
14553                    .as_ref()
14554                    .map(|location| {
14555                        let buffer = location.buffer.read(cx);
14556                        format!(
14557                            "References to `{}`",
14558                            buffer
14559                                .text_for_range(location.range.clone())
14560                                .collect::<String>()
14561                        )
14562                    })
14563                    .unwrap();
14564                Self::open_locations_in_multibuffer(
14565                    workspace,
14566                    locations,
14567                    title,
14568                    false,
14569                    MultibufferSelectionMode::First,
14570                    window,
14571                    cx,
14572                );
14573                Navigated::Yes
14574            })
14575        }))
14576    }
14577
14578    /// Opens a multibuffer with the given project locations in it
14579    pub fn open_locations_in_multibuffer(
14580        workspace: &mut Workspace,
14581        mut locations: Vec<Location>,
14582        title: String,
14583        split: bool,
14584        multibuffer_selection_mode: MultibufferSelectionMode,
14585        window: &mut Window,
14586        cx: &mut Context<Workspace>,
14587    ) {
14588        // If there are multiple definitions, open them in a multibuffer
14589        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14590        let mut locations = locations.into_iter().peekable();
14591        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14592        let capability = workspace.project().read(cx).capability();
14593
14594        let excerpt_buffer = cx.new(|cx| {
14595            let mut multibuffer = MultiBuffer::new(capability);
14596            while let Some(location) = locations.next() {
14597                let buffer = location.buffer.read(cx);
14598                let mut ranges_for_buffer = Vec::new();
14599                let range = location.range.to_point(buffer);
14600                ranges_for_buffer.push(range.clone());
14601
14602                while let Some(next_location) = locations.peek() {
14603                    if next_location.buffer == location.buffer {
14604                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14605                        locations.next();
14606                    } else {
14607                        break;
14608                    }
14609                }
14610
14611                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14612                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14613                    PathKey::for_buffer(&location.buffer, cx),
14614                    location.buffer.clone(),
14615                    ranges_for_buffer,
14616                    DEFAULT_MULTIBUFFER_CONTEXT,
14617                    cx,
14618                );
14619                ranges.extend(new_ranges)
14620            }
14621
14622            multibuffer.with_title(title)
14623        });
14624
14625        let editor = cx.new(|cx| {
14626            Editor::for_multibuffer(
14627                excerpt_buffer,
14628                Some(workspace.project().clone()),
14629                window,
14630                cx,
14631            )
14632        });
14633        editor.update(cx, |editor, cx| {
14634            match multibuffer_selection_mode {
14635                MultibufferSelectionMode::First => {
14636                    if let Some(first_range) = ranges.first() {
14637                        editor.change_selections(None, window, cx, |selections| {
14638                            selections.clear_disjoint();
14639                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14640                        });
14641                    }
14642                    editor.highlight_background::<Self>(
14643                        &ranges,
14644                        |theme| theme.editor_highlighted_line_background,
14645                        cx,
14646                    );
14647                }
14648                MultibufferSelectionMode::All => {
14649                    editor.change_selections(None, window, cx, |selections| {
14650                        selections.clear_disjoint();
14651                        selections.select_anchor_ranges(ranges);
14652                    });
14653                }
14654            }
14655            editor.register_buffers_with_language_servers(cx);
14656        });
14657
14658        let item = Box::new(editor);
14659        let item_id = item.item_id();
14660
14661        if split {
14662            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14663        } else {
14664            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14665                let (preview_item_id, preview_item_idx) =
14666                    workspace.active_pane().update(cx, |pane, _| {
14667                        (pane.preview_item_id(), pane.preview_item_idx())
14668                    });
14669
14670                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14671
14672                if let Some(preview_item_id) = preview_item_id {
14673                    workspace.active_pane().update(cx, |pane, cx| {
14674                        pane.remove_item(preview_item_id, false, false, window, cx);
14675                    });
14676                }
14677            } else {
14678                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14679            }
14680        }
14681        workspace.active_pane().update(cx, |pane, cx| {
14682            pane.set_preview_item_id(Some(item_id), cx);
14683        });
14684    }
14685
14686    pub fn rename(
14687        &mut self,
14688        _: &Rename,
14689        window: &mut Window,
14690        cx: &mut Context<Self>,
14691    ) -> Option<Task<Result<()>>> {
14692        use language::ToOffset as _;
14693
14694        let provider = self.semantics_provider.clone()?;
14695        let selection = self.selections.newest_anchor().clone();
14696        let (cursor_buffer, cursor_buffer_position) = self
14697            .buffer
14698            .read(cx)
14699            .text_anchor_for_position(selection.head(), cx)?;
14700        let (tail_buffer, cursor_buffer_position_end) = self
14701            .buffer
14702            .read(cx)
14703            .text_anchor_for_position(selection.tail(), cx)?;
14704        if tail_buffer != cursor_buffer {
14705            return None;
14706        }
14707
14708        let snapshot = cursor_buffer.read(cx).snapshot();
14709        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14710        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14711        let prepare_rename = provider
14712            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14713            .unwrap_or_else(|| Task::ready(Ok(None)));
14714        drop(snapshot);
14715
14716        Some(cx.spawn_in(window, async move |this, cx| {
14717            let rename_range = if let Some(range) = prepare_rename.await? {
14718                Some(range)
14719            } else {
14720                this.update(cx, |this, cx| {
14721                    let buffer = this.buffer.read(cx).snapshot(cx);
14722                    let mut buffer_highlights = this
14723                        .document_highlights_for_position(selection.head(), &buffer)
14724                        .filter(|highlight| {
14725                            highlight.start.excerpt_id == selection.head().excerpt_id
14726                                && highlight.end.excerpt_id == selection.head().excerpt_id
14727                        });
14728                    buffer_highlights
14729                        .next()
14730                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14731                })?
14732            };
14733            if let Some(rename_range) = rename_range {
14734                this.update_in(cx, |this, window, cx| {
14735                    let snapshot = cursor_buffer.read(cx).snapshot();
14736                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14737                    let cursor_offset_in_rename_range =
14738                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14739                    let cursor_offset_in_rename_range_end =
14740                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14741
14742                    this.take_rename(false, window, cx);
14743                    let buffer = this.buffer.read(cx).read(cx);
14744                    let cursor_offset = selection.head().to_offset(&buffer);
14745                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14746                    let rename_end = rename_start + rename_buffer_range.len();
14747                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14748                    let mut old_highlight_id = None;
14749                    let old_name: Arc<str> = buffer
14750                        .chunks(rename_start..rename_end, true)
14751                        .map(|chunk| {
14752                            if old_highlight_id.is_none() {
14753                                old_highlight_id = chunk.syntax_highlight_id;
14754                            }
14755                            chunk.text
14756                        })
14757                        .collect::<String>()
14758                        .into();
14759
14760                    drop(buffer);
14761
14762                    // Position the selection in the rename editor so that it matches the current selection.
14763                    this.show_local_selections = false;
14764                    let rename_editor = cx.new(|cx| {
14765                        let mut editor = Editor::single_line(window, cx);
14766                        editor.buffer.update(cx, |buffer, cx| {
14767                            buffer.edit([(0..0, old_name.clone())], None, cx)
14768                        });
14769                        let rename_selection_range = match cursor_offset_in_rename_range
14770                            .cmp(&cursor_offset_in_rename_range_end)
14771                        {
14772                            Ordering::Equal => {
14773                                editor.select_all(&SelectAll, window, cx);
14774                                return editor;
14775                            }
14776                            Ordering::Less => {
14777                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14778                            }
14779                            Ordering::Greater => {
14780                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14781                            }
14782                        };
14783                        if rename_selection_range.end > old_name.len() {
14784                            editor.select_all(&SelectAll, window, cx);
14785                        } else {
14786                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14787                                s.select_ranges([rename_selection_range]);
14788                            });
14789                        }
14790                        editor
14791                    });
14792                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14793                        if e == &EditorEvent::Focused {
14794                            cx.emit(EditorEvent::FocusedIn)
14795                        }
14796                    })
14797                    .detach();
14798
14799                    let write_highlights =
14800                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14801                    let read_highlights =
14802                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14803                    let ranges = write_highlights
14804                        .iter()
14805                        .flat_map(|(_, ranges)| ranges.iter())
14806                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14807                        .cloned()
14808                        .collect();
14809
14810                    this.highlight_text::<Rename>(
14811                        ranges,
14812                        HighlightStyle {
14813                            fade_out: Some(0.6),
14814                            ..Default::default()
14815                        },
14816                        cx,
14817                    );
14818                    let rename_focus_handle = rename_editor.focus_handle(cx);
14819                    window.focus(&rename_focus_handle);
14820                    let block_id = this.insert_blocks(
14821                        [BlockProperties {
14822                            style: BlockStyle::Flex,
14823                            placement: BlockPlacement::Below(range.start),
14824                            height: Some(1),
14825                            render: Arc::new({
14826                                let rename_editor = rename_editor.clone();
14827                                move |cx: &mut BlockContext| {
14828                                    let mut text_style = cx.editor_style.text.clone();
14829                                    if let Some(highlight_style) = old_highlight_id
14830                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14831                                    {
14832                                        text_style = text_style.highlight(highlight_style);
14833                                    }
14834                                    div()
14835                                        .block_mouse_down()
14836                                        .pl(cx.anchor_x)
14837                                        .child(EditorElement::new(
14838                                            &rename_editor,
14839                                            EditorStyle {
14840                                                background: cx.theme().system().transparent,
14841                                                local_player: cx.editor_style.local_player,
14842                                                text: text_style,
14843                                                scrollbar_width: cx.editor_style.scrollbar_width,
14844                                                syntax: cx.editor_style.syntax.clone(),
14845                                                status: cx.editor_style.status.clone(),
14846                                                inlay_hints_style: HighlightStyle {
14847                                                    font_weight: Some(FontWeight::BOLD),
14848                                                    ..make_inlay_hints_style(cx.app)
14849                                                },
14850                                                inline_completion_styles: make_suggestion_styles(
14851                                                    cx.app,
14852                                                ),
14853                                                ..EditorStyle::default()
14854                                            },
14855                                        ))
14856                                        .into_any_element()
14857                                }
14858                            }),
14859                            priority: 0,
14860                            render_in_minimap: true,
14861                        }],
14862                        Some(Autoscroll::fit()),
14863                        cx,
14864                    )[0];
14865                    this.pending_rename = Some(RenameState {
14866                        range,
14867                        old_name,
14868                        editor: rename_editor,
14869                        block_id,
14870                    });
14871                })?;
14872            }
14873
14874            Ok(())
14875        }))
14876    }
14877
14878    pub fn confirm_rename(
14879        &mut self,
14880        _: &ConfirmRename,
14881        window: &mut Window,
14882        cx: &mut Context<Self>,
14883    ) -> Option<Task<Result<()>>> {
14884        let rename = self.take_rename(false, window, cx)?;
14885        let workspace = self.workspace()?.downgrade();
14886        let (buffer, start) = self
14887            .buffer
14888            .read(cx)
14889            .text_anchor_for_position(rename.range.start, cx)?;
14890        let (end_buffer, _) = self
14891            .buffer
14892            .read(cx)
14893            .text_anchor_for_position(rename.range.end, cx)?;
14894        if buffer != end_buffer {
14895            return None;
14896        }
14897
14898        let old_name = rename.old_name;
14899        let new_name = rename.editor.read(cx).text(cx);
14900
14901        let rename = self.semantics_provider.as_ref()?.perform_rename(
14902            &buffer,
14903            start,
14904            new_name.clone(),
14905            cx,
14906        )?;
14907
14908        Some(cx.spawn_in(window, async move |editor, cx| {
14909            let project_transaction = rename.await?;
14910            Self::open_project_transaction(
14911                &editor,
14912                workspace,
14913                project_transaction,
14914                format!("Rename: {}{}", old_name, new_name),
14915                cx,
14916            )
14917            .await?;
14918
14919            editor.update(cx, |editor, cx| {
14920                editor.refresh_document_highlights(cx);
14921            })?;
14922            Ok(())
14923        }))
14924    }
14925
14926    fn take_rename(
14927        &mut self,
14928        moving_cursor: bool,
14929        window: &mut Window,
14930        cx: &mut Context<Self>,
14931    ) -> Option<RenameState> {
14932        let rename = self.pending_rename.take()?;
14933        if rename.editor.focus_handle(cx).is_focused(window) {
14934            window.focus(&self.focus_handle);
14935        }
14936
14937        self.remove_blocks(
14938            [rename.block_id].into_iter().collect(),
14939            Some(Autoscroll::fit()),
14940            cx,
14941        );
14942        self.clear_highlights::<Rename>(cx);
14943        self.show_local_selections = true;
14944
14945        if moving_cursor {
14946            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14947                editor.selections.newest::<usize>(cx).head()
14948            });
14949
14950            // Update the selection to match the position of the selection inside
14951            // the rename editor.
14952            let snapshot = self.buffer.read(cx).read(cx);
14953            let rename_range = rename.range.to_offset(&snapshot);
14954            let cursor_in_editor = snapshot
14955                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14956                .min(rename_range.end);
14957            drop(snapshot);
14958
14959            self.change_selections(None, window, cx, |s| {
14960                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14961            });
14962        } else {
14963            self.refresh_document_highlights(cx);
14964        }
14965
14966        Some(rename)
14967    }
14968
14969    pub fn pending_rename(&self) -> Option<&RenameState> {
14970        self.pending_rename.as_ref()
14971    }
14972
14973    fn format(
14974        &mut self,
14975        _: &Format,
14976        window: &mut Window,
14977        cx: &mut Context<Self>,
14978    ) -> Option<Task<Result<()>>> {
14979        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14980
14981        let project = match &self.project {
14982            Some(project) => project.clone(),
14983            None => return None,
14984        };
14985
14986        Some(self.perform_format(
14987            project,
14988            FormatTrigger::Manual,
14989            FormatTarget::Buffers,
14990            window,
14991            cx,
14992        ))
14993    }
14994
14995    fn format_selections(
14996        &mut self,
14997        _: &FormatSelections,
14998        window: &mut Window,
14999        cx: &mut Context<Self>,
15000    ) -> Option<Task<Result<()>>> {
15001        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15002
15003        let project = match &self.project {
15004            Some(project) => project.clone(),
15005            None => return None,
15006        };
15007
15008        let ranges = self
15009            .selections
15010            .all_adjusted(cx)
15011            .into_iter()
15012            .map(|selection| selection.range())
15013            .collect_vec();
15014
15015        Some(self.perform_format(
15016            project,
15017            FormatTrigger::Manual,
15018            FormatTarget::Ranges(ranges),
15019            window,
15020            cx,
15021        ))
15022    }
15023
15024    fn perform_format(
15025        &mut self,
15026        project: Entity<Project>,
15027        trigger: FormatTrigger,
15028        target: FormatTarget,
15029        window: &mut Window,
15030        cx: &mut Context<Self>,
15031    ) -> Task<Result<()>> {
15032        let buffer = self.buffer.clone();
15033        let (buffers, target) = match target {
15034            FormatTarget::Buffers => {
15035                let mut buffers = buffer.read(cx).all_buffers();
15036                if trigger == FormatTrigger::Save {
15037                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15038                }
15039                (buffers, LspFormatTarget::Buffers)
15040            }
15041            FormatTarget::Ranges(selection_ranges) => {
15042                let multi_buffer = buffer.read(cx);
15043                let snapshot = multi_buffer.read(cx);
15044                let mut buffers = HashSet::default();
15045                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15046                    BTreeMap::new();
15047                for selection_range in selection_ranges {
15048                    for (buffer, buffer_range, _) in
15049                        snapshot.range_to_buffer_ranges(selection_range)
15050                    {
15051                        let buffer_id = buffer.remote_id();
15052                        let start = buffer.anchor_before(buffer_range.start);
15053                        let end = buffer.anchor_after(buffer_range.end);
15054                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15055                        buffer_id_to_ranges
15056                            .entry(buffer_id)
15057                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15058                            .or_insert_with(|| vec![start..end]);
15059                    }
15060                }
15061                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15062            }
15063        };
15064
15065        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15066        let selections_prev = transaction_id_prev
15067            .and_then(|transaction_id_prev| {
15068                // default to selections as they were after the last edit, if we have them,
15069                // instead of how they are now.
15070                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15071                // will take you back to where you made the last edit, instead of staying where you scrolled
15072                self.selection_history
15073                    .transaction(transaction_id_prev)
15074                    .map(|t| t.0.clone())
15075            })
15076            .unwrap_or_else(|| {
15077                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15078                self.selections.disjoint_anchors()
15079            });
15080
15081        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15082        let format = project.update(cx, |project, cx| {
15083            project.format(buffers, target, true, trigger, cx)
15084        });
15085
15086        cx.spawn_in(window, async move |editor, cx| {
15087            let transaction = futures::select_biased! {
15088                transaction = format.log_err().fuse() => transaction,
15089                () = timeout => {
15090                    log::warn!("timed out waiting for formatting");
15091                    None
15092                }
15093            };
15094
15095            buffer
15096                .update(cx, |buffer, cx| {
15097                    if let Some(transaction) = transaction {
15098                        if !buffer.is_singleton() {
15099                            buffer.push_transaction(&transaction.0, cx);
15100                        }
15101                    }
15102                    cx.notify();
15103                })
15104                .ok();
15105
15106            if let Some(transaction_id_now) =
15107                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15108            {
15109                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15110                if has_new_transaction {
15111                    _ = editor.update(cx, |editor, _| {
15112                        editor
15113                            .selection_history
15114                            .insert_transaction(transaction_id_now, selections_prev);
15115                    });
15116                }
15117            }
15118
15119            Ok(())
15120        })
15121    }
15122
15123    fn organize_imports(
15124        &mut self,
15125        _: &OrganizeImports,
15126        window: &mut Window,
15127        cx: &mut Context<Self>,
15128    ) -> Option<Task<Result<()>>> {
15129        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15130        let project = match &self.project {
15131            Some(project) => project.clone(),
15132            None => return None,
15133        };
15134        Some(self.perform_code_action_kind(
15135            project,
15136            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15137            window,
15138            cx,
15139        ))
15140    }
15141
15142    fn perform_code_action_kind(
15143        &mut self,
15144        project: Entity<Project>,
15145        kind: CodeActionKind,
15146        window: &mut Window,
15147        cx: &mut Context<Self>,
15148    ) -> Task<Result<()>> {
15149        let buffer = self.buffer.clone();
15150        let buffers = buffer.read(cx).all_buffers();
15151        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15152        let apply_action = project.update(cx, |project, cx| {
15153            project.apply_code_action_kind(buffers, kind, true, cx)
15154        });
15155        cx.spawn_in(window, async move |_, cx| {
15156            let transaction = futures::select_biased! {
15157                () = timeout => {
15158                    log::warn!("timed out waiting for executing code action");
15159                    None
15160                }
15161                transaction = apply_action.log_err().fuse() => transaction,
15162            };
15163            buffer
15164                .update(cx, |buffer, cx| {
15165                    // check if we need this
15166                    if let Some(transaction) = transaction {
15167                        if !buffer.is_singleton() {
15168                            buffer.push_transaction(&transaction.0, cx);
15169                        }
15170                    }
15171                    cx.notify();
15172                })
15173                .ok();
15174            Ok(())
15175        })
15176    }
15177
15178    fn restart_language_server(
15179        &mut self,
15180        _: &RestartLanguageServer,
15181        _: &mut Window,
15182        cx: &mut Context<Self>,
15183    ) {
15184        if let Some(project) = self.project.clone() {
15185            self.buffer.update(cx, |multi_buffer, cx| {
15186                project.update(cx, |project, cx| {
15187                    project.restart_language_servers_for_buffers(
15188                        multi_buffer.all_buffers().into_iter().collect(),
15189                        cx,
15190                    );
15191                });
15192            })
15193        }
15194    }
15195
15196    fn stop_language_server(
15197        &mut self,
15198        _: &StopLanguageServer,
15199        _: &mut Window,
15200        cx: &mut Context<Self>,
15201    ) {
15202        if let Some(project) = self.project.clone() {
15203            self.buffer.update(cx, |multi_buffer, cx| {
15204                project.update(cx, |project, cx| {
15205                    project.stop_language_servers_for_buffers(
15206                        multi_buffer.all_buffers().into_iter().collect(),
15207                        cx,
15208                    );
15209                    cx.emit(project::Event::RefreshInlayHints);
15210                });
15211            });
15212        }
15213    }
15214
15215    fn cancel_language_server_work(
15216        workspace: &mut Workspace,
15217        _: &actions::CancelLanguageServerWork,
15218        _: &mut Window,
15219        cx: &mut Context<Workspace>,
15220    ) {
15221        let project = workspace.project();
15222        let buffers = workspace
15223            .active_item(cx)
15224            .and_then(|item| item.act_as::<Editor>(cx))
15225            .map_or(HashSet::default(), |editor| {
15226                editor.read(cx).buffer.read(cx).all_buffers()
15227            });
15228        project.update(cx, |project, cx| {
15229            project.cancel_language_server_work_for_buffers(buffers, cx);
15230        });
15231    }
15232
15233    fn show_character_palette(
15234        &mut self,
15235        _: &ShowCharacterPalette,
15236        window: &mut Window,
15237        _: &mut Context<Self>,
15238    ) {
15239        window.show_character_palette();
15240    }
15241
15242    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15243        if self.mode.is_minimap() {
15244            return;
15245        }
15246
15247        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15248            let buffer = self.buffer.read(cx).snapshot(cx);
15249            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15250            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15251            let is_valid = buffer
15252                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15253                .any(|entry| {
15254                    entry.diagnostic.is_primary
15255                        && !entry.range.is_empty()
15256                        && entry.range.start == primary_range_start
15257                        && entry.diagnostic.message == active_diagnostics.active_message
15258                });
15259
15260            if !is_valid {
15261                self.dismiss_diagnostics(cx);
15262            }
15263        }
15264    }
15265
15266    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15267        match &self.active_diagnostics {
15268            ActiveDiagnostic::Group(group) => Some(group),
15269            _ => None,
15270        }
15271    }
15272
15273    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15274        self.dismiss_diagnostics(cx);
15275        self.active_diagnostics = ActiveDiagnostic::All;
15276    }
15277
15278    fn activate_diagnostics(
15279        &mut self,
15280        buffer_id: BufferId,
15281        diagnostic: DiagnosticEntry<usize>,
15282        window: &mut Window,
15283        cx: &mut Context<Self>,
15284    ) {
15285        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15286            return;
15287        }
15288        self.dismiss_diagnostics(cx);
15289        let snapshot = self.snapshot(window, cx);
15290        let buffer = self.buffer.read(cx).snapshot(cx);
15291        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15292            return;
15293        };
15294
15295        let diagnostic_group = buffer
15296            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15297            .collect::<Vec<_>>();
15298
15299        let blocks =
15300            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15301
15302        let blocks = self.display_map.update(cx, |display_map, cx| {
15303            display_map.insert_blocks(blocks, cx).into_iter().collect()
15304        });
15305        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15306            active_range: buffer.anchor_before(diagnostic.range.start)
15307                ..buffer.anchor_after(diagnostic.range.end),
15308            active_message: diagnostic.diagnostic.message.clone(),
15309            group_id: diagnostic.diagnostic.group_id,
15310            blocks,
15311        });
15312        cx.notify();
15313    }
15314
15315    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15316        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15317            return;
15318        };
15319
15320        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15321        if let ActiveDiagnostic::Group(group) = prev {
15322            self.display_map.update(cx, |display_map, cx| {
15323                display_map.remove_blocks(group.blocks, cx);
15324            });
15325            cx.notify();
15326        }
15327    }
15328
15329    /// Disable inline diagnostics rendering for this editor.
15330    pub fn disable_inline_diagnostics(&mut self) {
15331        self.inline_diagnostics_enabled = false;
15332        self.inline_diagnostics_update = Task::ready(());
15333        self.inline_diagnostics.clear();
15334    }
15335
15336    pub fn diagnostics_enabled(&self) -> bool {
15337        self.mode.is_full()
15338    }
15339
15340    pub fn inline_diagnostics_enabled(&self) -> bool {
15341        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15342    }
15343
15344    pub fn show_inline_diagnostics(&self) -> bool {
15345        self.show_inline_diagnostics
15346    }
15347
15348    pub fn toggle_inline_diagnostics(
15349        &mut self,
15350        _: &ToggleInlineDiagnostics,
15351        window: &mut Window,
15352        cx: &mut Context<Editor>,
15353    ) {
15354        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15355        self.refresh_inline_diagnostics(false, window, cx);
15356    }
15357
15358    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15359        self.diagnostics_max_severity = severity;
15360        self.display_map.update(cx, |display_map, _| {
15361            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15362        });
15363    }
15364
15365    pub fn toggle_diagnostics(
15366        &mut self,
15367        _: &ToggleDiagnostics,
15368        window: &mut Window,
15369        cx: &mut Context<Editor>,
15370    ) {
15371        if !self.diagnostics_enabled() {
15372            return;
15373        }
15374
15375        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15376            EditorSettings::get_global(cx)
15377                .diagnostics_max_severity
15378                .filter(|severity| severity != &DiagnosticSeverity::Off)
15379                .unwrap_or(DiagnosticSeverity::Hint)
15380        } else {
15381            DiagnosticSeverity::Off
15382        };
15383        self.set_max_diagnostics_severity(new_severity, cx);
15384        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15385            self.active_diagnostics = ActiveDiagnostic::None;
15386            self.inline_diagnostics_update = Task::ready(());
15387            self.inline_diagnostics.clear();
15388        } else {
15389            self.refresh_inline_diagnostics(false, window, cx);
15390        }
15391
15392        cx.notify();
15393    }
15394
15395    pub fn toggle_minimap(
15396        &mut self,
15397        _: &ToggleMinimap,
15398        window: &mut Window,
15399        cx: &mut Context<Editor>,
15400    ) {
15401        if self.supports_minimap(cx) {
15402            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15403        }
15404    }
15405
15406    fn refresh_inline_diagnostics(
15407        &mut self,
15408        debounce: bool,
15409        window: &mut Window,
15410        cx: &mut Context<Self>,
15411    ) {
15412        let max_severity = ProjectSettings::get_global(cx)
15413            .diagnostics
15414            .inline
15415            .max_severity
15416            .unwrap_or(self.diagnostics_max_severity);
15417
15418        if self.mode.is_minimap()
15419            || !self.inline_diagnostics_enabled()
15420            || !self.show_inline_diagnostics
15421            || max_severity == DiagnosticSeverity::Off
15422        {
15423            self.inline_diagnostics_update = Task::ready(());
15424            self.inline_diagnostics.clear();
15425            return;
15426        }
15427
15428        let debounce_ms = ProjectSettings::get_global(cx)
15429            .diagnostics
15430            .inline
15431            .update_debounce_ms;
15432        let debounce = if debounce && debounce_ms > 0 {
15433            Some(Duration::from_millis(debounce_ms))
15434        } else {
15435            None
15436        };
15437        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15438            let editor = editor.upgrade().unwrap();
15439
15440            if let Some(debounce) = debounce {
15441                cx.background_executor().timer(debounce).await;
15442            }
15443            let Some(snapshot) = editor
15444                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15445                .ok()
15446            else {
15447                return;
15448            };
15449
15450            let new_inline_diagnostics = cx
15451                .background_spawn(async move {
15452                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15453                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15454                        let message = diagnostic_entry
15455                            .diagnostic
15456                            .message
15457                            .split_once('\n')
15458                            .map(|(line, _)| line)
15459                            .map(SharedString::new)
15460                            .unwrap_or_else(|| {
15461                                SharedString::from(diagnostic_entry.diagnostic.message)
15462                            });
15463                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15464                        let (Ok(i) | Err(i)) = inline_diagnostics
15465                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15466                        inline_diagnostics.insert(
15467                            i,
15468                            (
15469                                start_anchor,
15470                                InlineDiagnostic {
15471                                    message,
15472                                    group_id: diagnostic_entry.diagnostic.group_id,
15473                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15474                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15475                                    severity: diagnostic_entry.diagnostic.severity,
15476                                },
15477                            ),
15478                        );
15479                    }
15480                    inline_diagnostics
15481                })
15482                .await;
15483
15484            editor
15485                .update(cx, |editor, cx| {
15486                    editor.inline_diagnostics = new_inline_diagnostics;
15487                    cx.notify();
15488                })
15489                .ok();
15490        });
15491    }
15492
15493    pub fn set_selections_from_remote(
15494        &mut self,
15495        selections: Vec<Selection<Anchor>>,
15496        pending_selection: Option<Selection<Anchor>>,
15497        window: &mut Window,
15498        cx: &mut Context<Self>,
15499    ) {
15500        let old_cursor_position = self.selections.newest_anchor().head();
15501        self.selections.change_with(cx, |s| {
15502            s.select_anchors(selections);
15503            if let Some(pending_selection) = pending_selection {
15504                s.set_pending(pending_selection, SelectMode::Character);
15505            } else {
15506                s.clear_pending();
15507            }
15508        });
15509        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15510    }
15511
15512    fn push_to_selection_history(&mut self) {
15513        self.selection_history.push(SelectionHistoryEntry {
15514            selections: self.selections.disjoint_anchors(),
15515            select_next_state: self.select_next_state.clone(),
15516            select_prev_state: self.select_prev_state.clone(),
15517            add_selections_state: self.add_selections_state.clone(),
15518        });
15519    }
15520
15521    pub fn transact(
15522        &mut self,
15523        window: &mut Window,
15524        cx: &mut Context<Self>,
15525        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15526    ) -> Option<TransactionId> {
15527        self.start_transaction_at(Instant::now(), window, cx);
15528        update(self, window, cx);
15529        self.end_transaction_at(Instant::now(), cx)
15530    }
15531
15532    pub fn start_transaction_at(
15533        &mut self,
15534        now: Instant,
15535        window: &mut Window,
15536        cx: &mut Context<Self>,
15537    ) {
15538        self.end_selection(window, cx);
15539        if let Some(tx_id) = self
15540            .buffer
15541            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15542        {
15543            self.selection_history
15544                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15545            cx.emit(EditorEvent::TransactionBegun {
15546                transaction_id: tx_id,
15547            })
15548        }
15549    }
15550
15551    pub fn end_transaction_at(
15552        &mut self,
15553        now: Instant,
15554        cx: &mut Context<Self>,
15555    ) -> Option<TransactionId> {
15556        if let Some(transaction_id) = self
15557            .buffer
15558            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15559        {
15560            if let Some((_, end_selections)) =
15561                self.selection_history.transaction_mut(transaction_id)
15562            {
15563                *end_selections = Some(self.selections.disjoint_anchors());
15564            } else {
15565                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15566            }
15567
15568            cx.emit(EditorEvent::Edited { transaction_id });
15569            Some(transaction_id)
15570        } else {
15571            None
15572        }
15573    }
15574
15575    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15576        if self.selection_mark_mode {
15577            self.change_selections(None, window, cx, |s| {
15578                s.move_with(|_, sel| {
15579                    sel.collapse_to(sel.head(), SelectionGoal::None);
15580                });
15581            })
15582        }
15583        self.selection_mark_mode = true;
15584        cx.notify();
15585    }
15586
15587    pub fn swap_selection_ends(
15588        &mut self,
15589        _: &actions::SwapSelectionEnds,
15590        window: &mut Window,
15591        cx: &mut Context<Self>,
15592    ) {
15593        self.change_selections(None, window, cx, |s| {
15594            s.move_with(|_, sel| {
15595                if sel.start != sel.end {
15596                    sel.reversed = !sel.reversed
15597                }
15598            });
15599        });
15600        self.request_autoscroll(Autoscroll::newest(), cx);
15601        cx.notify();
15602    }
15603
15604    pub fn toggle_fold(
15605        &mut self,
15606        _: &actions::ToggleFold,
15607        window: &mut Window,
15608        cx: &mut Context<Self>,
15609    ) {
15610        if self.is_singleton(cx) {
15611            let selection = self.selections.newest::<Point>(cx);
15612
15613            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15614            let range = if selection.is_empty() {
15615                let point = selection.head().to_display_point(&display_map);
15616                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15617                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15618                    .to_point(&display_map);
15619                start..end
15620            } else {
15621                selection.range()
15622            };
15623            if display_map.folds_in_range(range).next().is_some() {
15624                self.unfold_lines(&Default::default(), window, cx)
15625            } else {
15626                self.fold(&Default::default(), window, cx)
15627            }
15628        } else {
15629            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15630            let buffer_ids: HashSet<_> = self
15631                .selections
15632                .disjoint_anchor_ranges()
15633                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15634                .collect();
15635
15636            let should_unfold = buffer_ids
15637                .iter()
15638                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15639
15640            for buffer_id in buffer_ids {
15641                if should_unfold {
15642                    self.unfold_buffer(buffer_id, cx);
15643                } else {
15644                    self.fold_buffer(buffer_id, cx);
15645                }
15646            }
15647        }
15648    }
15649
15650    pub fn toggle_fold_recursive(
15651        &mut self,
15652        _: &actions::ToggleFoldRecursive,
15653        window: &mut Window,
15654        cx: &mut Context<Self>,
15655    ) {
15656        let selection = self.selections.newest::<Point>(cx);
15657
15658        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15659        let range = if selection.is_empty() {
15660            let point = selection.head().to_display_point(&display_map);
15661            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15662            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15663                .to_point(&display_map);
15664            start..end
15665        } else {
15666            selection.range()
15667        };
15668        if display_map.folds_in_range(range).next().is_some() {
15669            self.unfold_recursive(&Default::default(), window, cx)
15670        } else {
15671            self.fold_recursive(&Default::default(), window, cx)
15672        }
15673    }
15674
15675    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15676        if self.is_singleton(cx) {
15677            let mut to_fold = Vec::new();
15678            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15679            let selections = self.selections.all_adjusted(cx);
15680
15681            for selection in selections {
15682                let range = selection.range().sorted();
15683                let buffer_start_row = range.start.row;
15684
15685                if range.start.row != range.end.row {
15686                    let mut found = false;
15687                    let mut row = range.start.row;
15688                    while row <= range.end.row {
15689                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15690                        {
15691                            found = true;
15692                            row = crease.range().end.row + 1;
15693                            to_fold.push(crease);
15694                        } else {
15695                            row += 1
15696                        }
15697                    }
15698                    if found {
15699                        continue;
15700                    }
15701                }
15702
15703                for row in (0..=range.start.row).rev() {
15704                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15705                        if crease.range().end.row >= buffer_start_row {
15706                            to_fold.push(crease);
15707                            if row <= range.start.row {
15708                                break;
15709                            }
15710                        }
15711                    }
15712                }
15713            }
15714
15715            self.fold_creases(to_fold, true, window, cx);
15716        } else {
15717            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15718            let buffer_ids = self
15719                .selections
15720                .disjoint_anchor_ranges()
15721                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15722                .collect::<HashSet<_>>();
15723            for buffer_id in buffer_ids {
15724                self.fold_buffer(buffer_id, cx);
15725            }
15726        }
15727    }
15728
15729    fn fold_at_level(
15730        &mut self,
15731        fold_at: &FoldAtLevel,
15732        window: &mut Window,
15733        cx: &mut Context<Self>,
15734    ) {
15735        if !self.buffer.read(cx).is_singleton() {
15736            return;
15737        }
15738
15739        let fold_at_level = fold_at.0;
15740        let snapshot = self.buffer.read(cx).snapshot(cx);
15741        let mut to_fold = Vec::new();
15742        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15743
15744        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15745            while start_row < end_row {
15746                match self
15747                    .snapshot(window, cx)
15748                    .crease_for_buffer_row(MultiBufferRow(start_row))
15749                {
15750                    Some(crease) => {
15751                        let nested_start_row = crease.range().start.row + 1;
15752                        let nested_end_row = crease.range().end.row;
15753
15754                        if current_level < fold_at_level {
15755                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15756                        } else if current_level == fold_at_level {
15757                            to_fold.push(crease);
15758                        }
15759
15760                        start_row = nested_end_row + 1;
15761                    }
15762                    None => start_row += 1,
15763                }
15764            }
15765        }
15766
15767        self.fold_creases(to_fold, true, window, cx);
15768    }
15769
15770    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15771        if self.buffer.read(cx).is_singleton() {
15772            let mut fold_ranges = Vec::new();
15773            let snapshot = self.buffer.read(cx).snapshot(cx);
15774
15775            for row in 0..snapshot.max_row().0 {
15776                if let Some(foldable_range) = self
15777                    .snapshot(window, cx)
15778                    .crease_for_buffer_row(MultiBufferRow(row))
15779                {
15780                    fold_ranges.push(foldable_range);
15781                }
15782            }
15783
15784            self.fold_creases(fold_ranges, true, window, cx);
15785        } else {
15786            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15787                editor
15788                    .update_in(cx, |editor, _, cx| {
15789                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15790                            editor.fold_buffer(buffer_id, cx);
15791                        }
15792                    })
15793                    .ok();
15794            });
15795        }
15796    }
15797
15798    pub fn fold_function_bodies(
15799        &mut self,
15800        _: &actions::FoldFunctionBodies,
15801        window: &mut Window,
15802        cx: &mut Context<Self>,
15803    ) {
15804        let snapshot = self.buffer.read(cx).snapshot(cx);
15805
15806        let ranges = snapshot
15807            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15808            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15809            .collect::<Vec<_>>();
15810
15811        let creases = ranges
15812            .into_iter()
15813            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15814            .collect();
15815
15816        self.fold_creases(creases, true, window, cx);
15817    }
15818
15819    pub fn fold_recursive(
15820        &mut self,
15821        _: &actions::FoldRecursive,
15822        window: &mut Window,
15823        cx: &mut Context<Self>,
15824    ) {
15825        let mut to_fold = Vec::new();
15826        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15827        let selections = self.selections.all_adjusted(cx);
15828
15829        for selection in selections {
15830            let range = selection.range().sorted();
15831            let buffer_start_row = range.start.row;
15832
15833            if range.start.row != range.end.row {
15834                let mut found = false;
15835                for row in range.start.row..=range.end.row {
15836                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15837                        found = true;
15838                        to_fold.push(crease);
15839                    }
15840                }
15841                if found {
15842                    continue;
15843                }
15844            }
15845
15846            for row in (0..=range.start.row).rev() {
15847                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15848                    if crease.range().end.row >= buffer_start_row {
15849                        to_fold.push(crease);
15850                    } else {
15851                        break;
15852                    }
15853                }
15854            }
15855        }
15856
15857        self.fold_creases(to_fold, true, window, cx);
15858    }
15859
15860    pub fn fold_at(
15861        &mut self,
15862        buffer_row: MultiBufferRow,
15863        window: &mut Window,
15864        cx: &mut Context<Self>,
15865    ) {
15866        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15867
15868        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15869            let autoscroll = self
15870                .selections
15871                .all::<Point>(cx)
15872                .iter()
15873                .any(|selection| crease.range().overlaps(&selection.range()));
15874
15875            self.fold_creases(vec![crease], autoscroll, window, cx);
15876        }
15877    }
15878
15879    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15880        if self.is_singleton(cx) {
15881            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15882            let buffer = &display_map.buffer_snapshot;
15883            let selections = self.selections.all::<Point>(cx);
15884            let ranges = selections
15885                .iter()
15886                .map(|s| {
15887                    let range = s.display_range(&display_map).sorted();
15888                    let mut start = range.start.to_point(&display_map);
15889                    let mut end = range.end.to_point(&display_map);
15890                    start.column = 0;
15891                    end.column = buffer.line_len(MultiBufferRow(end.row));
15892                    start..end
15893                })
15894                .collect::<Vec<_>>();
15895
15896            self.unfold_ranges(&ranges, true, true, cx);
15897        } else {
15898            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15899            let buffer_ids = self
15900                .selections
15901                .disjoint_anchor_ranges()
15902                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15903                .collect::<HashSet<_>>();
15904            for buffer_id in buffer_ids {
15905                self.unfold_buffer(buffer_id, cx);
15906            }
15907        }
15908    }
15909
15910    pub fn unfold_recursive(
15911        &mut self,
15912        _: &UnfoldRecursive,
15913        _window: &mut Window,
15914        cx: &mut Context<Self>,
15915    ) {
15916        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15917        let selections = self.selections.all::<Point>(cx);
15918        let ranges = selections
15919            .iter()
15920            .map(|s| {
15921                let mut range = s.display_range(&display_map).sorted();
15922                *range.start.column_mut() = 0;
15923                *range.end.column_mut() = display_map.line_len(range.end.row());
15924                let start = range.start.to_point(&display_map);
15925                let end = range.end.to_point(&display_map);
15926                start..end
15927            })
15928            .collect::<Vec<_>>();
15929
15930        self.unfold_ranges(&ranges, true, true, cx);
15931    }
15932
15933    pub fn unfold_at(
15934        &mut self,
15935        buffer_row: MultiBufferRow,
15936        _window: &mut Window,
15937        cx: &mut Context<Self>,
15938    ) {
15939        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15940
15941        let intersection_range = Point::new(buffer_row.0, 0)
15942            ..Point::new(
15943                buffer_row.0,
15944                display_map.buffer_snapshot.line_len(buffer_row),
15945            );
15946
15947        let autoscroll = self
15948            .selections
15949            .all::<Point>(cx)
15950            .iter()
15951            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15952
15953        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15954    }
15955
15956    pub fn unfold_all(
15957        &mut self,
15958        _: &actions::UnfoldAll,
15959        _window: &mut Window,
15960        cx: &mut Context<Self>,
15961    ) {
15962        if self.buffer.read(cx).is_singleton() {
15963            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15964            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15965        } else {
15966            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15967                editor
15968                    .update(cx, |editor, cx| {
15969                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15970                            editor.unfold_buffer(buffer_id, cx);
15971                        }
15972                    })
15973                    .ok();
15974            });
15975        }
15976    }
15977
15978    pub fn fold_selected_ranges(
15979        &mut self,
15980        _: &FoldSelectedRanges,
15981        window: &mut Window,
15982        cx: &mut Context<Self>,
15983    ) {
15984        let selections = self.selections.all_adjusted(cx);
15985        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15986        let ranges = selections
15987            .into_iter()
15988            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
15989            .collect::<Vec<_>>();
15990        self.fold_creases(ranges, true, window, cx);
15991    }
15992
15993    pub fn fold_ranges<T: ToOffset + Clone>(
15994        &mut self,
15995        ranges: Vec<Range<T>>,
15996        auto_scroll: bool,
15997        window: &mut Window,
15998        cx: &mut Context<Self>,
15999    ) {
16000        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16001        let ranges = ranges
16002            .into_iter()
16003            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16004            .collect::<Vec<_>>();
16005        self.fold_creases(ranges, auto_scroll, window, cx);
16006    }
16007
16008    pub fn fold_creases<T: ToOffset + Clone>(
16009        &mut self,
16010        creases: Vec<Crease<T>>,
16011        auto_scroll: bool,
16012        _window: &mut Window,
16013        cx: &mut Context<Self>,
16014    ) {
16015        if creases.is_empty() {
16016            return;
16017        }
16018
16019        let mut buffers_affected = HashSet::default();
16020        let multi_buffer = self.buffer().read(cx);
16021        for crease in &creases {
16022            if let Some((_, buffer, _)) =
16023                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16024            {
16025                buffers_affected.insert(buffer.read(cx).remote_id());
16026            };
16027        }
16028
16029        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16030
16031        if auto_scroll {
16032            self.request_autoscroll(Autoscroll::fit(), cx);
16033        }
16034
16035        cx.notify();
16036
16037        self.scrollbar_marker_state.dirty = true;
16038        self.folds_did_change(cx);
16039    }
16040
16041    /// Removes any folds whose ranges intersect any of the given ranges.
16042    pub fn unfold_ranges<T: ToOffset + Clone>(
16043        &mut self,
16044        ranges: &[Range<T>],
16045        inclusive: bool,
16046        auto_scroll: bool,
16047        cx: &mut Context<Self>,
16048    ) {
16049        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16050            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16051        });
16052        self.folds_did_change(cx);
16053    }
16054
16055    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16056        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16057            return;
16058        }
16059        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16060        self.display_map.update(cx, |display_map, cx| {
16061            display_map.fold_buffers([buffer_id], cx)
16062        });
16063        cx.emit(EditorEvent::BufferFoldToggled {
16064            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16065            folded: true,
16066        });
16067        cx.notify();
16068    }
16069
16070    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16071        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16072            return;
16073        }
16074        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16075        self.display_map.update(cx, |display_map, cx| {
16076            display_map.unfold_buffers([buffer_id], cx);
16077        });
16078        cx.emit(EditorEvent::BufferFoldToggled {
16079            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16080            folded: false,
16081        });
16082        cx.notify();
16083    }
16084
16085    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16086        self.display_map.read(cx).is_buffer_folded(buffer)
16087    }
16088
16089    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16090        self.display_map.read(cx).folded_buffers()
16091    }
16092
16093    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16094        self.display_map.update(cx, |display_map, cx| {
16095            display_map.disable_header_for_buffer(buffer_id, cx);
16096        });
16097        cx.notify();
16098    }
16099
16100    /// Removes any folds with the given ranges.
16101    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16102        &mut self,
16103        ranges: &[Range<T>],
16104        type_id: TypeId,
16105        auto_scroll: bool,
16106        cx: &mut Context<Self>,
16107    ) {
16108        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16109            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16110        });
16111        self.folds_did_change(cx);
16112    }
16113
16114    fn remove_folds_with<T: ToOffset + Clone>(
16115        &mut self,
16116        ranges: &[Range<T>],
16117        auto_scroll: bool,
16118        cx: &mut Context<Self>,
16119        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16120    ) {
16121        if ranges.is_empty() {
16122            return;
16123        }
16124
16125        let mut buffers_affected = HashSet::default();
16126        let multi_buffer = self.buffer().read(cx);
16127        for range in ranges {
16128            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16129                buffers_affected.insert(buffer.read(cx).remote_id());
16130            };
16131        }
16132
16133        self.display_map.update(cx, update);
16134
16135        if auto_scroll {
16136            self.request_autoscroll(Autoscroll::fit(), cx);
16137        }
16138
16139        cx.notify();
16140        self.scrollbar_marker_state.dirty = true;
16141        self.active_indent_guides_state.dirty = true;
16142    }
16143
16144    pub fn update_fold_widths(
16145        &mut self,
16146        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16147        cx: &mut Context<Self>,
16148    ) -> bool {
16149        self.display_map
16150            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16151    }
16152
16153    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16154        self.display_map.read(cx).fold_placeholder.clone()
16155    }
16156
16157    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16158        self.buffer.update(cx, |buffer, cx| {
16159            buffer.set_all_diff_hunks_expanded(cx);
16160        });
16161    }
16162
16163    pub fn expand_all_diff_hunks(
16164        &mut self,
16165        _: &ExpandAllDiffHunks,
16166        _window: &mut Window,
16167        cx: &mut Context<Self>,
16168    ) {
16169        self.buffer.update(cx, |buffer, cx| {
16170            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16171        });
16172    }
16173
16174    pub fn toggle_selected_diff_hunks(
16175        &mut self,
16176        _: &ToggleSelectedDiffHunks,
16177        _window: &mut Window,
16178        cx: &mut Context<Self>,
16179    ) {
16180        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16181        self.toggle_diff_hunks_in_ranges(ranges, cx);
16182    }
16183
16184    pub fn diff_hunks_in_ranges<'a>(
16185        &'a self,
16186        ranges: &'a [Range<Anchor>],
16187        buffer: &'a MultiBufferSnapshot,
16188    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16189        ranges.iter().flat_map(move |range| {
16190            let end_excerpt_id = range.end.excerpt_id;
16191            let range = range.to_point(buffer);
16192            let mut peek_end = range.end;
16193            if range.end.row < buffer.max_row().0 {
16194                peek_end = Point::new(range.end.row + 1, 0);
16195            }
16196            buffer
16197                .diff_hunks_in_range(range.start..peek_end)
16198                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16199        })
16200    }
16201
16202    pub fn has_stageable_diff_hunks_in_ranges(
16203        &self,
16204        ranges: &[Range<Anchor>],
16205        snapshot: &MultiBufferSnapshot,
16206    ) -> bool {
16207        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16208        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16209    }
16210
16211    pub fn toggle_staged_selected_diff_hunks(
16212        &mut self,
16213        _: &::git::ToggleStaged,
16214        _: &mut Window,
16215        cx: &mut Context<Self>,
16216    ) {
16217        let snapshot = self.buffer.read(cx).snapshot(cx);
16218        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16219        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16220        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16221    }
16222
16223    pub fn set_render_diff_hunk_controls(
16224        &mut self,
16225        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16226        cx: &mut Context<Self>,
16227    ) {
16228        self.render_diff_hunk_controls = render_diff_hunk_controls;
16229        cx.notify();
16230    }
16231
16232    pub fn stage_and_next(
16233        &mut self,
16234        _: &::git::StageAndNext,
16235        window: &mut Window,
16236        cx: &mut Context<Self>,
16237    ) {
16238        self.do_stage_or_unstage_and_next(true, window, cx);
16239    }
16240
16241    pub fn unstage_and_next(
16242        &mut self,
16243        _: &::git::UnstageAndNext,
16244        window: &mut Window,
16245        cx: &mut Context<Self>,
16246    ) {
16247        self.do_stage_or_unstage_and_next(false, window, cx);
16248    }
16249
16250    pub fn stage_or_unstage_diff_hunks(
16251        &mut self,
16252        stage: bool,
16253        ranges: Vec<Range<Anchor>>,
16254        cx: &mut Context<Self>,
16255    ) {
16256        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16257        cx.spawn(async move |this, cx| {
16258            task.await?;
16259            this.update(cx, |this, cx| {
16260                let snapshot = this.buffer.read(cx).snapshot(cx);
16261                let chunk_by = this
16262                    .diff_hunks_in_ranges(&ranges, &snapshot)
16263                    .chunk_by(|hunk| hunk.buffer_id);
16264                for (buffer_id, hunks) in &chunk_by {
16265                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16266                }
16267            })
16268        })
16269        .detach_and_log_err(cx);
16270    }
16271
16272    fn save_buffers_for_ranges_if_needed(
16273        &mut self,
16274        ranges: &[Range<Anchor>],
16275        cx: &mut Context<Editor>,
16276    ) -> Task<Result<()>> {
16277        let multibuffer = self.buffer.read(cx);
16278        let snapshot = multibuffer.read(cx);
16279        let buffer_ids: HashSet<_> = ranges
16280            .iter()
16281            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16282            .collect();
16283        drop(snapshot);
16284
16285        let mut buffers = HashSet::default();
16286        for buffer_id in buffer_ids {
16287            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16288                let buffer = buffer_entity.read(cx);
16289                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16290                {
16291                    buffers.insert(buffer_entity);
16292                }
16293            }
16294        }
16295
16296        if let Some(project) = &self.project {
16297            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16298        } else {
16299            Task::ready(Ok(()))
16300        }
16301    }
16302
16303    fn do_stage_or_unstage_and_next(
16304        &mut self,
16305        stage: bool,
16306        window: &mut Window,
16307        cx: &mut Context<Self>,
16308    ) {
16309        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16310
16311        if ranges.iter().any(|range| range.start != range.end) {
16312            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16313            return;
16314        }
16315
16316        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16317        let snapshot = self.snapshot(window, cx);
16318        let position = self.selections.newest::<Point>(cx).head();
16319        let mut row = snapshot
16320            .buffer_snapshot
16321            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16322            .find(|hunk| hunk.row_range.start.0 > position.row)
16323            .map(|hunk| hunk.row_range.start);
16324
16325        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16326        // Outside of the project diff editor, wrap around to the beginning.
16327        if !all_diff_hunks_expanded {
16328            row = row.or_else(|| {
16329                snapshot
16330                    .buffer_snapshot
16331                    .diff_hunks_in_range(Point::zero()..position)
16332                    .find(|hunk| hunk.row_range.end.0 < position.row)
16333                    .map(|hunk| hunk.row_range.start)
16334            });
16335        }
16336
16337        if let Some(row) = row {
16338            let destination = Point::new(row.0, 0);
16339            let autoscroll = Autoscroll::center();
16340
16341            self.unfold_ranges(&[destination..destination], false, false, cx);
16342            self.change_selections(Some(autoscroll), window, cx, |s| {
16343                s.select_ranges([destination..destination]);
16344            });
16345        }
16346    }
16347
16348    fn do_stage_or_unstage(
16349        &self,
16350        stage: bool,
16351        buffer_id: BufferId,
16352        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16353        cx: &mut App,
16354    ) -> Option<()> {
16355        let project = self.project.as_ref()?;
16356        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16357        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16358        let buffer_snapshot = buffer.read(cx).snapshot();
16359        let file_exists = buffer_snapshot
16360            .file()
16361            .is_some_and(|file| file.disk_state().exists());
16362        diff.update(cx, |diff, cx| {
16363            diff.stage_or_unstage_hunks(
16364                stage,
16365                &hunks
16366                    .map(|hunk| buffer_diff::DiffHunk {
16367                        buffer_range: hunk.buffer_range,
16368                        diff_base_byte_range: hunk.diff_base_byte_range,
16369                        secondary_status: hunk.secondary_status,
16370                        range: Point::zero()..Point::zero(), // unused
16371                    })
16372                    .collect::<Vec<_>>(),
16373                &buffer_snapshot,
16374                file_exists,
16375                cx,
16376            )
16377        });
16378        None
16379    }
16380
16381    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16382        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16383        self.buffer
16384            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16385    }
16386
16387    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16388        self.buffer.update(cx, |buffer, cx| {
16389            let ranges = vec![Anchor::min()..Anchor::max()];
16390            if !buffer.all_diff_hunks_expanded()
16391                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16392            {
16393                buffer.collapse_diff_hunks(ranges, cx);
16394                true
16395            } else {
16396                false
16397            }
16398        })
16399    }
16400
16401    fn toggle_diff_hunks_in_ranges(
16402        &mut self,
16403        ranges: Vec<Range<Anchor>>,
16404        cx: &mut Context<Editor>,
16405    ) {
16406        self.buffer.update(cx, |buffer, cx| {
16407            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16408            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16409        })
16410    }
16411
16412    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16413        self.buffer.update(cx, |buffer, cx| {
16414            let snapshot = buffer.snapshot(cx);
16415            let excerpt_id = range.end.excerpt_id;
16416            let point_range = range.to_point(&snapshot);
16417            let expand = !buffer.single_hunk_is_expanded(range, cx);
16418            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16419        })
16420    }
16421
16422    pub(crate) fn apply_all_diff_hunks(
16423        &mut self,
16424        _: &ApplyAllDiffHunks,
16425        window: &mut Window,
16426        cx: &mut Context<Self>,
16427    ) {
16428        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16429
16430        let buffers = self.buffer.read(cx).all_buffers();
16431        for branch_buffer in buffers {
16432            branch_buffer.update(cx, |branch_buffer, cx| {
16433                branch_buffer.merge_into_base(Vec::new(), cx);
16434            });
16435        }
16436
16437        if let Some(project) = self.project.clone() {
16438            self.save(true, project, window, cx).detach_and_log_err(cx);
16439        }
16440    }
16441
16442    pub(crate) fn apply_selected_diff_hunks(
16443        &mut self,
16444        _: &ApplyDiffHunk,
16445        window: &mut Window,
16446        cx: &mut Context<Self>,
16447    ) {
16448        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16449        let snapshot = self.snapshot(window, cx);
16450        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16451        let mut ranges_by_buffer = HashMap::default();
16452        self.transact(window, cx, |editor, _window, cx| {
16453            for hunk in hunks {
16454                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16455                    ranges_by_buffer
16456                        .entry(buffer.clone())
16457                        .or_insert_with(Vec::new)
16458                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16459                }
16460            }
16461
16462            for (buffer, ranges) in ranges_by_buffer {
16463                buffer.update(cx, |buffer, cx| {
16464                    buffer.merge_into_base(ranges, cx);
16465                });
16466            }
16467        });
16468
16469        if let Some(project) = self.project.clone() {
16470            self.save(true, project, window, cx).detach_and_log_err(cx);
16471        }
16472    }
16473
16474    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16475        if hovered != self.gutter_hovered {
16476            self.gutter_hovered = hovered;
16477            cx.notify();
16478        }
16479    }
16480
16481    pub fn insert_blocks(
16482        &mut self,
16483        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16484        autoscroll: Option<Autoscroll>,
16485        cx: &mut Context<Self>,
16486    ) -> Vec<CustomBlockId> {
16487        let blocks = self
16488            .display_map
16489            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16490        if let Some(autoscroll) = autoscroll {
16491            self.request_autoscroll(autoscroll, cx);
16492        }
16493        cx.notify();
16494        blocks
16495    }
16496
16497    pub fn resize_blocks(
16498        &mut self,
16499        heights: HashMap<CustomBlockId, u32>,
16500        autoscroll: Option<Autoscroll>,
16501        cx: &mut Context<Self>,
16502    ) {
16503        self.display_map
16504            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16505        if let Some(autoscroll) = autoscroll {
16506            self.request_autoscroll(autoscroll, cx);
16507        }
16508        cx.notify();
16509    }
16510
16511    pub fn replace_blocks(
16512        &mut self,
16513        renderers: HashMap<CustomBlockId, RenderBlock>,
16514        autoscroll: Option<Autoscroll>,
16515        cx: &mut Context<Self>,
16516    ) {
16517        self.display_map
16518            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16519        if let Some(autoscroll) = autoscroll {
16520            self.request_autoscroll(autoscroll, cx);
16521        }
16522        cx.notify();
16523    }
16524
16525    pub fn remove_blocks(
16526        &mut self,
16527        block_ids: HashSet<CustomBlockId>,
16528        autoscroll: Option<Autoscroll>,
16529        cx: &mut Context<Self>,
16530    ) {
16531        self.display_map.update(cx, |display_map, cx| {
16532            display_map.remove_blocks(block_ids, cx)
16533        });
16534        if let Some(autoscroll) = autoscroll {
16535            self.request_autoscroll(autoscroll, cx);
16536        }
16537        cx.notify();
16538    }
16539
16540    pub fn row_for_block(
16541        &self,
16542        block_id: CustomBlockId,
16543        cx: &mut Context<Self>,
16544    ) -> Option<DisplayRow> {
16545        self.display_map
16546            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16547    }
16548
16549    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16550        self.focused_block = Some(focused_block);
16551    }
16552
16553    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16554        self.focused_block.take()
16555    }
16556
16557    pub fn insert_creases(
16558        &mut self,
16559        creases: impl IntoIterator<Item = Crease<Anchor>>,
16560        cx: &mut Context<Self>,
16561    ) -> Vec<CreaseId> {
16562        self.display_map
16563            .update(cx, |map, cx| map.insert_creases(creases, cx))
16564    }
16565
16566    pub fn remove_creases(
16567        &mut self,
16568        ids: impl IntoIterator<Item = CreaseId>,
16569        cx: &mut Context<Self>,
16570    ) -> Vec<(CreaseId, Range<Anchor>)> {
16571        self.display_map
16572            .update(cx, |map, cx| map.remove_creases(ids, cx))
16573    }
16574
16575    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16576        self.display_map
16577            .update(cx, |map, cx| map.snapshot(cx))
16578            .longest_row()
16579    }
16580
16581    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16582        self.display_map
16583            .update(cx, |map, cx| map.snapshot(cx))
16584            .max_point()
16585    }
16586
16587    pub fn text(&self, cx: &App) -> String {
16588        self.buffer.read(cx).read(cx).text()
16589    }
16590
16591    pub fn is_empty(&self, cx: &App) -> bool {
16592        self.buffer.read(cx).read(cx).is_empty()
16593    }
16594
16595    pub fn text_option(&self, cx: &App) -> Option<String> {
16596        let text = self.text(cx);
16597        let text = text.trim();
16598
16599        if text.is_empty() {
16600            return None;
16601        }
16602
16603        Some(text.to_string())
16604    }
16605
16606    pub fn set_text(
16607        &mut self,
16608        text: impl Into<Arc<str>>,
16609        window: &mut Window,
16610        cx: &mut Context<Self>,
16611    ) {
16612        self.transact(window, cx, |this, _, cx| {
16613            this.buffer
16614                .read(cx)
16615                .as_singleton()
16616                .expect("you can only call set_text on editors for singleton buffers")
16617                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16618        });
16619    }
16620
16621    pub fn display_text(&self, cx: &mut App) -> String {
16622        self.display_map
16623            .update(cx, |map, cx| map.snapshot(cx))
16624            .text()
16625    }
16626
16627    fn create_minimap(
16628        &self,
16629        minimap_settings: MinimapSettings,
16630        window: &mut Window,
16631        cx: &mut Context<Self>,
16632    ) -> Option<Entity<Self>> {
16633        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16634            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16635    }
16636
16637    fn initialize_new_minimap(
16638        &self,
16639        minimap_settings: MinimapSettings,
16640        window: &mut Window,
16641        cx: &mut Context<Self>,
16642    ) -> Entity<Self> {
16643        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16644
16645        let mut minimap = Editor::new_internal(
16646            EditorMode::Minimap {
16647                parent: cx.weak_entity(),
16648            },
16649            self.buffer.clone(),
16650            self.project.clone(),
16651            Some(self.display_map.clone()),
16652            window,
16653            cx,
16654        );
16655        minimap.scroll_manager.clone_state(&self.scroll_manager);
16656        minimap.set_text_style_refinement(TextStyleRefinement {
16657            font_size: Some(MINIMAP_FONT_SIZE),
16658            font_weight: Some(MINIMAP_FONT_WEIGHT),
16659            ..Default::default()
16660        });
16661        minimap.update_minimap_configuration(minimap_settings, cx);
16662        cx.new(|_| minimap)
16663    }
16664
16665    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16666        let current_line_highlight = minimap_settings
16667            .current_line_highlight
16668            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16669        self.set_current_line_highlight(Some(current_line_highlight));
16670    }
16671
16672    pub fn minimap(&self) -> Option<&Entity<Self>> {
16673        self.minimap
16674            .as_ref()
16675            .filter(|_| self.minimap_visibility.visible())
16676    }
16677
16678    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16679        let mut wrap_guides = smallvec::smallvec![];
16680
16681        if self.show_wrap_guides == Some(false) {
16682            return wrap_guides;
16683        }
16684
16685        let settings = self.buffer.read(cx).language_settings(cx);
16686        if settings.show_wrap_guides {
16687            match self.soft_wrap_mode(cx) {
16688                SoftWrap::Column(soft_wrap) => {
16689                    wrap_guides.push((soft_wrap as usize, true));
16690                }
16691                SoftWrap::Bounded(soft_wrap) => {
16692                    wrap_guides.push((soft_wrap as usize, true));
16693                }
16694                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16695            }
16696            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16697        }
16698
16699        wrap_guides
16700    }
16701
16702    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16703        let settings = self.buffer.read(cx).language_settings(cx);
16704        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16705        match mode {
16706            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16707                SoftWrap::None
16708            }
16709            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16710            language_settings::SoftWrap::PreferredLineLength => {
16711                SoftWrap::Column(settings.preferred_line_length)
16712            }
16713            language_settings::SoftWrap::Bounded => {
16714                SoftWrap::Bounded(settings.preferred_line_length)
16715            }
16716        }
16717    }
16718
16719    pub fn set_soft_wrap_mode(
16720        &mut self,
16721        mode: language_settings::SoftWrap,
16722
16723        cx: &mut Context<Self>,
16724    ) {
16725        self.soft_wrap_mode_override = Some(mode);
16726        cx.notify();
16727    }
16728
16729    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16730        self.hard_wrap = hard_wrap;
16731        cx.notify();
16732    }
16733
16734    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16735        self.text_style_refinement = Some(style);
16736    }
16737
16738    /// called by the Element so we know what style we were most recently rendered with.
16739    pub(crate) fn set_style(
16740        &mut self,
16741        style: EditorStyle,
16742        window: &mut Window,
16743        cx: &mut Context<Self>,
16744    ) {
16745        // We intentionally do not inform the display map about the minimap style
16746        // so that wrapping is not recalculated and stays consistent for the editor
16747        // and its linked minimap.
16748        if !self.mode.is_minimap() {
16749            let rem_size = window.rem_size();
16750            self.display_map.update(cx, |map, cx| {
16751                map.set_font(
16752                    style.text.font(),
16753                    style.text.font_size.to_pixels(rem_size),
16754                    cx,
16755                )
16756            });
16757        }
16758        self.style = Some(style);
16759    }
16760
16761    pub fn style(&self) -> Option<&EditorStyle> {
16762        self.style.as_ref()
16763    }
16764
16765    // Called by the element. This method is not designed to be called outside of the editor
16766    // element's layout code because it does not notify when rewrapping is computed synchronously.
16767    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16768        self.display_map
16769            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16770    }
16771
16772    pub fn set_soft_wrap(&mut self) {
16773        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16774    }
16775
16776    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16777        if self.soft_wrap_mode_override.is_some() {
16778            self.soft_wrap_mode_override.take();
16779        } else {
16780            let soft_wrap = match self.soft_wrap_mode(cx) {
16781                SoftWrap::GitDiff => return,
16782                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16783                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16784                    language_settings::SoftWrap::None
16785                }
16786            };
16787            self.soft_wrap_mode_override = Some(soft_wrap);
16788        }
16789        cx.notify();
16790    }
16791
16792    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16793        let Some(workspace) = self.workspace() else {
16794            return;
16795        };
16796        let fs = workspace.read(cx).app_state().fs.clone();
16797        let current_show = TabBarSettings::get_global(cx).show;
16798        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16799            setting.show = Some(!current_show);
16800        });
16801    }
16802
16803    pub fn toggle_indent_guides(
16804        &mut self,
16805        _: &ToggleIndentGuides,
16806        _: &mut Window,
16807        cx: &mut Context<Self>,
16808    ) {
16809        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16810            self.buffer
16811                .read(cx)
16812                .language_settings(cx)
16813                .indent_guides
16814                .enabled
16815        });
16816        self.show_indent_guides = Some(!currently_enabled);
16817        cx.notify();
16818    }
16819
16820    fn should_show_indent_guides(&self) -> Option<bool> {
16821        self.show_indent_guides
16822    }
16823
16824    pub fn toggle_line_numbers(
16825        &mut self,
16826        _: &ToggleLineNumbers,
16827        _: &mut Window,
16828        cx: &mut Context<Self>,
16829    ) {
16830        let mut editor_settings = EditorSettings::get_global(cx).clone();
16831        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16832        EditorSettings::override_global(editor_settings, cx);
16833    }
16834
16835    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16836        if let Some(show_line_numbers) = self.show_line_numbers {
16837            return show_line_numbers;
16838        }
16839        EditorSettings::get_global(cx).gutter.line_numbers
16840    }
16841
16842    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16843        self.use_relative_line_numbers
16844            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16845    }
16846
16847    pub fn toggle_relative_line_numbers(
16848        &mut self,
16849        _: &ToggleRelativeLineNumbers,
16850        _: &mut Window,
16851        cx: &mut Context<Self>,
16852    ) {
16853        let is_relative = self.should_use_relative_line_numbers(cx);
16854        self.set_relative_line_number(Some(!is_relative), cx)
16855    }
16856
16857    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16858        self.use_relative_line_numbers = is_relative;
16859        cx.notify();
16860    }
16861
16862    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16863        self.show_gutter = show_gutter;
16864        cx.notify();
16865    }
16866
16867    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16868        self.show_scrollbars = show_scrollbars;
16869        cx.notify();
16870    }
16871
16872    pub fn set_minimap_visibility(
16873        &mut self,
16874        minimap_visibility: MinimapVisibility,
16875        window: &mut Window,
16876        cx: &mut Context<Self>,
16877    ) {
16878        if self.minimap_visibility != minimap_visibility {
16879            if minimap_visibility.visible() && self.minimap.is_none() {
16880                let minimap_settings = EditorSettings::get_global(cx).minimap;
16881                self.minimap =
16882                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16883            }
16884            self.minimap_visibility = minimap_visibility;
16885            cx.notify();
16886        }
16887    }
16888
16889    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16890        self.set_show_scrollbars(false, cx);
16891        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16892    }
16893
16894    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16895        self.show_line_numbers = Some(show_line_numbers);
16896        cx.notify();
16897    }
16898
16899    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16900        self.disable_expand_excerpt_buttons = true;
16901        cx.notify();
16902    }
16903
16904    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16905        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16906        cx.notify();
16907    }
16908
16909    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16910        self.show_code_actions = Some(show_code_actions);
16911        cx.notify();
16912    }
16913
16914    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16915        self.show_runnables = Some(show_runnables);
16916        cx.notify();
16917    }
16918
16919    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16920        self.show_breakpoints = Some(show_breakpoints);
16921        cx.notify();
16922    }
16923
16924    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16925        if self.display_map.read(cx).masked != masked {
16926            self.display_map.update(cx, |map, _| map.masked = masked);
16927        }
16928        cx.notify()
16929    }
16930
16931    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16932        self.show_wrap_guides = Some(show_wrap_guides);
16933        cx.notify();
16934    }
16935
16936    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16937        self.show_indent_guides = Some(show_indent_guides);
16938        cx.notify();
16939    }
16940
16941    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16942        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16943            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16944                if let Some(dir) = file.abs_path(cx).parent() {
16945                    return Some(dir.to_owned());
16946                }
16947            }
16948
16949            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16950                return Some(project_path.path.to_path_buf());
16951            }
16952        }
16953
16954        None
16955    }
16956
16957    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16958        self.active_excerpt(cx)?
16959            .1
16960            .read(cx)
16961            .file()
16962            .and_then(|f| f.as_local())
16963    }
16964
16965    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16966        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16967            let buffer = buffer.read(cx);
16968            if let Some(project_path) = buffer.project_path(cx) {
16969                let project = self.project.as_ref()?.read(cx);
16970                project.absolute_path(&project_path, cx)
16971            } else {
16972                buffer
16973                    .file()
16974                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16975            }
16976        })
16977    }
16978
16979    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16980        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16981            let project_path = buffer.read(cx).project_path(cx)?;
16982            let project = self.project.as_ref()?.read(cx);
16983            let entry = project.entry_for_path(&project_path, cx)?;
16984            let path = entry.path.to_path_buf();
16985            Some(path)
16986        })
16987    }
16988
16989    pub fn reveal_in_finder(
16990        &mut self,
16991        _: &RevealInFileManager,
16992        _window: &mut Window,
16993        cx: &mut Context<Self>,
16994    ) {
16995        if let Some(target) = self.target_file(cx) {
16996            cx.reveal_path(&target.abs_path(cx));
16997        }
16998    }
16999
17000    pub fn copy_path(
17001        &mut self,
17002        _: &zed_actions::workspace::CopyPath,
17003        _window: &mut Window,
17004        cx: &mut Context<Self>,
17005    ) {
17006        if let Some(path) = self.target_file_abs_path(cx) {
17007            if let Some(path) = path.to_str() {
17008                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17009            }
17010        }
17011    }
17012
17013    pub fn copy_relative_path(
17014        &mut self,
17015        _: &zed_actions::workspace::CopyRelativePath,
17016        _window: &mut Window,
17017        cx: &mut Context<Self>,
17018    ) {
17019        if let Some(path) = self.target_file_path(cx) {
17020            if let Some(path) = path.to_str() {
17021                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17022            }
17023        }
17024    }
17025
17026    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17027        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17028            buffer.read(cx).project_path(cx)
17029        } else {
17030            None
17031        }
17032    }
17033
17034    // Returns true if the editor handled a go-to-line request
17035    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17036        maybe!({
17037            let breakpoint_store = self.breakpoint_store.as_ref()?;
17038
17039            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17040            else {
17041                self.clear_row_highlights::<ActiveDebugLine>();
17042                return None;
17043            };
17044
17045            let position = active_stack_frame.position;
17046            let buffer_id = position.buffer_id?;
17047            let snapshot = self
17048                .project
17049                .as_ref()?
17050                .read(cx)
17051                .buffer_for_id(buffer_id, cx)?
17052                .read(cx)
17053                .snapshot();
17054
17055            let mut handled = false;
17056            for (id, ExcerptRange { context, .. }) in
17057                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17058            {
17059                if context.start.cmp(&position, &snapshot).is_ge()
17060                    || context.end.cmp(&position, &snapshot).is_lt()
17061                {
17062                    continue;
17063                }
17064                let snapshot = self.buffer.read(cx).snapshot(cx);
17065                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17066
17067                handled = true;
17068                self.clear_row_highlights::<ActiveDebugLine>();
17069
17070                self.go_to_line::<ActiveDebugLine>(
17071                    multibuffer_anchor,
17072                    Some(cx.theme().colors().editor_debugger_active_line_background),
17073                    window,
17074                    cx,
17075                );
17076
17077                cx.notify();
17078            }
17079
17080            handled.then_some(())
17081        })
17082        .is_some()
17083    }
17084
17085    pub fn copy_file_name_without_extension(
17086        &mut self,
17087        _: &CopyFileNameWithoutExtension,
17088        _: &mut Window,
17089        cx: &mut Context<Self>,
17090    ) {
17091        if let Some(file) = self.target_file(cx) {
17092            if let Some(file_stem) = file.path().file_stem() {
17093                if let Some(name) = file_stem.to_str() {
17094                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17095                }
17096            }
17097        }
17098    }
17099
17100    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17101        if let Some(file) = self.target_file(cx) {
17102            if let Some(file_name) = file.path().file_name() {
17103                if let Some(name) = file_name.to_str() {
17104                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17105                }
17106            }
17107        }
17108    }
17109
17110    pub fn toggle_git_blame(
17111        &mut self,
17112        _: &::git::Blame,
17113        window: &mut Window,
17114        cx: &mut Context<Self>,
17115    ) {
17116        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17117
17118        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17119            self.start_git_blame(true, window, cx);
17120        }
17121
17122        cx.notify();
17123    }
17124
17125    pub fn toggle_git_blame_inline(
17126        &mut self,
17127        _: &ToggleGitBlameInline,
17128        window: &mut Window,
17129        cx: &mut Context<Self>,
17130    ) {
17131        self.toggle_git_blame_inline_internal(true, window, cx);
17132        cx.notify();
17133    }
17134
17135    pub fn open_git_blame_commit(
17136        &mut self,
17137        _: &OpenGitBlameCommit,
17138        window: &mut Window,
17139        cx: &mut Context<Self>,
17140    ) {
17141        self.open_git_blame_commit_internal(window, cx);
17142    }
17143
17144    fn open_git_blame_commit_internal(
17145        &mut self,
17146        window: &mut Window,
17147        cx: &mut Context<Self>,
17148    ) -> Option<()> {
17149        let blame = self.blame.as_ref()?;
17150        let snapshot = self.snapshot(window, cx);
17151        let cursor = self.selections.newest::<Point>(cx).head();
17152        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17153        let blame_entry = blame
17154            .update(cx, |blame, cx| {
17155                blame
17156                    .blame_for_rows(
17157                        &[RowInfo {
17158                            buffer_id: Some(buffer.remote_id()),
17159                            buffer_row: Some(point.row),
17160                            ..Default::default()
17161                        }],
17162                        cx,
17163                    )
17164                    .next()
17165            })
17166            .flatten()?;
17167        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17168        let repo = blame.read(cx).repository(cx)?;
17169        let workspace = self.workspace()?.downgrade();
17170        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17171        None
17172    }
17173
17174    pub fn git_blame_inline_enabled(&self) -> bool {
17175        self.git_blame_inline_enabled
17176    }
17177
17178    pub fn toggle_selection_menu(
17179        &mut self,
17180        _: &ToggleSelectionMenu,
17181        _: &mut Window,
17182        cx: &mut Context<Self>,
17183    ) {
17184        self.show_selection_menu = self
17185            .show_selection_menu
17186            .map(|show_selections_menu| !show_selections_menu)
17187            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17188
17189        cx.notify();
17190    }
17191
17192    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17193        self.show_selection_menu
17194            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17195    }
17196
17197    fn start_git_blame(
17198        &mut self,
17199        user_triggered: bool,
17200        window: &mut Window,
17201        cx: &mut Context<Self>,
17202    ) {
17203        if let Some(project) = self.project.as_ref() {
17204            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17205                return;
17206            };
17207
17208            if buffer.read(cx).file().is_none() {
17209                return;
17210            }
17211
17212            let focused = self.focus_handle(cx).contains_focused(window, cx);
17213
17214            let project = project.clone();
17215            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17216            self.blame_subscription =
17217                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17218            self.blame = Some(blame);
17219        }
17220    }
17221
17222    fn toggle_git_blame_inline_internal(
17223        &mut self,
17224        user_triggered: bool,
17225        window: &mut Window,
17226        cx: &mut Context<Self>,
17227    ) {
17228        if self.git_blame_inline_enabled {
17229            self.git_blame_inline_enabled = false;
17230            self.show_git_blame_inline = false;
17231            self.show_git_blame_inline_delay_task.take();
17232        } else {
17233            self.git_blame_inline_enabled = true;
17234            self.start_git_blame_inline(user_triggered, window, cx);
17235        }
17236
17237        cx.notify();
17238    }
17239
17240    fn start_git_blame_inline(
17241        &mut self,
17242        user_triggered: bool,
17243        window: &mut Window,
17244        cx: &mut Context<Self>,
17245    ) {
17246        self.start_git_blame(user_triggered, window, cx);
17247
17248        if ProjectSettings::get_global(cx)
17249            .git
17250            .inline_blame_delay()
17251            .is_some()
17252        {
17253            self.start_inline_blame_timer(window, cx);
17254        } else {
17255            self.show_git_blame_inline = true
17256        }
17257    }
17258
17259    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17260        self.blame.as_ref()
17261    }
17262
17263    pub fn show_git_blame_gutter(&self) -> bool {
17264        self.show_git_blame_gutter
17265    }
17266
17267    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17268        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17269    }
17270
17271    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17272        self.show_git_blame_inline
17273            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17274            && !self.newest_selection_head_on_empty_line(cx)
17275            && self.has_blame_entries(cx)
17276    }
17277
17278    fn has_blame_entries(&self, cx: &App) -> bool {
17279        self.blame()
17280            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17281    }
17282
17283    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17284        let cursor_anchor = self.selections.newest_anchor().head();
17285
17286        let snapshot = self.buffer.read(cx).snapshot(cx);
17287        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17288
17289        snapshot.line_len(buffer_row) == 0
17290    }
17291
17292    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17293        let buffer_and_selection = maybe!({
17294            let selection = self.selections.newest::<Point>(cx);
17295            let selection_range = selection.range();
17296
17297            let multi_buffer = self.buffer().read(cx);
17298            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17299            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17300
17301            let (buffer, range, _) = if selection.reversed {
17302                buffer_ranges.first()
17303            } else {
17304                buffer_ranges.last()
17305            }?;
17306
17307            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17308                ..text::ToPoint::to_point(&range.end, &buffer).row;
17309            Some((
17310                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17311                selection,
17312            ))
17313        });
17314
17315        let Some((buffer, selection)) = buffer_and_selection else {
17316            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17317        };
17318
17319        let Some(project) = self.project.as_ref() else {
17320            return Task::ready(Err(anyhow!("editor does not have project")));
17321        };
17322
17323        project.update(cx, |project, cx| {
17324            project.get_permalink_to_line(&buffer, selection, cx)
17325        })
17326    }
17327
17328    pub fn copy_permalink_to_line(
17329        &mut self,
17330        _: &CopyPermalinkToLine,
17331        window: &mut Window,
17332        cx: &mut Context<Self>,
17333    ) {
17334        let permalink_task = self.get_permalink_to_line(cx);
17335        let workspace = self.workspace();
17336
17337        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17338            Ok(permalink) => {
17339                cx.update(|_, cx| {
17340                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17341                })
17342                .ok();
17343            }
17344            Err(err) => {
17345                let message = format!("Failed to copy permalink: {err}");
17346
17347                anyhow::Result::<()>::Err(err).log_err();
17348
17349                if let Some(workspace) = workspace {
17350                    workspace
17351                        .update_in(cx, |workspace, _, cx| {
17352                            struct CopyPermalinkToLine;
17353
17354                            workspace.show_toast(
17355                                Toast::new(
17356                                    NotificationId::unique::<CopyPermalinkToLine>(),
17357                                    message,
17358                                ),
17359                                cx,
17360                            )
17361                        })
17362                        .ok();
17363                }
17364            }
17365        })
17366        .detach();
17367    }
17368
17369    pub fn copy_file_location(
17370        &mut self,
17371        _: &CopyFileLocation,
17372        _: &mut Window,
17373        cx: &mut Context<Self>,
17374    ) {
17375        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17376        if let Some(file) = self.target_file(cx) {
17377            if let Some(path) = file.path().to_str() {
17378                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17379            }
17380        }
17381    }
17382
17383    pub fn open_permalink_to_line(
17384        &mut self,
17385        _: &OpenPermalinkToLine,
17386        window: &mut Window,
17387        cx: &mut Context<Self>,
17388    ) {
17389        let permalink_task = self.get_permalink_to_line(cx);
17390        let workspace = self.workspace();
17391
17392        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17393            Ok(permalink) => {
17394                cx.update(|_, cx| {
17395                    cx.open_url(permalink.as_ref());
17396                })
17397                .ok();
17398            }
17399            Err(err) => {
17400                let message = format!("Failed to open permalink: {err}");
17401
17402                anyhow::Result::<()>::Err(err).log_err();
17403
17404                if let Some(workspace) = workspace {
17405                    workspace
17406                        .update(cx, |workspace, cx| {
17407                            struct OpenPermalinkToLine;
17408
17409                            workspace.show_toast(
17410                                Toast::new(
17411                                    NotificationId::unique::<OpenPermalinkToLine>(),
17412                                    message,
17413                                ),
17414                                cx,
17415                            )
17416                        })
17417                        .ok();
17418                }
17419            }
17420        })
17421        .detach();
17422    }
17423
17424    pub fn insert_uuid_v4(
17425        &mut self,
17426        _: &InsertUuidV4,
17427        window: &mut Window,
17428        cx: &mut Context<Self>,
17429    ) {
17430        self.insert_uuid(UuidVersion::V4, window, cx);
17431    }
17432
17433    pub fn insert_uuid_v7(
17434        &mut self,
17435        _: &InsertUuidV7,
17436        window: &mut Window,
17437        cx: &mut Context<Self>,
17438    ) {
17439        self.insert_uuid(UuidVersion::V7, window, cx);
17440    }
17441
17442    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17443        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17444        self.transact(window, cx, |this, window, cx| {
17445            let edits = this
17446                .selections
17447                .all::<Point>(cx)
17448                .into_iter()
17449                .map(|selection| {
17450                    let uuid = match version {
17451                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17452                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17453                    };
17454
17455                    (selection.range(), uuid.to_string())
17456                });
17457            this.edit(edits, cx);
17458            this.refresh_inline_completion(true, false, window, cx);
17459        });
17460    }
17461
17462    pub fn open_selections_in_multibuffer(
17463        &mut self,
17464        _: &OpenSelectionsInMultibuffer,
17465        window: &mut Window,
17466        cx: &mut Context<Self>,
17467    ) {
17468        let multibuffer = self.buffer.read(cx);
17469
17470        let Some(buffer) = multibuffer.as_singleton() else {
17471            return;
17472        };
17473
17474        let Some(workspace) = self.workspace() else {
17475            return;
17476        };
17477
17478        let locations = self
17479            .selections
17480            .disjoint_anchors()
17481            .iter()
17482            .map(|range| Location {
17483                buffer: buffer.clone(),
17484                range: range.start.text_anchor..range.end.text_anchor,
17485            })
17486            .collect::<Vec<_>>();
17487
17488        let title = multibuffer.title(cx).to_string();
17489
17490        cx.spawn_in(window, async move |_, cx| {
17491            workspace.update_in(cx, |workspace, window, cx| {
17492                Self::open_locations_in_multibuffer(
17493                    workspace,
17494                    locations,
17495                    format!("Selections for '{title}'"),
17496                    false,
17497                    MultibufferSelectionMode::All,
17498                    window,
17499                    cx,
17500                );
17501            })
17502        })
17503        .detach();
17504    }
17505
17506    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17507    /// last highlight added will be used.
17508    ///
17509    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17510    pub fn highlight_rows<T: 'static>(
17511        &mut self,
17512        range: Range<Anchor>,
17513        color: Hsla,
17514        options: RowHighlightOptions,
17515        cx: &mut Context<Self>,
17516    ) {
17517        let snapshot = self.buffer().read(cx).snapshot(cx);
17518        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17519        let ix = row_highlights.binary_search_by(|highlight| {
17520            Ordering::Equal
17521                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17522                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17523        });
17524
17525        if let Err(mut ix) = ix {
17526            let index = post_inc(&mut self.highlight_order);
17527
17528            // If this range intersects with the preceding highlight, then merge it with
17529            // the preceding highlight. Otherwise insert a new highlight.
17530            let mut merged = false;
17531            if ix > 0 {
17532                let prev_highlight = &mut row_highlights[ix - 1];
17533                if prev_highlight
17534                    .range
17535                    .end
17536                    .cmp(&range.start, &snapshot)
17537                    .is_ge()
17538                {
17539                    ix -= 1;
17540                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17541                        prev_highlight.range.end = range.end;
17542                    }
17543                    merged = true;
17544                    prev_highlight.index = index;
17545                    prev_highlight.color = color;
17546                    prev_highlight.options = options;
17547                }
17548            }
17549
17550            if !merged {
17551                row_highlights.insert(
17552                    ix,
17553                    RowHighlight {
17554                        range: range.clone(),
17555                        index,
17556                        color,
17557                        options,
17558                        type_id: TypeId::of::<T>(),
17559                    },
17560                );
17561            }
17562
17563            // If any of the following highlights intersect with this one, merge them.
17564            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17565                let highlight = &row_highlights[ix];
17566                if next_highlight
17567                    .range
17568                    .start
17569                    .cmp(&highlight.range.end, &snapshot)
17570                    .is_le()
17571                {
17572                    if next_highlight
17573                        .range
17574                        .end
17575                        .cmp(&highlight.range.end, &snapshot)
17576                        .is_gt()
17577                    {
17578                        row_highlights[ix].range.end = next_highlight.range.end;
17579                    }
17580                    row_highlights.remove(ix + 1);
17581                } else {
17582                    break;
17583                }
17584            }
17585        }
17586    }
17587
17588    /// Remove any highlighted row ranges of the given type that intersect the
17589    /// given ranges.
17590    pub fn remove_highlighted_rows<T: 'static>(
17591        &mut self,
17592        ranges_to_remove: Vec<Range<Anchor>>,
17593        cx: &mut Context<Self>,
17594    ) {
17595        let snapshot = self.buffer().read(cx).snapshot(cx);
17596        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17597        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17598        row_highlights.retain(|highlight| {
17599            while let Some(range_to_remove) = ranges_to_remove.peek() {
17600                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17601                    Ordering::Less | Ordering::Equal => {
17602                        ranges_to_remove.next();
17603                    }
17604                    Ordering::Greater => {
17605                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17606                            Ordering::Less | Ordering::Equal => {
17607                                return false;
17608                            }
17609                            Ordering::Greater => break,
17610                        }
17611                    }
17612                }
17613            }
17614
17615            true
17616        })
17617    }
17618
17619    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17620    pub fn clear_row_highlights<T: 'static>(&mut self) {
17621        self.highlighted_rows.remove(&TypeId::of::<T>());
17622    }
17623
17624    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17625    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17626        self.highlighted_rows
17627            .get(&TypeId::of::<T>())
17628            .map_or(&[] as &[_], |vec| vec.as_slice())
17629            .iter()
17630            .map(|highlight| (highlight.range.clone(), highlight.color))
17631    }
17632
17633    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17634    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17635    /// Allows to ignore certain kinds of highlights.
17636    pub fn highlighted_display_rows(
17637        &self,
17638        window: &mut Window,
17639        cx: &mut App,
17640    ) -> BTreeMap<DisplayRow, LineHighlight> {
17641        let snapshot = self.snapshot(window, cx);
17642        let mut used_highlight_orders = HashMap::default();
17643        self.highlighted_rows
17644            .iter()
17645            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17646            .fold(
17647                BTreeMap::<DisplayRow, LineHighlight>::new(),
17648                |mut unique_rows, highlight| {
17649                    let start = highlight.range.start.to_display_point(&snapshot);
17650                    let end = highlight.range.end.to_display_point(&snapshot);
17651                    let start_row = start.row().0;
17652                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17653                        && end.column() == 0
17654                    {
17655                        end.row().0.saturating_sub(1)
17656                    } else {
17657                        end.row().0
17658                    };
17659                    for row in start_row..=end_row {
17660                        let used_index =
17661                            used_highlight_orders.entry(row).or_insert(highlight.index);
17662                        if highlight.index >= *used_index {
17663                            *used_index = highlight.index;
17664                            unique_rows.insert(
17665                                DisplayRow(row),
17666                                LineHighlight {
17667                                    include_gutter: highlight.options.include_gutter,
17668                                    border: None,
17669                                    background: highlight.color.into(),
17670                                    type_id: Some(highlight.type_id),
17671                                },
17672                            );
17673                        }
17674                    }
17675                    unique_rows
17676                },
17677            )
17678    }
17679
17680    pub fn highlighted_display_row_for_autoscroll(
17681        &self,
17682        snapshot: &DisplaySnapshot,
17683    ) -> Option<DisplayRow> {
17684        self.highlighted_rows
17685            .values()
17686            .flat_map(|highlighted_rows| highlighted_rows.iter())
17687            .filter_map(|highlight| {
17688                if highlight.options.autoscroll {
17689                    Some(highlight.range.start.to_display_point(snapshot).row())
17690                } else {
17691                    None
17692                }
17693            })
17694            .min()
17695    }
17696
17697    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17698        self.highlight_background::<SearchWithinRange>(
17699            ranges,
17700            |colors| colors.editor_document_highlight_read_background,
17701            cx,
17702        )
17703    }
17704
17705    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17706        self.breadcrumb_header = Some(new_header);
17707    }
17708
17709    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17710        self.clear_background_highlights::<SearchWithinRange>(cx);
17711    }
17712
17713    pub fn highlight_background<T: 'static>(
17714        &mut self,
17715        ranges: &[Range<Anchor>],
17716        color_fetcher: fn(&ThemeColors) -> Hsla,
17717        cx: &mut Context<Self>,
17718    ) {
17719        self.background_highlights
17720            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17721        self.scrollbar_marker_state.dirty = true;
17722        cx.notify();
17723    }
17724
17725    pub fn clear_background_highlights<T: 'static>(
17726        &mut self,
17727        cx: &mut Context<Self>,
17728    ) -> Option<BackgroundHighlight> {
17729        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17730        if !text_highlights.1.is_empty() {
17731            self.scrollbar_marker_state.dirty = true;
17732            cx.notify();
17733        }
17734        Some(text_highlights)
17735    }
17736
17737    pub fn highlight_gutter<T: 'static>(
17738        &mut self,
17739        ranges: &[Range<Anchor>],
17740        color_fetcher: fn(&App) -> Hsla,
17741        cx: &mut Context<Self>,
17742    ) {
17743        self.gutter_highlights
17744            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17745        cx.notify();
17746    }
17747
17748    pub fn clear_gutter_highlights<T: 'static>(
17749        &mut self,
17750        cx: &mut Context<Self>,
17751    ) -> Option<GutterHighlight> {
17752        cx.notify();
17753        self.gutter_highlights.remove(&TypeId::of::<T>())
17754    }
17755
17756    #[cfg(feature = "test-support")]
17757    pub fn all_text_background_highlights(
17758        &self,
17759        window: &mut Window,
17760        cx: &mut Context<Self>,
17761    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17762        let snapshot = self.snapshot(window, cx);
17763        let buffer = &snapshot.buffer_snapshot;
17764        let start = buffer.anchor_before(0);
17765        let end = buffer.anchor_after(buffer.len());
17766        let theme = cx.theme().colors();
17767        self.background_highlights_in_range(start..end, &snapshot, theme)
17768    }
17769
17770    #[cfg(feature = "test-support")]
17771    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17772        let snapshot = self.buffer().read(cx).snapshot(cx);
17773
17774        let highlights = self
17775            .background_highlights
17776            .get(&TypeId::of::<items::BufferSearchHighlights>());
17777
17778        if let Some((_color, ranges)) = highlights {
17779            ranges
17780                .iter()
17781                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17782                .collect_vec()
17783        } else {
17784            vec![]
17785        }
17786    }
17787
17788    fn document_highlights_for_position<'a>(
17789        &'a self,
17790        position: Anchor,
17791        buffer: &'a MultiBufferSnapshot,
17792    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17793        let read_highlights = self
17794            .background_highlights
17795            .get(&TypeId::of::<DocumentHighlightRead>())
17796            .map(|h| &h.1);
17797        let write_highlights = self
17798            .background_highlights
17799            .get(&TypeId::of::<DocumentHighlightWrite>())
17800            .map(|h| &h.1);
17801        let left_position = position.bias_left(buffer);
17802        let right_position = position.bias_right(buffer);
17803        read_highlights
17804            .into_iter()
17805            .chain(write_highlights)
17806            .flat_map(move |ranges| {
17807                let start_ix = match ranges.binary_search_by(|probe| {
17808                    let cmp = probe.end.cmp(&left_position, buffer);
17809                    if cmp.is_ge() {
17810                        Ordering::Greater
17811                    } else {
17812                        Ordering::Less
17813                    }
17814                }) {
17815                    Ok(i) | Err(i) => i,
17816                };
17817
17818                ranges[start_ix..]
17819                    .iter()
17820                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17821            })
17822    }
17823
17824    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17825        self.background_highlights
17826            .get(&TypeId::of::<T>())
17827            .map_or(false, |(_, highlights)| !highlights.is_empty())
17828    }
17829
17830    pub fn background_highlights_in_range(
17831        &self,
17832        search_range: Range<Anchor>,
17833        display_snapshot: &DisplaySnapshot,
17834        theme: &ThemeColors,
17835    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17836        let mut results = Vec::new();
17837        for (color_fetcher, ranges) in self.background_highlights.values() {
17838            let color = color_fetcher(theme);
17839            let start_ix = match ranges.binary_search_by(|probe| {
17840                let cmp = probe
17841                    .end
17842                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17843                if cmp.is_gt() {
17844                    Ordering::Greater
17845                } else {
17846                    Ordering::Less
17847                }
17848            }) {
17849                Ok(i) | Err(i) => i,
17850            };
17851            for range in &ranges[start_ix..] {
17852                if range
17853                    .start
17854                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17855                    .is_ge()
17856                {
17857                    break;
17858                }
17859
17860                let start = range.start.to_display_point(display_snapshot);
17861                let end = range.end.to_display_point(display_snapshot);
17862                results.push((start..end, color))
17863            }
17864        }
17865        results
17866    }
17867
17868    pub fn background_highlight_row_ranges<T: 'static>(
17869        &self,
17870        search_range: Range<Anchor>,
17871        display_snapshot: &DisplaySnapshot,
17872        count: usize,
17873    ) -> Vec<RangeInclusive<DisplayPoint>> {
17874        let mut results = Vec::new();
17875        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17876            return vec![];
17877        };
17878
17879        let start_ix = match ranges.binary_search_by(|probe| {
17880            let cmp = probe
17881                .end
17882                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17883            if cmp.is_gt() {
17884                Ordering::Greater
17885            } else {
17886                Ordering::Less
17887            }
17888        }) {
17889            Ok(i) | Err(i) => i,
17890        };
17891        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17892            if let (Some(start_display), Some(end_display)) = (start, end) {
17893                results.push(
17894                    start_display.to_display_point(display_snapshot)
17895                        ..=end_display.to_display_point(display_snapshot),
17896                );
17897            }
17898        };
17899        let mut start_row: Option<Point> = None;
17900        let mut end_row: Option<Point> = None;
17901        if ranges.len() > count {
17902            return Vec::new();
17903        }
17904        for range in &ranges[start_ix..] {
17905            if range
17906                .start
17907                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17908                .is_ge()
17909            {
17910                break;
17911            }
17912            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17913            if let Some(current_row) = &end_row {
17914                if end.row == current_row.row {
17915                    continue;
17916                }
17917            }
17918            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17919            if start_row.is_none() {
17920                assert_eq!(end_row, None);
17921                start_row = Some(start);
17922                end_row = Some(end);
17923                continue;
17924            }
17925            if let Some(current_end) = end_row.as_mut() {
17926                if start.row > current_end.row + 1 {
17927                    push_region(start_row, end_row);
17928                    start_row = Some(start);
17929                    end_row = Some(end);
17930                } else {
17931                    // Merge two hunks.
17932                    *current_end = end;
17933                }
17934            } else {
17935                unreachable!();
17936            }
17937        }
17938        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17939        push_region(start_row, end_row);
17940        results
17941    }
17942
17943    pub fn gutter_highlights_in_range(
17944        &self,
17945        search_range: Range<Anchor>,
17946        display_snapshot: &DisplaySnapshot,
17947        cx: &App,
17948    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17949        let mut results = Vec::new();
17950        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17951            let color = color_fetcher(cx);
17952            let start_ix = match ranges.binary_search_by(|probe| {
17953                let cmp = probe
17954                    .end
17955                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17956                if cmp.is_gt() {
17957                    Ordering::Greater
17958                } else {
17959                    Ordering::Less
17960                }
17961            }) {
17962                Ok(i) | Err(i) => i,
17963            };
17964            for range in &ranges[start_ix..] {
17965                if range
17966                    .start
17967                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17968                    .is_ge()
17969                {
17970                    break;
17971                }
17972
17973                let start = range.start.to_display_point(display_snapshot);
17974                let end = range.end.to_display_point(display_snapshot);
17975                results.push((start..end, color))
17976            }
17977        }
17978        results
17979    }
17980
17981    /// Get the text ranges corresponding to the redaction query
17982    pub fn redacted_ranges(
17983        &self,
17984        search_range: Range<Anchor>,
17985        display_snapshot: &DisplaySnapshot,
17986        cx: &App,
17987    ) -> Vec<Range<DisplayPoint>> {
17988        display_snapshot
17989            .buffer_snapshot
17990            .redacted_ranges(search_range, |file| {
17991                if let Some(file) = file {
17992                    file.is_private()
17993                        && EditorSettings::get(
17994                            Some(SettingsLocation {
17995                                worktree_id: file.worktree_id(cx),
17996                                path: file.path().as_ref(),
17997                            }),
17998                            cx,
17999                        )
18000                        .redact_private_values
18001                } else {
18002                    false
18003                }
18004            })
18005            .map(|range| {
18006                range.start.to_display_point(display_snapshot)
18007                    ..range.end.to_display_point(display_snapshot)
18008            })
18009            .collect()
18010    }
18011
18012    pub fn highlight_text<T: 'static>(
18013        &mut self,
18014        ranges: Vec<Range<Anchor>>,
18015        style: HighlightStyle,
18016        cx: &mut Context<Self>,
18017    ) {
18018        self.display_map.update(cx, |map, _| {
18019            map.highlight_text(TypeId::of::<T>(), ranges, style)
18020        });
18021        cx.notify();
18022    }
18023
18024    pub(crate) fn highlight_inlays<T: 'static>(
18025        &mut self,
18026        highlights: Vec<InlayHighlight>,
18027        style: HighlightStyle,
18028        cx: &mut Context<Self>,
18029    ) {
18030        self.display_map.update(cx, |map, _| {
18031            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18032        });
18033        cx.notify();
18034    }
18035
18036    pub fn text_highlights<'a, T: 'static>(
18037        &'a self,
18038        cx: &'a App,
18039    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18040        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18041    }
18042
18043    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18044        let cleared = self
18045            .display_map
18046            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18047        if cleared {
18048            cx.notify();
18049        }
18050    }
18051
18052    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18053        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18054            && self.focus_handle.is_focused(window)
18055    }
18056
18057    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18058        self.show_cursor_when_unfocused = is_enabled;
18059        cx.notify();
18060    }
18061
18062    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18063        cx.notify();
18064    }
18065
18066    fn on_debug_session_event(
18067        &mut self,
18068        _session: Entity<Session>,
18069        event: &SessionEvent,
18070        cx: &mut Context<Self>,
18071    ) {
18072        match event {
18073            SessionEvent::InvalidateInlineValue => {
18074                self.refresh_inline_values(cx);
18075            }
18076            _ => {}
18077        }
18078    }
18079
18080    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18081        let Some(project) = self.project.clone() else {
18082            return;
18083        };
18084
18085        if !self.inline_value_cache.enabled {
18086            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18087            self.splice_inlays(&inlays, Vec::new(), cx);
18088            return;
18089        }
18090
18091        let current_execution_position = self
18092            .highlighted_rows
18093            .get(&TypeId::of::<ActiveDebugLine>())
18094            .and_then(|lines| lines.last().map(|line| line.range.start));
18095
18096        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18097            let inline_values = editor
18098                .update(cx, |editor, cx| {
18099                    let Some(current_execution_position) = current_execution_position else {
18100                        return Some(Task::ready(Ok(Vec::new())));
18101                    };
18102
18103                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18104                        let snapshot = buffer.snapshot(cx);
18105
18106                        let excerpt = snapshot.excerpt_containing(
18107                            current_execution_position..current_execution_position,
18108                        )?;
18109
18110                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18111                    })?;
18112
18113                    let range =
18114                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18115
18116                    project.inline_values(buffer, range, cx)
18117                })
18118                .ok()
18119                .flatten()?
18120                .await
18121                .context("refreshing debugger inlays")
18122                .log_err()?;
18123
18124            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18125
18126            for (buffer_id, inline_value) in inline_values
18127                .into_iter()
18128                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18129            {
18130                buffer_inline_values
18131                    .entry(buffer_id)
18132                    .or_default()
18133                    .push(inline_value);
18134            }
18135
18136            editor
18137                .update(cx, |editor, cx| {
18138                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18139                    let mut new_inlays = Vec::default();
18140
18141                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18142                        let buffer_id = buffer_snapshot.remote_id();
18143                        buffer_inline_values
18144                            .get(&buffer_id)
18145                            .into_iter()
18146                            .flatten()
18147                            .for_each(|hint| {
18148                                let inlay = Inlay::debugger_hint(
18149                                    post_inc(&mut editor.next_inlay_id),
18150                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18151                                    hint.text(),
18152                                );
18153
18154                                new_inlays.push(inlay);
18155                            });
18156                    }
18157
18158                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18159                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18160
18161                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18162                })
18163                .ok()?;
18164            Some(())
18165        });
18166    }
18167
18168    fn on_buffer_event(
18169        &mut self,
18170        multibuffer: &Entity<MultiBuffer>,
18171        event: &multi_buffer::Event,
18172        window: &mut Window,
18173        cx: &mut Context<Self>,
18174    ) {
18175        match event {
18176            multi_buffer::Event::Edited {
18177                singleton_buffer_edited,
18178                edited_buffer: buffer_edited,
18179            } => {
18180                self.scrollbar_marker_state.dirty = true;
18181                self.active_indent_guides_state.dirty = true;
18182                self.refresh_active_diagnostics(cx);
18183                self.refresh_code_actions(window, cx);
18184                self.refresh_selected_text_highlights(true, window, cx);
18185                refresh_matching_bracket_highlights(self, window, cx);
18186                if self.has_active_inline_completion() {
18187                    self.update_visible_inline_completion(window, cx);
18188                }
18189                if let Some(buffer) = buffer_edited {
18190                    let buffer_id = buffer.read(cx).remote_id();
18191                    if !self.registered_buffers.contains_key(&buffer_id) {
18192                        if let Some(project) = self.project.as_ref() {
18193                            project.update(cx, |project, cx| {
18194                                self.registered_buffers.insert(
18195                                    buffer_id,
18196                                    project.register_buffer_with_language_servers(&buffer, cx),
18197                                );
18198                            })
18199                        }
18200                    }
18201                }
18202                cx.emit(EditorEvent::BufferEdited);
18203                cx.emit(SearchEvent::MatchesInvalidated);
18204                if *singleton_buffer_edited {
18205                    if let Some(project) = &self.project {
18206                        #[allow(clippy::mutable_key_type)]
18207                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18208                            multibuffer
18209                                .all_buffers()
18210                                .into_iter()
18211                                .filter_map(|buffer| {
18212                                    buffer.update(cx, |buffer, cx| {
18213                                        let language = buffer.language()?;
18214                                        let should_discard = project.update(cx, |project, cx| {
18215                                            project.is_local()
18216                                                && !project.has_language_servers_for(buffer, cx)
18217                                        });
18218                                        should_discard.not().then_some(language.clone())
18219                                    })
18220                                })
18221                                .collect::<HashSet<_>>()
18222                        });
18223                        if !languages_affected.is_empty() {
18224                            self.refresh_inlay_hints(
18225                                InlayHintRefreshReason::BufferEdited(languages_affected),
18226                                cx,
18227                            );
18228                        }
18229                    }
18230                }
18231
18232                let Some(project) = &self.project else { return };
18233                let (telemetry, is_via_ssh) = {
18234                    let project = project.read(cx);
18235                    let telemetry = project.client().telemetry().clone();
18236                    let is_via_ssh = project.is_via_ssh();
18237                    (telemetry, is_via_ssh)
18238                };
18239                refresh_linked_ranges(self, window, cx);
18240                telemetry.log_edit_event("editor", is_via_ssh);
18241            }
18242            multi_buffer::Event::ExcerptsAdded {
18243                buffer,
18244                predecessor,
18245                excerpts,
18246            } => {
18247                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18248                let buffer_id = buffer.read(cx).remote_id();
18249                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18250                    if let Some(project) = &self.project {
18251                        update_uncommitted_diff_for_buffer(
18252                            cx.entity(),
18253                            project,
18254                            [buffer.clone()],
18255                            self.buffer.clone(),
18256                            cx,
18257                        )
18258                        .detach();
18259                    }
18260                }
18261                cx.emit(EditorEvent::ExcerptsAdded {
18262                    buffer: buffer.clone(),
18263                    predecessor: *predecessor,
18264                    excerpts: excerpts.clone(),
18265                });
18266                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18267            }
18268            multi_buffer::Event::ExcerptsRemoved {
18269                ids,
18270                removed_buffer_ids,
18271            } => {
18272                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18273                let buffer = self.buffer.read(cx);
18274                self.registered_buffers
18275                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18276                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18277                cx.emit(EditorEvent::ExcerptsRemoved {
18278                    ids: ids.clone(),
18279                    removed_buffer_ids: removed_buffer_ids.clone(),
18280                })
18281            }
18282            multi_buffer::Event::ExcerptsEdited {
18283                excerpt_ids,
18284                buffer_ids,
18285            } => {
18286                self.display_map.update(cx, |map, cx| {
18287                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18288                });
18289                cx.emit(EditorEvent::ExcerptsEdited {
18290                    ids: excerpt_ids.clone(),
18291                })
18292            }
18293            multi_buffer::Event::ExcerptsExpanded { ids } => {
18294                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18295                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18296            }
18297            multi_buffer::Event::Reparsed(buffer_id) => {
18298                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18299                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18300
18301                cx.emit(EditorEvent::Reparsed(*buffer_id));
18302            }
18303            multi_buffer::Event::DiffHunksToggled => {
18304                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18305            }
18306            multi_buffer::Event::LanguageChanged(buffer_id) => {
18307                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18308                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18309                cx.emit(EditorEvent::Reparsed(*buffer_id));
18310                cx.notify();
18311            }
18312            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18313            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18314            multi_buffer::Event::FileHandleChanged
18315            | multi_buffer::Event::Reloaded
18316            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18317            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18318            multi_buffer::Event::DiagnosticsUpdated => {
18319                self.refresh_active_diagnostics(cx);
18320                self.refresh_inline_diagnostics(true, window, cx);
18321                self.scrollbar_marker_state.dirty = true;
18322                cx.notify();
18323            }
18324            _ => {}
18325        };
18326    }
18327
18328    pub fn start_temporary_diff_override(&mut self) {
18329        self.load_diff_task.take();
18330        self.temporary_diff_override = true;
18331    }
18332
18333    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18334        self.temporary_diff_override = false;
18335        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18336        self.buffer.update(cx, |buffer, cx| {
18337            buffer.set_all_diff_hunks_collapsed(cx);
18338        });
18339
18340        if let Some(project) = self.project.clone() {
18341            self.load_diff_task = Some(
18342                update_uncommitted_diff_for_buffer(
18343                    cx.entity(),
18344                    &project,
18345                    self.buffer.read(cx).all_buffers(),
18346                    self.buffer.clone(),
18347                    cx,
18348                )
18349                .shared(),
18350            );
18351        }
18352    }
18353
18354    fn on_display_map_changed(
18355        &mut self,
18356        _: Entity<DisplayMap>,
18357        _: &mut Window,
18358        cx: &mut Context<Self>,
18359    ) {
18360        cx.notify();
18361    }
18362
18363    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18364        let new_severity = if self.diagnostics_enabled() {
18365            EditorSettings::get_global(cx)
18366                .diagnostics_max_severity
18367                .unwrap_or(DiagnosticSeverity::Hint)
18368        } else {
18369            DiagnosticSeverity::Off
18370        };
18371        self.set_max_diagnostics_severity(new_severity, cx);
18372        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18373        self.update_edit_prediction_settings(cx);
18374        self.refresh_inline_completion(true, false, window, cx);
18375        self.refresh_inlay_hints(
18376            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18377                self.selections.newest_anchor().head(),
18378                &self.buffer.read(cx).snapshot(cx),
18379                cx,
18380            )),
18381            cx,
18382        );
18383
18384        let old_cursor_shape = self.cursor_shape;
18385
18386        {
18387            let editor_settings = EditorSettings::get_global(cx);
18388            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18389            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18390            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18391            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18392        }
18393
18394        if old_cursor_shape != self.cursor_shape {
18395            cx.emit(EditorEvent::CursorShapeChanged);
18396        }
18397
18398        let project_settings = ProjectSettings::get_global(cx);
18399        self.serialize_dirty_buffers =
18400            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18401
18402        if self.mode.is_full() {
18403            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18404            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18405            if self.show_inline_diagnostics != show_inline_diagnostics {
18406                self.show_inline_diagnostics = show_inline_diagnostics;
18407                self.refresh_inline_diagnostics(false, window, cx);
18408            }
18409
18410            if self.git_blame_inline_enabled != inline_blame_enabled {
18411                self.toggle_git_blame_inline_internal(false, window, cx);
18412            }
18413
18414            let minimap_settings = EditorSettings::get_global(cx).minimap;
18415            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18416                self.set_minimap_visibility(
18417                    self.minimap_visibility.toggle_visibility(),
18418                    window,
18419                    cx,
18420                );
18421            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18422                minimap_entity.update(cx, |minimap_editor, cx| {
18423                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18424                })
18425            }
18426        }
18427
18428        cx.notify();
18429    }
18430
18431    pub fn set_searchable(&mut self, searchable: bool) {
18432        self.searchable = searchable;
18433    }
18434
18435    pub fn searchable(&self) -> bool {
18436        self.searchable
18437    }
18438
18439    fn open_proposed_changes_editor(
18440        &mut self,
18441        _: &OpenProposedChangesEditor,
18442        window: &mut Window,
18443        cx: &mut Context<Self>,
18444    ) {
18445        let Some(workspace) = self.workspace() else {
18446            cx.propagate();
18447            return;
18448        };
18449
18450        let selections = self.selections.all::<usize>(cx);
18451        let multi_buffer = self.buffer.read(cx);
18452        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18453        let mut new_selections_by_buffer = HashMap::default();
18454        for selection in selections {
18455            for (buffer, range, _) in
18456                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18457            {
18458                let mut range = range.to_point(buffer);
18459                range.start.column = 0;
18460                range.end.column = buffer.line_len(range.end.row);
18461                new_selections_by_buffer
18462                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18463                    .or_insert(Vec::new())
18464                    .push(range)
18465            }
18466        }
18467
18468        let proposed_changes_buffers = new_selections_by_buffer
18469            .into_iter()
18470            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18471            .collect::<Vec<_>>();
18472        let proposed_changes_editor = cx.new(|cx| {
18473            ProposedChangesEditor::new(
18474                "Proposed changes",
18475                proposed_changes_buffers,
18476                self.project.clone(),
18477                window,
18478                cx,
18479            )
18480        });
18481
18482        window.defer(cx, move |window, cx| {
18483            workspace.update(cx, |workspace, cx| {
18484                workspace.active_pane().update(cx, |pane, cx| {
18485                    pane.add_item(
18486                        Box::new(proposed_changes_editor),
18487                        true,
18488                        true,
18489                        None,
18490                        window,
18491                        cx,
18492                    );
18493                });
18494            });
18495        });
18496    }
18497
18498    pub fn open_excerpts_in_split(
18499        &mut self,
18500        _: &OpenExcerptsSplit,
18501        window: &mut Window,
18502        cx: &mut Context<Self>,
18503    ) {
18504        self.open_excerpts_common(None, true, window, cx)
18505    }
18506
18507    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18508        self.open_excerpts_common(None, false, window, cx)
18509    }
18510
18511    fn open_excerpts_common(
18512        &mut self,
18513        jump_data: Option<JumpData>,
18514        split: bool,
18515        window: &mut Window,
18516        cx: &mut Context<Self>,
18517    ) {
18518        let Some(workspace) = self.workspace() else {
18519            cx.propagate();
18520            return;
18521        };
18522
18523        if self.buffer.read(cx).is_singleton() {
18524            cx.propagate();
18525            return;
18526        }
18527
18528        let mut new_selections_by_buffer = HashMap::default();
18529        match &jump_data {
18530            Some(JumpData::MultiBufferPoint {
18531                excerpt_id,
18532                position,
18533                anchor,
18534                line_offset_from_top,
18535            }) => {
18536                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18537                if let Some(buffer) = multi_buffer_snapshot
18538                    .buffer_id_for_excerpt(*excerpt_id)
18539                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18540                {
18541                    let buffer_snapshot = buffer.read(cx).snapshot();
18542                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18543                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18544                    } else {
18545                        buffer_snapshot.clip_point(*position, Bias::Left)
18546                    };
18547                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18548                    new_selections_by_buffer.insert(
18549                        buffer,
18550                        (
18551                            vec![jump_to_offset..jump_to_offset],
18552                            Some(*line_offset_from_top),
18553                        ),
18554                    );
18555                }
18556            }
18557            Some(JumpData::MultiBufferRow {
18558                row,
18559                line_offset_from_top,
18560            }) => {
18561                let point = MultiBufferPoint::new(row.0, 0);
18562                if let Some((buffer, buffer_point, _)) =
18563                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18564                {
18565                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18566                    new_selections_by_buffer
18567                        .entry(buffer)
18568                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18569                        .0
18570                        .push(buffer_offset..buffer_offset)
18571                }
18572            }
18573            None => {
18574                let selections = self.selections.all::<usize>(cx);
18575                let multi_buffer = self.buffer.read(cx);
18576                for selection in selections {
18577                    for (snapshot, range, _, anchor) in multi_buffer
18578                        .snapshot(cx)
18579                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18580                    {
18581                        if let Some(anchor) = anchor {
18582                            // selection is in a deleted hunk
18583                            let Some(buffer_id) = anchor.buffer_id else {
18584                                continue;
18585                            };
18586                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18587                                continue;
18588                            };
18589                            let offset = text::ToOffset::to_offset(
18590                                &anchor.text_anchor,
18591                                &buffer_handle.read(cx).snapshot(),
18592                            );
18593                            let range = offset..offset;
18594                            new_selections_by_buffer
18595                                .entry(buffer_handle)
18596                                .or_insert((Vec::new(), None))
18597                                .0
18598                                .push(range)
18599                        } else {
18600                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18601                            else {
18602                                continue;
18603                            };
18604                            new_selections_by_buffer
18605                                .entry(buffer_handle)
18606                                .or_insert((Vec::new(), None))
18607                                .0
18608                                .push(range)
18609                        }
18610                    }
18611                }
18612            }
18613        }
18614
18615        new_selections_by_buffer
18616            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18617
18618        if new_selections_by_buffer.is_empty() {
18619            return;
18620        }
18621
18622        // We defer the pane interaction because we ourselves are a workspace item
18623        // and activating a new item causes the pane to call a method on us reentrantly,
18624        // which panics if we're on the stack.
18625        window.defer(cx, move |window, cx| {
18626            workspace.update(cx, |workspace, cx| {
18627                let pane = if split {
18628                    workspace.adjacent_pane(window, cx)
18629                } else {
18630                    workspace.active_pane().clone()
18631                };
18632
18633                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18634                    let editor = buffer
18635                        .read(cx)
18636                        .file()
18637                        .is_none()
18638                        .then(|| {
18639                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18640                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18641                            // Instead, we try to activate the existing editor in the pane first.
18642                            let (editor, pane_item_index) =
18643                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18644                                    let editor = item.downcast::<Editor>()?;
18645                                    let singleton_buffer =
18646                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18647                                    if singleton_buffer == buffer {
18648                                        Some((editor, i))
18649                                    } else {
18650                                        None
18651                                    }
18652                                })?;
18653                            pane.update(cx, |pane, cx| {
18654                                pane.activate_item(pane_item_index, true, true, window, cx)
18655                            });
18656                            Some(editor)
18657                        })
18658                        .flatten()
18659                        .unwrap_or_else(|| {
18660                            workspace.open_project_item::<Self>(
18661                                pane.clone(),
18662                                buffer,
18663                                true,
18664                                true,
18665                                window,
18666                                cx,
18667                            )
18668                        });
18669
18670                    editor.update(cx, |editor, cx| {
18671                        let autoscroll = match scroll_offset {
18672                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18673                            None => Autoscroll::newest(),
18674                        };
18675                        let nav_history = editor.nav_history.take();
18676                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18677                            s.select_ranges(ranges);
18678                        });
18679                        editor.nav_history = nav_history;
18680                    });
18681                }
18682            })
18683        });
18684    }
18685
18686    // For now, don't allow opening excerpts in buffers that aren't backed by
18687    // regular project files.
18688    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18689        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18690    }
18691
18692    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18693        let snapshot = self.buffer.read(cx).read(cx);
18694        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18695        Some(
18696            ranges
18697                .iter()
18698                .map(move |range| {
18699                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18700                })
18701                .collect(),
18702        )
18703    }
18704
18705    fn selection_replacement_ranges(
18706        &self,
18707        range: Range<OffsetUtf16>,
18708        cx: &mut App,
18709    ) -> Vec<Range<OffsetUtf16>> {
18710        let selections = self.selections.all::<OffsetUtf16>(cx);
18711        let newest_selection = selections
18712            .iter()
18713            .max_by_key(|selection| selection.id)
18714            .unwrap();
18715        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18716        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18717        let snapshot = self.buffer.read(cx).read(cx);
18718        selections
18719            .into_iter()
18720            .map(|mut selection| {
18721                selection.start.0 =
18722                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18723                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18724                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18725                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18726            })
18727            .collect()
18728    }
18729
18730    fn report_editor_event(
18731        &self,
18732        event_type: &'static str,
18733        file_extension: Option<String>,
18734        cx: &App,
18735    ) {
18736        if cfg!(any(test, feature = "test-support")) {
18737            return;
18738        }
18739
18740        let Some(project) = &self.project else { return };
18741
18742        // If None, we are in a file without an extension
18743        let file = self
18744            .buffer
18745            .read(cx)
18746            .as_singleton()
18747            .and_then(|b| b.read(cx).file());
18748        let file_extension = file_extension.or(file
18749            .as_ref()
18750            .and_then(|file| Path::new(file.file_name(cx)).extension())
18751            .and_then(|e| e.to_str())
18752            .map(|a| a.to_string()));
18753
18754        let vim_mode = vim_enabled(cx);
18755
18756        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18757        let copilot_enabled = edit_predictions_provider
18758            == language::language_settings::EditPredictionProvider::Copilot;
18759        let copilot_enabled_for_language = self
18760            .buffer
18761            .read(cx)
18762            .language_settings(cx)
18763            .show_edit_predictions;
18764
18765        let project = project.read(cx);
18766        telemetry::event!(
18767            event_type,
18768            file_extension,
18769            vim_mode,
18770            copilot_enabled,
18771            copilot_enabled_for_language,
18772            edit_predictions_provider,
18773            is_via_ssh = project.is_via_ssh(),
18774        );
18775    }
18776
18777    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18778    /// with each line being an array of {text, highlight} objects.
18779    fn copy_highlight_json(
18780        &mut self,
18781        _: &CopyHighlightJson,
18782        window: &mut Window,
18783        cx: &mut Context<Self>,
18784    ) {
18785        #[derive(Serialize)]
18786        struct Chunk<'a> {
18787            text: String,
18788            highlight: Option<&'a str>,
18789        }
18790
18791        let snapshot = self.buffer.read(cx).snapshot(cx);
18792        let range = self
18793            .selected_text_range(false, window, cx)
18794            .and_then(|selection| {
18795                if selection.range.is_empty() {
18796                    None
18797                } else {
18798                    Some(selection.range)
18799                }
18800            })
18801            .unwrap_or_else(|| 0..snapshot.len());
18802
18803        let chunks = snapshot.chunks(range, true);
18804        let mut lines = Vec::new();
18805        let mut line: VecDeque<Chunk> = VecDeque::new();
18806
18807        let Some(style) = self.style.as_ref() else {
18808            return;
18809        };
18810
18811        for chunk in chunks {
18812            let highlight = chunk
18813                .syntax_highlight_id
18814                .and_then(|id| id.name(&style.syntax));
18815            let mut chunk_lines = chunk.text.split('\n').peekable();
18816            while let Some(text) = chunk_lines.next() {
18817                let mut merged_with_last_token = false;
18818                if let Some(last_token) = line.back_mut() {
18819                    if last_token.highlight == highlight {
18820                        last_token.text.push_str(text);
18821                        merged_with_last_token = true;
18822                    }
18823                }
18824
18825                if !merged_with_last_token {
18826                    line.push_back(Chunk {
18827                        text: text.into(),
18828                        highlight,
18829                    });
18830                }
18831
18832                if chunk_lines.peek().is_some() {
18833                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18834                        line.pop_front();
18835                    }
18836                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18837                        line.pop_back();
18838                    }
18839
18840                    lines.push(mem::take(&mut line));
18841                }
18842            }
18843        }
18844
18845        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18846            return;
18847        };
18848        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18849    }
18850
18851    pub fn open_context_menu(
18852        &mut self,
18853        _: &OpenContextMenu,
18854        window: &mut Window,
18855        cx: &mut Context<Self>,
18856    ) {
18857        self.request_autoscroll(Autoscroll::newest(), cx);
18858        let position = self.selections.newest_display(cx).start;
18859        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18860    }
18861
18862    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18863        &self.inlay_hint_cache
18864    }
18865
18866    pub fn replay_insert_event(
18867        &mut self,
18868        text: &str,
18869        relative_utf16_range: Option<Range<isize>>,
18870        window: &mut Window,
18871        cx: &mut Context<Self>,
18872    ) {
18873        if !self.input_enabled {
18874            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18875            return;
18876        }
18877        if let Some(relative_utf16_range) = relative_utf16_range {
18878            let selections = self.selections.all::<OffsetUtf16>(cx);
18879            self.change_selections(None, window, cx, |s| {
18880                let new_ranges = selections.into_iter().map(|range| {
18881                    let start = OffsetUtf16(
18882                        range
18883                            .head()
18884                            .0
18885                            .saturating_add_signed(relative_utf16_range.start),
18886                    );
18887                    let end = OffsetUtf16(
18888                        range
18889                            .head()
18890                            .0
18891                            .saturating_add_signed(relative_utf16_range.end),
18892                    );
18893                    start..end
18894                });
18895                s.select_ranges(new_ranges);
18896            });
18897        }
18898
18899        self.handle_input(text, window, cx);
18900    }
18901
18902    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18903        let Some(provider) = self.semantics_provider.as_ref() else {
18904            return false;
18905        };
18906
18907        let mut supports = false;
18908        self.buffer().update(cx, |this, cx| {
18909            this.for_each_buffer(|buffer| {
18910                supports |= provider.supports_inlay_hints(buffer, cx);
18911            });
18912        });
18913
18914        supports
18915    }
18916
18917    pub fn is_focused(&self, window: &Window) -> bool {
18918        self.focus_handle.is_focused(window)
18919    }
18920
18921    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18922        cx.emit(EditorEvent::Focused);
18923
18924        if let Some(descendant) = self
18925            .last_focused_descendant
18926            .take()
18927            .and_then(|descendant| descendant.upgrade())
18928        {
18929            window.focus(&descendant);
18930        } else {
18931            if let Some(blame) = self.blame.as_ref() {
18932                blame.update(cx, GitBlame::focus)
18933            }
18934
18935            self.blink_manager.update(cx, BlinkManager::enable);
18936            self.show_cursor_names(window, cx);
18937            self.buffer.update(cx, |buffer, cx| {
18938                buffer.finalize_last_transaction(cx);
18939                if self.leader_id.is_none() {
18940                    buffer.set_active_selections(
18941                        &self.selections.disjoint_anchors(),
18942                        self.selections.line_mode,
18943                        self.cursor_shape,
18944                        cx,
18945                    );
18946                }
18947            });
18948        }
18949    }
18950
18951    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18952        cx.emit(EditorEvent::FocusedIn)
18953    }
18954
18955    fn handle_focus_out(
18956        &mut self,
18957        event: FocusOutEvent,
18958        _window: &mut Window,
18959        cx: &mut Context<Self>,
18960    ) {
18961        if event.blurred != self.focus_handle {
18962            self.last_focused_descendant = Some(event.blurred);
18963        }
18964        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18965    }
18966
18967    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18968        self.blink_manager.update(cx, BlinkManager::disable);
18969        self.buffer
18970            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18971
18972        if let Some(blame) = self.blame.as_ref() {
18973            blame.update(cx, GitBlame::blur)
18974        }
18975        if !self.hover_state.focused(window, cx) {
18976            hide_hover(self, cx);
18977        }
18978        if !self
18979            .context_menu
18980            .borrow()
18981            .as_ref()
18982            .is_some_and(|context_menu| context_menu.focused(window, cx))
18983        {
18984            self.hide_context_menu(window, cx);
18985        }
18986        self.discard_inline_completion(false, cx);
18987        cx.emit(EditorEvent::Blurred);
18988        cx.notify();
18989    }
18990
18991    pub fn register_action<A: Action>(
18992        &mut self,
18993        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
18994    ) -> Subscription {
18995        let id = self.next_editor_action_id.post_inc();
18996        let listener = Arc::new(listener);
18997        self.editor_actions.borrow_mut().insert(
18998            id,
18999            Box::new(move |window, _| {
19000                let listener = listener.clone();
19001                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19002                    let action = action.downcast_ref().unwrap();
19003                    if phase == DispatchPhase::Bubble {
19004                        listener(action, window, cx)
19005                    }
19006                })
19007            }),
19008        );
19009
19010        let editor_actions = self.editor_actions.clone();
19011        Subscription::new(move || {
19012            editor_actions.borrow_mut().remove(&id);
19013        })
19014    }
19015
19016    pub fn file_header_size(&self) -> u32 {
19017        FILE_HEADER_HEIGHT
19018    }
19019
19020    pub fn restore(
19021        &mut self,
19022        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19023        window: &mut Window,
19024        cx: &mut Context<Self>,
19025    ) {
19026        let workspace = self.workspace();
19027        let project = self.project.as_ref();
19028        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19029            let mut tasks = Vec::new();
19030            for (buffer_id, changes) in revert_changes {
19031                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19032                    buffer.update(cx, |buffer, cx| {
19033                        buffer.edit(
19034                            changes
19035                                .into_iter()
19036                                .map(|(range, text)| (range, text.to_string())),
19037                            None,
19038                            cx,
19039                        );
19040                    });
19041
19042                    if let Some(project) =
19043                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19044                    {
19045                        project.update(cx, |project, cx| {
19046                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19047                        })
19048                    }
19049                }
19050            }
19051            tasks
19052        });
19053        cx.spawn_in(window, async move |_, cx| {
19054            for (buffer, task) in save_tasks {
19055                let result = task.await;
19056                if result.is_err() {
19057                    let Some(path) = buffer
19058                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19059                        .ok()
19060                    else {
19061                        continue;
19062                    };
19063                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19064                        let Some(task) = cx
19065                            .update_window_entity(&workspace, |workspace, window, cx| {
19066                                workspace
19067                                    .open_path_preview(path, None, false, false, false, window, cx)
19068                            })
19069                            .ok()
19070                        else {
19071                            continue;
19072                        };
19073                        task.await.log_err();
19074                    }
19075                }
19076            }
19077        })
19078        .detach();
19079        self.change_selections(None, window, cx, |selections| selections.refresh());
19080    }
19081
19082    pub fn to_pixel_point(
19083        &self,
19084        source: multi_buffer::Anchor,
19085        editor_snapshot: &EditorSnapshot,
19086        window: &mut Window,
19087    ) -> Option<gpui::Point<Pixels>> {
19088        let source_point = source.to_display_point(editor_snapshot);
19089        self.display_to_pixel_point(source_point, editor_snapshot, window)
19090    }
19091
19092    pub fn display_to_pixel_point(
19093        &self,
19094        source: DisplayPoint,
19095        editor_snapshot: &EditorSnapshot,
19096        window: &mut Window,
19097    ) -> Option<gpui::Point<Pixels>> {
19098        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19099        let text_layout_details = self.text_layout_details(window);
19100        let scroll_top = text_layout_details
19101            .scroll_anchor
19102            .scroll_position(editor_snapshot)
19103            .y;
19104
19105        if source.row().as_f32() < scroll_top.floor() {
19106            return None;
19107        }
19108        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19109        let source_y = line_height * (source.row().as_f32() - scroll_top);
19110        Some(gpui::Point::new(source_x, source_y))
19111    }
19112
19113    pub fn has_visible_completions_menu(&self) -> bool {
19114        !self.edit_prediction_preview_is_active()
19115            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19116                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19117            })
19118    }
19119
19120    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19121        if self.mode.is_minimap() {
19122            return;
19123        }
19124        self.addons
19125            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19126    }
19127
19128    pub fn unregister_addon<T: Addon>(&mut self) {
19129        self.addons.remove(&std::any::TypeId::of::<T>());
19130    }
19131
19132    pub fn addon<T: Addon>(&self) -> Option<&T> {
19133        let type_id = std::any::TypeId::of::<T>();
19134        self.addons
19135            .get(&type_id)
19136            .and_then(|item| item.to_any().downcast_ref::<T>())
19137    }
19138
19139    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19140        let type_id = std::any::TypeId::of::<T>();
19141        self.addons
19142            .get_mut(&type_id)
19143            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19144    }
19145
19146    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19147        let text_layout_details = self.text_layout_details(window);
19148        let style = &text_layout_details.editor_style;
19149        let font_id = window.text_system().resolve_font(&style.text.font());
19150        let font_size = style.text.font_size.to_pixels(window.rem_size());
19151        let line_height = style.text.line_height_in_pixels(window.rem_size());
19152        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19153
19154        gpui::Size::new(em_width, line_height)
19155    }
19156
19157    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19158        self.load_diff_task.clone()
19159    }
19160
19161    fn read_metadata_from_db(
19162        &mut self,
19163        item_id: u64,
19164        workspace_id: WorkspaceId,
19165        window: &mut Window,
19166        cx: &mut Context<Editor>,
19167    ) {
19168        if self.is_singleton(cx)
19169            && !self.mode.is_minimap()
19170            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19171        {
19172            let buffer_snapshot = OnceCell::new();
19173
19174            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19175                if !folds.is_empty() {
19176                    let snapshot =
19177                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19178                    self.fold_ranges(
19179                        folds
19180                            .into_iter()
19181                            .map(|(start, end)| {
19182                                snapshot.clip_offset(start, Bias::Left)
19183                                    ..snapshot.clip_offset(end, Bias::Right)
19184                            })
19185                            .collect(),
19186                        false,
19187                        window,
19188                        cx,
19189                    );
19190                }
19191            }
19192
19193            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19194                if !selections.is_empty() {
19195                    let snapshot =
19196                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19197                    self.change_selections(None, window, cx, |s| {
19198                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19199                            snapshot.clip_offset(start, Bias::Left)
19200                                ..snapshot.clip_offset(end, Bias::Right)
19201                        }));
19202                    });
19203                }
19204            };
19205        }
19206
19207        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19208    }
19209}
19210
19211fn vim_enabled(cx: &App) -> bool {
19212    cx.global::<SettingsStore>()
19213        .raw_user_settings()
19214        .get("vim_mode")
19215        == Some(&serde_json::Value::Bool(true))
19216}
19217
19218// Consider user intent and default settings
19219fn choose_completion_range(
19220    completion: &Completion,
19221    intent: CompletionIntent,
19222    buffer: &Entity<Buffer>,
19223    cx: &mut Context<Editor>,
19224) -> Range<usize> {
19225    fn should_replace(
19226        completion: &Completion,
19227        insert_range: &Range<text::Anchor>,
19228        intent: CompletionIntent,
19229        completion_mode_setting: LspInsertMode,
19230        buffer: &Buffer,
19231    ) -> bool {
19232        // specific actions take precedence over settings
19233        match intent {
19234            CompletionIntent::CompleteWithInsert => return false,
19235            CompletionIntent::CompleteWithReplace => return true,
19236            CompletionIntent::Complete | CompletionIntent::Compose => {}
19237        }
19238
19239        match completion_mode_setting {
19240            LspInsertMode::Insert => false,
19241            LspInsertMode::Replace => true,
19242            LspInsertMode::ReplaceSubsequence => {
19243                let mut text_to_replace = buffer.chars_for_range(
19244                    buffer.anchor_before(completion.replace_range.start)
19245                        ..buffer.anchor_after(completion.replace_range.end),
19246                );
19247                let mut completion_text = completion.new_text.chars();
19248
19249                // is `text_to_replace` a subsequence of `completion_text`
19250                text_to_replace
19251                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19252            }
19253            LspInsertMode::ReplaceSuffix => {
19254                let range_after_cursor = insert_range.end..completion.replace_range.end;
19255
19256                let text_after_cursor = buffer
19257                    .text_for_range(
19258                        buffer.anchor_before(range_after_cursor.start)
19259                            ..buffer.anchor_after(range_after_cursor.end),
19260                    )
19261                    .collect::<String>();
19262                completion.new_text.ends_with(&text_after_cursor)
19263            }
19264        }
19265    }
19266
19267    let buffer = buffer.read(cx);
19268
19269    if let CompletionSource::Lsp {
19270        insert_range: Some(insert_range),
19271        ..
19272    } = &completion.source
19273    {
19274        let completion_mode_setting =
19275            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19276                .completions
19277                .lsp_insert_mode;
19278
19279        if !should_replace(
19280            completion,
19281            &insert_range,
19282            intent,
19283            completion_mode_setting,
19284            buffer,
19285        ) {
19286            return insert_range.to_offset(buffer);
19287        }
19288    }
19289
19290    completion.replace_range.to_offset(buffer)
19291}
19292
19293fn insert_extra_newline_brackets(
19294    buffer: &MultiBufferSnapshot,
19295    range: Range<usize>,
19296    language: &language::LanguageScope,
19297) -> bool {
19298    let leading_whitespace_len = buffer
19299        .reversed_chars_at(range.start)
19300        .take_while(|c| c.is_whitespace() && *c != '\n')
19301        .map(|c| c.len_utf8())
19302        .sum::<usize>();
19303    let trailing_whitespace_len = buffer
19304        .chars_at(range.end)
19305        .take_while(|c| c.is_whitespace() && *c != '\n')
19306        .map(|c| c.len_utf8())
19307        .sum::<usize>();
19308    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19309
19310    language.brackets().any(|(pair, enabled)| {
19311        let pair_start = pair.start.trim_end();
19312        let pair_end = pair.end.trim_start();
19313
19314        enabled
19315            && pair.newline
19316            && buffer.contains_str_at(range.end, pair_end)
19317            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19318    })
19319}
19320
19321fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19322    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19323        [(buffer, range, _)] => (*buffer, range.clone()),
19324        _ => return false,
19325    };
19326    let pair = {
19327        let mut result: Option<BracketMatch> = None;
19328
19329        for pair in buffer
19330            .all_bracket_ranges(range.clone())
19331            .filter(move |pair| {
19332                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19333            })
19334        {
19335            let len = pair.close_range.end - pair.open_range.start;
19336
19337            if let Some(existing) = &result {
19338                let existing_len = existing.close_range.end - existing.open_range.start;
19339                if len > existing_len {
19340                    continue;
19341                }
19342            }
19343
19344            result = Some(pair);
19345        }
19346
19347        result
19348    };
19349    let Some(pair) = pair else {
19350        return false;
19351    };
19352    pair.newline_only
19353        && buffer
19354            .chars_for_range(pair.open_range.end..range.start)
19355            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19356            .all(|c| c.is_whitespace() && c != '\n')
19357}
19358
19359fn update_uncommitted_diff_for_buffer(
19360    editor: Entity<Editor>,
19361    project: &Entity<Project>,
19362    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19363    buffer: Entity<MultiBuffer>,
19364    cx: &mut App,
19365) -> Task<()> {
19366    let mut tasks = Vec::new();
19367    project.update(cx, |project, cx| {
19368        for buffer in buffers {
19369            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19370                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19371            }
19372        }
19373    });
19374    cx.spawn(async move |cx| {
19375        let diffs = future::join_all(tasks).await;
19376        if editor
19377            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19378            .unwrap_or(false)
19379        {
19380            return;
19381        }
19382
19383        buffer
19384            .update(cx, |buffer, cx| {
19385                for diff in diffs.into_iter().flatten() {
19386                    buffer.add_diff(diff, cx);
19387                }
19388            })
19389            .ok();
19390    })
19391}
19392
19393fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19394    let tab_size = tab_size.get() as usize;
19395    let mut width = offset;
19396
19397    for ch in text.chars() {
19398        width += if ch == '\t' {
19399            tab_size - (width % tab_size)
19400        } else {
19401            1
19402        };
19403    }
19404
19405    width - offset
19406}
19407
19408#[cfg(test)]
19409mod tests {
19410    use super::*;
19411
19412    #[test]
19413    fn test_string_size_with_expanded_tabs() {
19414        let nz = |val| NonZeroU32::new(val).unwrap();
19415        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19416        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19417        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19418        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19419        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19420        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19421        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19422        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19423    }
19424}
19425
19426/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19427struct WordBreakingTokenizer<'a> {
19428    input: &'a str,
19429}
19430
19431impl<'a> WordBreakingTokenizer<'a> {
19432    fn new(input: &'a str) -> Self {
19433        Self { input }
19434    }
19435}
19436
19437fn is_char_ideographic(ch: char) -> bool {
19438    use unicode_script::Script::*;
19439    use unicode_script::UnicodeScript;
19440    matches!(ch.script(), Han | Tangut | Yi)
19441}
19442
19443fn is_grapheme_ideographic(text: &str) -> bool {
19444    text.chars().any(is_char_ideographic)
19445}
19446
19447fn is_grapheme_whitespace(text: &str) -> bool {
19448    text.chars().any(|x| x.is_whitespace())
19449}
19450
19451fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19452    text.chars().next().map_or(false, |ch| {
19453        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19454    })
19455}
19456
19457#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19458enum WordBreakToken<'a> {
19459    Word { token: &'a str, grapheme_len: usize },
19460    InlineWhitespace { token: &'a str, grapheme_len: usize },
19461    Newline,
19462}
19463
19464impl<'a> Iterator for WordBreakingTokenizer<'a> {
19465    /// Yields a span, the count of graphemes in the token, and whether it was
19466    /// whitespace. Note that it also breaks at word boundaries.
19467    type Item = WordBreakToken<'a>;
19468
19469    fn next(&mut self) -> Option<Self::Item> {
19470        use unicode_segmentation::UnicodeSegmentation;
19471        if self.input.is_empty() {
19472            return None;
19473        }
19474
19475        let mut iter = self.input.graphemes(true).peekable();
19476        let mut offset = 0;
19477        let mut grapheme_len = 0;
19478        if let Some(first_grapheme) = iter.next() {
19479            let is_newline = first_grapheme == "\n";
19480            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19481            offset += first_grapheme.len();
19482            grapheme_len += 1;
19483            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19484                if let Some(grapheme) = iter.peek().copied() {
19485                    if should_stay_with_preceding_ideograph(grapheme) {
19486                        offset += grapheme.len();
19487                        grapheme_len += 1;
19488                    }
19489                }
19490            } else {
19491                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19492                let mut next_word_bound = words.peek().copied();
19493                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19494                    next_word_bound = words.next();
19495                }
19496                while let Some(grapheme) = iter.peek().copied() {
19497                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19498                        break;
19499                    };
19500                    if is_grapheme_whitespace(grapheme) != is_whitespace
19501                        || (grapheme == "\n") != is_newline
19502                    {
19503                        break;
19504                    };
19505                    offset += grapheme.len();
19506                    grapheme_len += 1;
19507                    iter.next();
19508                }
19509            }
19510            let token = &self.input[..offset];
19511            self.input = &self.input[offset..];
19512            if token == "\n" {
19513                Some(WordBreakToken::Newline)
19514            } else if is_whitespace {
19515                Some(WordBreakToken::InlineWhitespace {
19516                    token,
19517                    grapheme_len,
19518                })
19519            } else {
19520                Some(WordBreakToken::Word {
19521                    token,
19522                    grapheme_len,
19523                })
19524            }
19525        } else {
19526            None
19527        }
19528    }
19529}
19530
19531#[test]
19532fn test_word_breaking_tokenizer() {
19533    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19534        ("", &[]),
19535        ("  ", &[whitespace("  ", 2)]),
19536        ("Ʒ", &[word("Ʒ", 1)]),
19537        ("Ǽ", &[word("Ǽ", 1)]),
19538        ("", &[word("", 1)]),
19539        ("⋑⋑", &[word("⋑⋑", 2)]),
19540        (
19541            "原理,进而",
19542            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19543        ),
19544        (
19545            "hello world",
19546            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19547        ),
19548        (
19549            "hello, world",
19550            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19551        ),
19552        (
19553            "  hello world",
19554            &[
19555                whitespace("  ", 2),
19556                word("hello", 5),
19557                whitespace(" ", 1),
19558                word("world", 5),
19559            ],
19560        ),
19561        (
19562            "这是什么 \n 钢笔",
19563            &[
19564                word("", 1),
19565                word("", 1),
19566                word("", 1),
19567                word("", 1),
19568                whitespace(" ", 1),
19569                newline(),
19570                whitespace(" ", 1),
19571                word("", 1),
19572                word("", 1),
19573            ],
19574        ),
19575        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19576    ];
19577
19578    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19579        WordBreakToken::Word {
19580            token,
19581            grapheme_len,
19582        }
19583    }
19584
19585    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19586        WordBreakToken::InlineWhitespace {
19587            token,
19588            grapheme_len,
19589        }
19590    }
19591
19592    fn newline() -> WordBreakToken<'static> {
19593        WordBreakToken::Newline
19594    }
19595
19596    for (input, result) in tests {
19597        assert_eq!(
19598            WordBreakingTokenizer::new(input)
19599                .collect::<Vec<_>>()
19600                .as_slice(),
19601            *result,
19602        );
19603    }
19604}
19605
19606fn wrap_with_prefix(
19607    line_prefix: String,
19608    unwrapped_text: String,
19609    wrap_column: usize,
19610    tab_size: NonZeroU32,
19611    preserve_existing_whitespace: bool,
19612) -> String {
19613    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19614    let mut wrapped_text = String::new();
19615    let mut current_line = line_prefix.clone();
19616
19617    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19618    let mut current_line_len = line_prefix_len;
19619    let mut in_whitespace = false;
19620    for token in tokenizer {
19621        let have_preceding_whitespace = in_whitespace;
19622        match token {
19623            WordBreakToken::Word {
19624                token,
19625                grapheme_len,
19626            } => {
19627                in_whitespace = false;
19628                if current_line_len + grapheme_len > wrap_column
19629                    && current_line_len != line_prefix_len
19630                {
19631                    wrapped_text.push_str(current_line.trim_end());
19632                    wrapped_text.push('\n');
19633                    current_line.truncate(line_prefix.len());
19634                    current_line_len = line_prefix_len;
19635                }
19636                current_line.push_str(token);
19637                current_line_len += grapheme_len;
19638            }
19639            WordBreakToken::InlineWhitespace {
19640                mut token,
19641                mut grapheme_len,
19642            } => {
19643                in_whitespace = true;
19644                if have_preceding_whitespace && !preserve_existing_whitespace {
19645                    continue;
19646                }
19647                if !preserve_existing_whitespace {
19648                    token = " ";
19649                    grapheme_len = 1;
19650                }
19651                if current_line_len + grapheme_len > wrap_column {
19652                    wrapped_text.push_str(current_line.trim_end());
19653                    wrapped_text.push('\n');
19654                    current_line.truncate(line_prefix.len());
19655                    current_line_len = line_prefix_len;
19656                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19657                    current_line.push_str(token);
19658                    current_line_len += grapheme_len;
19659                }
19660            }
19661            WordBreakToken::Newline => {
19662                in_whitespace = true;
19663                if preserve_existing_whitespace {
19664                    wrapped_text.push_str(current_line.trim_end());
19665                    wrapped_text.push('\n');
19666                    current_line.truncate(line_prefix.len());
19667                    current_line_len = line_prefix_len;
19668                } else if have_preceding_whitespace {
19669                    continue;
19670                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19671                {
19672                    wrapped_text.push_str(current_line.trim_end());
19673                    wrapped_text.push('\n');
19674                    current_line.truncate(line_prefix.len());
19675                    current_line_len = line_prefix_len;
19676                } else if current_line_len != line_prefix_len {
19677                    current_line.push(' ');
19678                    current_line_len += 1;
19679                }
19680            }
19681        }
19682    }
19683
19684    if !current_line.is_empty() {
19685        wrapped_text.push_str(&current_line);
19686    }
19687    wrapped_text
19688}
19689
19690#[test]
19691fn test_wrap_with_prefix() {
19692    assert_eq!(
19693        wrap_with_prefix(
19694            "# ".to_string(),
19695            "abcdefg".to_string(),
19696            4,
19697            NonZeroU32::new(4).unwrap(),
19698            false,
19699        ),
19700        "# abcdefg"
19701    );
19702    assert_eq!(
19703        wrap_with_prefix(
19704            "".to_string(),
19705            "\thello world".to_string(),
19706            8,
19707            NonZeroU32::new(4).unwrap(),
19708            false,
19709        ),
19710        "hello\nworld"
19711    );
19712    assert_eq!(
19713        wrap_with_prefix(
19714            "// ".to_string(),
19715            "xx \nyy zz aa bb cc".to_string(),
19716            12,
19717            NonZeroU32::new(4).unwrap(),
19718            false,
19719        ),
19720        "// xx yy zz\n// aa bb cc"
19721    );
19722    assert_eq!(
19723        wrap_with_prefix(
19724            String::new(),
19725            "这是什么 \n 钢笔".to_string(),
19726            3,
19727            NonZeroU32::new(4).unwrap(),
19728            false,
19729        ),
19730        "这是什\n么 钢\n"
19731    );
19732}
19733
19734pub trait CollaborationHub {
19735    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19736    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19737    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19738}
19739
19740impl CollaborationHub for Entity<Project> {
19741    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19742        self.read(cx).collaborators()
19743    }
19744
19745    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19746        self.read(cx).user_store().read(cx).participant_indices()
19747    }
19748
19749    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19750        let this = self.read(cx);
19751        let user_ids = this.collaborators().values().map(|c| c.user_id);
19752        this.user_store().read_with(cx, |user_store, cx| {
19753            user_store.participant_names(user_ids, cx)
19754        })
19755    }
19756}
19757
19758pub trait SemanticsProvider {
19759    fn hover(
19760        &self,
19761        buffer: &Entity<Buffer>,
19762        position: text::Anchor,
19763        cx: &mut App,
19764    ) -> Option<Task<Vec<project::Hover>>>;
19765
19766    fn inline_values(
19767        &self,
19768        buffer_handle: Entity<Buffer>,
19769        range: Range<text::Anchor>,
19770        cx: &mut App,
19771    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19772
19773    fn inlay_hints(
19774        &self,
19775        buffer_handle: Entity<Buffer>,
19776        range: Range<text::Anchor>,
19777        cx: &mut App,
19778    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19779
19780    fn resolve_inlay_hint(
19781        &self,
19782        hint: InlayHint,
19783        buffer_handle: Entity<Buffer>,
19784        server_id: LanguageServerId,
19785        cx: &mut App,
19786    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19787
19788    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19789
19790    fn document_highlights(
19791        &self,
19792        buffer: &Entity<Buffer>,
19793        position: text::Anchor,
19794        cx: &mut App,
19795    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19796
19797    fn definitions(
19798        &self,
19799        buffer: &Entity<Buffer>,
19800        position: text::Anchor,
19801        kind: GotoDefinitionKind,
19802        cx: &mut App,
19803    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19804
19805    fn range_for_rename(
19806        &self,
19807        buffer: &Entity<Buffer>,
19808        position: text::Anchor,
19809        cx: &mut App,
19810    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19811
19812    fn perform_rename(
19813        &self,
19814        buffer: &Entity<Buffer>,
19815        position: text::Anchor,
19816        new_name: String,
19817        cx: &mut App,
19818    ) -> Option<Task<Result<ProjectTransaction>>>;
19819}
19820
19821pub trait CompletionProvider {
19822    fn completions(
19823        &self,
19824        excerpt_id: ExcerptId,
19825        buffer: &Entity<Buffer>,
19826        buffer_position: text::Anchor,
19827        trigger: CompletionContext,
19828        window: &mut Window,
19829        cx: &mut Context<Editor>,
19830    ) -> Task<Result<Option<Vec<Completion>>>>;
19831
19832    fn resolve_completions(
19833        &self,
19834        buffer: Entity<Buffer>,
19835        completion_indices: Vec<usize>,
19836        completions: Rc<RefCell<Box<[Completion]>>>,
19837        cx: &mut Context<Editor>,
19838    ) -> Task<Result<bool>>;
19839
19840    fn apply_additional_edits_for_completion(
19841        &self,
19842        _buffer: Entity<Buffer>,
19843        _completions: Rc<RefCell<Box<[Completion]>>>,
19844        _completion_index: usize,
19845        _push_to_history: bool,
19846        _cx: &mut Context<Editor>,
19847    ) -> Task<Result<Option<language::Transaction>>> {
19848        Task::ready(Ok(None))
19849    }
19850
19851    fn is_completion_trigger(
19852        &self,
19853        buffer: &Entity<Buffer>,
19854        position: language::Anchor,
19855        text: &str,
19856        trigger_in_words: bool,
19857        cx: &mut Context<Editor>,
19858    ) -> bool;
19859
19860    fn sort_completions(&self) -> bool {
19861        true
19862    }
19863
19864    fn filter_completions(&self) -> bool {
19865        true
19866    }
19867}
19868
19869pub trait CodeActionProvider {
19870    fn id(&self) -> Arc<str>;
19871
19872    fn code_actions(
19873        &self,
19874        buffer: &Entity<Buffer>,
19875        range: Range<text::Anchor>,
19876        window: &mut Window,
19877        cx: &mut App,
19878    ) -> Task<Result<Vec<CodeAction>>>;
19879
19880    fn apply_code_action(
19881        &self,
19882        buffer_handle: Entity<Buffer>,
19883        action: CodeAction,
19884        excerpt_id: ExcerptId,
19885        push_to_history: bool,
19886        window: &mut Window,
19887        cx: &mut App,
19888    ) -> Task<Result<ProjectTransaction>>;
19889}
19890
19891impl CodeActionProvider for Entity<Project> {
19892    fn id(&self) -> Arc<str> {
19893        "project".into()
19894    }
19895
19896    fn code_actions(
19897        &self,
19898        buffer: &Entity<Buffer>,
19899        range: Range<text::Anchor>,
19900        _window: &mut Window,
19901        cx: &mut App,
19902    ) -> Task<Result<Vec<CodeAction>>> {
19903        self.update(cx, |project, cx| {
19904            let code_lens = project.code_lens(buffer, range.clone(), cx);
19905            let code_actions = project.code_actions(buffer, range, None, cx);
19906            cx.background_spawn(async move {
19907                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19908                Ok(code_lens
19909                    .context("code lens fetch")?
19910                    .into_iter()
19911                    .chain(code_actions.context("code action fetch")?)
19912                    .collect())
19913            })
19914        })
19915    }
19916
19917    fn apply_code_action(
19918        &self,
19919        buffer_handle: Entity<Buffer>,
19920        action: CodeAction,
19921        _excerpt_id: ExcerptId,
19922        push_to_history: bool,
19923        _window: &mut Window,
19924        cx: &mut App,
19925    ) -> Task<Result<ProjectTransaction>> {
19926        self.update(cx, |project, cx| {
19927            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19928        })
19929    }
19930}
19931
19932fn snippet_completions(
19933    project: &Project,
19934    buffer: &Entity<Buffer>,
19935    buffer_position: text::Anchor,
19936    cx: &mut App,
19937) -> Task<Result<Vec<Completion>>> {
19938    let languages = buffer.read(cx).languages_at(buffer_position);
19939    let snippet_store = project.snippets().read(cx);
19940
19941    let scopes: Vec<_> = languages
19942        .iter()
19943        .filter_map(|language| {
19944            let language_name = language.lsp_id();
19945            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19946
19947            if snippets.is_empty() {
19948                None
19949            } else {
19950                Some((language.default_scope(), snippets))
19951            }
19952        })
19953        .collect();
19954
19955    if scopes.is_empty() {
19956        return Task::ready(Ok(vec![]));
19957    }
19958
19959    let snapshot = buffer.read(cx).text_snapshot();
19960    let chars: String = snapshot
19961        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19962        .collect();
19963    let executor = cx.background_executor().clone();
19964
19965    cx.background_spawn(async move {
19966        let mut all_results: Vec<Completion> = Vec::new();
19967        for (scope, snippets) in scopes.into_iter() {
19968            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19969            let mut last_word = chars
19970                .chars()
19971                .take_while(|c| classifier.is_word(*c))
19972                .collect::<String>();
19973            last_word = last_word.chars().rev().collect();
19974
19975            if last_word.is_empty() {
19976                return Ok(vec![]);
19977            }
19978
19979            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19980            let to_lsp = |point: &text::Anchor| {
19981                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19982                point_to_lsp(end)
19983            };
19984            let lsp_end = to_lsp(&buffer_position);
19985
19986            let candidates = snippets
19987                .iter()
19988                .enumerate()
19989                .flat_map(|(ix, snippet)| {
19990                    snippet
19991                        .prefix
19992                        .iter()
19993                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19994                })
19995                .collect::<Vec<StringMatchCandidate>>();
19996
19997            let mut matches = fuzzy::match_strings(
19998                &candidates,
19999                &last_word,
20000                last_word.chars().any(|c| c.is_uppercase()),
20001                100,
20002                &Default::default(),
20003                executor.clone(),
20004            )
20005            .await;
20006
20007            // Remove all candidates where the query's start does not match the start of any word in the candidate
20008            if let Some(query_start) = last_word.chars().next() {
20009                matches.retain(|string_match| {
20010                    split_words(&string_match.string).any(|word| {
20011                        // Check that the first codepoint of the word as lowercase matches the first
20012                        // codepoint of the query as lowercase
20013                        word.chars()
20014                            .flat_map(|codepoint| codepoint.to_lowercase())
20015                            .zip(query_start.to_lowercase())
20016                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20017                    })
20018                });
20019            }
20020
20021            let matched_strings = matches
20022                .into_iter()
20023                .map(|m| m.string)
20024                .collect::<HashSet<_>>();
20025
20026            let mut result: Vec<Completion> = snippets
20027                .iter()
20028                .filter_map(|snippet| {
20029                    let matching_prefix = snippet
20030                        .prefix
20031                        .iter()
20032                        .find(|prefix| matched_strings.contains(*prefix))?;
20033                    let start = as_offset - last_word.len();
20034                    let start = snapshot.anchor_before(start);
20035                    let range = start..buffer_position;
20036                    let lsp_start = to_lsp(&start);
20037                    let lsp_range = lsp::Range {
20038                        start: lsp_start,
20039                        end: lsp_end,
20040                    };
20041                    Some(Completion {
20042                        replace_range: range,
20043                        new_text: snippet.body.clone(),
20044                        source: CompletionSource::Lsp {
20045                            insert_range: None,
20046                            server_id: LanguageServerId(usize::MAX),
20047                            resolved: true,
20048                            lsp_completion: Box::new(lsp::CompletionItem {
20049                                label: snippet.prefix.first().unwrap().clone(),
20050                                kind: Some(CompletionItemKind::SNIPPET),
20051                                label_details: snippet.description.as_ref().map(|description| {
20052                                    lsp::CompletionItemLabelDetails {
20053                                        detail: Some(description.clone()),
20054                                        description: None,
20055                                    }
20056                                }),
20057                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20058                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20059                                    lsp::InsertReplaceEdit {
20060                                        new_text: snippet.body.clone(),
20061                                        insert: lsp_range,
20062                                        replace: lsp_range,
20063                                    },
20064                                )),
20065                                filter_text: Some(snippet.body.clone()),
20066                                sort_text: Some(char::MAX.to_string()),
20067                                ..lsp::CompletionItem::default()
20068                            }),
20069                            lsp_defaults: None,
20070                        },
20071                        label: CodeLabel {
20072                            text: matching_prefix.clone(),
20073                            runs: Vec::new(),
20074                            filter_range: 0..matching_prefix.len(),
20075                        },
20076                        icon_path: None,
20077                        documentation: Some(
20078                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20079                                single_line: snippet.name.clone().into(),
20080                                plain_text: snippet
20081                                    .description
20082                                    .clone()
20083                                    .map(|description| description.into()),
20084                            },
20085                        ),
20086                        insert_text_mode: None,
20087                        confirm: None,
20088                    })
20089                })
20090                .collect();
20091
20092            all_results.append(&mut result);
20093        }
20094
20095        Ok(all_results)
20096    })
20097}
20098
20099impl CompletionProvider for Entity<Project> {
20100    fn completions(
20101        &self,
20102        _excerpt_id: ExcerptId,
20103        buffer: &Entity<Buffer>,
20104        buffer_position: text::Anchor,
20105        options: CompletionContext,
20106        _window: &mut Window,
20107        cx: &mut Context<Editor>,
20108    ) -> Task<Result<Option<Vec<Completion>>>> {
20109        self.update(cx, |project, cx| {
20110            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20111            let project_completions = project.completions(buffer, buffer_position, options, cx);
20112            cx.background_spawn(async move {
20113                let snippets_completions = snippets.await?;
20114                match project_completions.await? {
20115                    Some(mut completions) => {
20116                        completions.extend(snippets_completions);
20117                        Ok(Some(completions))
20118                    }
20119                    None => {
20120                        if snippets_completions.is_empty() {
20121                            Ok(None)
20122                        } else {
20123                            Ok(Some(snippets_completions))
20124                        }
20125                    }
20126                }
20127            })
20128        })
20129    }
20130
20131    fn resolve_completions(
20132        &self,
20133        buffer: Entity<Buffer>,
20134        completion_indices: Vec<usize>,
20135        completions: Rc<RefCell<Box<[Completion]>>>,
20136        cx: &mut Context<Editor>,
20137    ) -> Task<Result<bool>> {
20138        self.update(cx, |project, cx| {
20139            project.lsp_store().update(cx, |lsp_store, cx| {
20140                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20141            })
20142        })
20143    }
20144
20145    fn apply_additional_edits_for_completion(
20146        &self,
20147        buffer: Entity<Buffer>,
20148        completions: Rc<RefCell<Box<[Completion]>>>,
20149        completion_index: usize,
20150        push_to_history: bool,
20151        cx: &mut Context<Editor>,
20152    ) -> Task<Result<Option<language::Transaction>>> {
20153        self.update(cx, |project, cx| {
20154            project.lsp_store().update(cx, |lsp_store, cx| {
20155                lsp_store.apply_additional_edits_for_completion(
20156                    buffer,
20157                    completions,
20158                    completion_index,
20159                    push_to_history,
20160                    cx,
20161                )
20162            })
20163        })
20164    }
20165
20166    fn is_completion_trigger(
20167        &self,
20168        buffer: &Entity<Buffer>,
20169        position: language::Anchor,
20170        text: &str,
20171        trigger_in_words: bool,
20172        cx: &mut Context<Editor>,
20173    ) -> bool {
20174        let mut chars = text.chars();
20175        let char = if let Some(char) = chars.next() {
20176            char
20177        } else {
20178            return false;
20179        };
20180        if chars.next().is_some() {
20181            return false;
20182        }
20183
20184        let buffer = buffer.read(cx);
20185        let snapshot = buffer.snapshot();
20186        if !snapshot.settings_at(position, cx).show_completions_on_input {
20187            return false;
20188        }
20189        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20190        if trigger_in_words && classifier.is_word(char) {
20191            return true;
20192        }
20193
20194        buffer.completion_triggers().contains(text)
20195    }
20196}
20197
20198impl SemanticsProvider for Entity<Project> {
20199    fn hover(
20200        &self,
20201        buffer: &Entity<Buffer>,
20202        position: text::Anchor,
20203        cx: &mut App,
20204    ) -> Option<Task<Vec<project::Hover>>> {
20205        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20206    }
20207
20208    fn document_highlights(
20209        &self,
20210        buffer: &Entity<Buffer>,
20211        position: text::Anchor,
20212        cx: &mut App,
20213    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20214        Some(self.update(cx, |project, cx| {
20215            project.document_highlights(buffer, position, cx)
20216        }))
20217    }
20218
20219    fn definitions(
20220        &self,
20221        buffer: &Entity<Buffer>,
20222        position: text::Anchor,
20223        kind: GotoDefinitionKind,
20224        cx: &mut App,
20225    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20226        Some(self.update(cx, |project, cx| match kind {
20227            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20228            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20229            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20230            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20231        }))
20232    }
20233
20234    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20235        // TODO: make this work for remote projects
20236        self.update(cx, |project, cx| {
20237            if project
20238                .active_debug_session(cx)
20239                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20240            {
20241                return true;
20242            }
20243
20244            buffer.update(cx, |buffer, cx| {
20245                project.any_language_server_supports_inlay_hints(buffer, cx)
20246            })
20247        })
20248    }
20249
20250    fn inline_values(
20251        &self,
20252        buffer_handle: Entity<Buffer>,
20253
20254        range: Range<text::Anchor>,
20255        cx: &mut App,
20256    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20257        self.update(cx, |project, cx| {
20258            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20259
20260            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20261        })
20262    }
20263
20264    fn inlay_hints(
20265        &self,
20266        buffer_handle: Entity<Buffer>,
20267        range: Range<text::Anchor>,
20268        cx: &mut App,
20269    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20270        Some(self.update(cx, |project, cx| {
20271            project.inlay_hints(buffer_handle, range, cx)
20272        }))
20273    }
20274
20275    fn resolve_inlay_hint(
20276        &self,
20277        hint: InlayHint,
20278        buffer_handle: Entity<Buffer>,
20279        server_id: LanguageServerId,
20280        cx: &mut App,
20281    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20282        Some(self.update(cx, |project, cx| {
20283            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20284        }))
20285    }
20286
20287    fn range_for_rename(
20288        &self,
20289        buffer: &Entity<Buffer>,
20290        position: text::Anchor,
20291        cx: &mut App,
20292    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20293        Some(self.update(cx, |project, cx| {
20294            let buffer = buffer.clone();
20295            let task = project.prepare_rename(buffer.clone(), position, cx);
20296            cx.spawn(async move |_, cx| {
20297                Ok(match task.await? {
20298                    PrepareRenameResponse::Success(range) => Some(range),
20299                    PrepareRenameResponse::InvalidPosition => None,
20300                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20301                        // Fallback on using TreeSitter info to determine identifier range
20302                        buffer.update(cx, |buffer, _| {
20303                            let snapshot = buffer.snapshot();
20304                            let (range, kind) = snapshot.surrounding_word(position);
20305                            if kind != Some(CharKind::Word) {
20306                                return None;
20307                            }
20308                            Some(
20309                                snapshot.anchor_before(range.start)
20310                                    ..snapshot.anchor_after(range.end),
20311                            )
20312                        })?
20313                    }
20314                })
20315            })
20316        }))
20317    }
20318
20319    fn perform_rename(
20320        &self,
20321        buffer: &Entity<Buffer>,
20322        position: text::Anchor,
20323        new_name: String,
20324        cx: &mut App,
20325    ) -> Option<Task<Result<ProjectTransaction>>> {
20326        Some(self.update(cx, |project, cx| {
20327            project.perform_rename(buffer.clone(), position, new_name, cx)
20328        }))
20329    }
20330}
20331
20332fn inlay_hint_settings(
20333    location: Anchor,
20334    snapshot: &MultiBufferSnapshot,
20335    cx: &mut Context<Editor>,
20336) -> InlayHintSettings {
20337    let file = snapshot.file_at(location);
20338    let language = snapshot.language_at(location).map(|l| l.name());
20339    language_settings(language, file, cx).inlay_hints
20340}
20341
20342fn consume_contiguous_rows(
20343    contiguous_row_selections: &mut Vec<Selection<Point>>,
20344    selection: &Selection<Point>,
20345    display_map: &DisplaySnapshot,
20346    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20347) -> (MultiBufferRow, MultiBufferRow) {
20348    contiguous_row_selections.push(selection.clone());
20349    let start_row = MultiBufferRow(selection.start.row);
20350    let mut end_row = ending_row(selection, display_map);
20351
20352    while let Some(next_selection) = selections.peek() {
20353        if next_selection.start.row <= end_row.0 {
20354            end_row = ending_row(next_selection, display_map);
20355            contiguous_row_selections.push(selections.next().unwrap().clone());
20356        } else {
20357            break;
20358        }
20359    }
20360    (start_row, end_row)
20361}
20362
20363fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20364    if next_selection.end.column > 0 || next_selection.is_empty() {
20365        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20366    } else {
20367        MultiBufferRow(next_selection.end.row)
20368    }
20369}
20370
20371impl EditorSnapshot {
20372    pub fn remote_selections_in_range<'a>(
20373        &'a self,
20374        range: &'a Range<Anchor>,
20375        collaboration_hub: &dyn CollaborationHub,
20376        cx: &'a App,
20377    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20378        let participant_names = collaboration_hub.user_names(cx);
20379        let participant_indices = collaboration_hub.user_participant_indices(cx);
20380        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20381        let collaborators_by_replica_id = collaborators_by_peer_id
20382            .values()
20383            .map(|collaborator| (collaborator.replica_id, collaborator))
20384            .collect::<HashMap<_, _>>();
20385        self.buffer_snapshot
20386            .selections_in_range(range, false)
20387            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20388                if replica_id == AGENT_REPLICA_ID {
20389                    Some(RemoteSelection {
20390                        replica_id,
20391                        selection,
20392                        cursor_shape,
20393                        line_mode,
20394                        collaborator_id: CollaboratorId::Agent,
20395                        user_name: Some("Agent".into()),
20396                        color: cx.theme().players().agent(),
20397                    })
20398                } else {
20399                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20400                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20401                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20402                    Some(RemoteSelection {
20403                        replica_id,
20404                        selection,
20405                        cursor_shape,
20406                        line_mode,
20407                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20408                        user_name,
20409                        color: if let Some(index) = participant_index {
20410                            cx.theme().players().color_for_participant(index.0)
20411                        } else {
20412                            cx.theme().players().absent()
20413                        },
20414                    })
20415                }
20416            })
20417    }
20418
20419    pub fn hunks_for_ranges(
20420        &self,
20421        ranges: impl IntoIterator<Item = Range<Point>>,
20422    ) -> Vec<MultiBufferDiffHunk> {
20423        let mut hunks = Vec::new();
20424        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20425            HashMap::default();
20426        for query_range in ranges {
20427            let query_rows =
20428                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20429            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20430                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20431            ) {
20432                // Include deleted hunks that are adjacent to the query range, because
20433                // otherwise they would be missed.
20434                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20435                if hunk.status().is_deleted() {
20436                    intersects_range |= hunk.row_range.start == query_rows.end;
20437                    intersects_range |= hunk.row_range.end == query_rows.start;
20438                }
20439                if intersects_range {
20440                    if !processed_buffer_rows
20441                        .entry(hunk.buffer_id)
20442                        .or_default()
20443                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20444                    {
20445                        continue;
20446                    }
20447                    hunks.push(hunk);
20448                }
20449            }
20450        }
20451
20452        hunks
20453    }
20454
20455    fn display_diff_hunks_for_rows<'a>(
20456        &'a self,
20457        display_rows: Range<DisplayRow>,
20458        folded_buffers: &'a HashSet<BufferId>,
20459    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20460        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20461        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20462
20463        self.buffer_snapshot
20464            .diff_hunks_in_range(buffer_start..buffer_end)
20465            .filter_map(|hunk| {
20466                if folded_buffers.contains(&hunk.buffer_id) {
20467                    return None;
20468                }
20469
20470                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20471                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20472
20473                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20474                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20475
20476                let display_hunk = if hunk_display_start.column() != 0 {
20477                    DisplayDiffHunk::Folded {
20478                        display_row: hunk_display_start.row(),
20479                    }
20480                } else {
20481                    let mut end_row = hunk_display_end.row();
20482                    if hunk_display_end.column() > 0 {
20483                        end_row.0 += 1;
20484                    }
20485                    let is_created_file = hunk.is_created_file();
20486                    DisplayDiffHunk::Unfolded {
20487                        status: hunk.status(),
20488                        diff_base_byte_range: hunk.diff_base_byte_range,
20489                        display_row_range: hunk_display_start.row()..end_row,
20490                        multi_buffer_range: Anchor::range_in_buffer(
20491                            hunk.excerpt_id,
20492                            hunk.buffer_id,
20493                            hunk.buffer_range,
20494                        ),
20495                        is_created_file,
20496                    }
20497                };
20498
20499                Some(display_hunk)
20500            })
20501    }
20502
20503    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20504        self.display_snapshot.buffer_snapshot.language_at(position)
20505    }
20506
20507    pub fn is_focused(&self) -> bool {
20508        self.is_focused
20509    }
20510
20511    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20512        self.placeholder_text.as_ref()
20513    }
20514
20515    pub fn scroll_position(&self) -> gpui::Point<f32> {
20516        self.scroll_anchor.scroll_position(&self.display_snapshot)
20517    }
20518
20519    fn gutter_dimensions(
20520        &self,
20521        font_id: FontId,
20522        font_size: Pixels,
20523        max_line_number_width: Pixels,
20524        cx: &App,
20525    ) -> Option<GutterDimensions> {
20526        if !self.show_gutter {
20527            return None;
20528        }
20529
20530        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20531        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20532
20533        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20534            matches!(
20535                ProjectSettings::get_global(cx).git.git_gutter,
20536                Some(GitGutterSetting::TrackedFiles)
20537            )
20538        });
20539        let gutter_settings = EditorSettings::get_global(cx).gutter;
20540        let show_line_numbers = self
20541            .show_line_numbers
20542            .unwrap_or(gutter_settings.line_numbers);
20543        let line_gutter_width = if show_line_numbers {
20544            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20545            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20546            max_line_number_width.max(min_width_for_number_on_gutter)
20547        } else {
20548            0.0.into()
20549        };
20550
20551        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20552        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20553
20554        let git_blame_entries_width =
20555            self.git_blame_gutter_max_author_length
20556                .map(|max_author_length| {
20557                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20558                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20559
20560                    /// The number of characters to dedicate to gaps and margins.
20561                    const SPACING_WIDTH: usize = 4;
20562
20563                    let max_char_count = max_author_length.min(renderer.max_author_length())
20564                        + ::git::SHORT_SHA_LENGTH
20565                        + MAX_RELATIVE_TIMESTAMP.len()
20566                        + SPACING_WIDTH;
20567
20568                    em_advance * max_char_count
20569                });
20570
20571        let is_singleton = self.buffer_snapshot.is_singleton();
20572
20573        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20574        left_padding += if !is_singleton {
20575            em_width * 4.0
20576        } else if show_runnables || show_breakpoints {
20577            em_width * 3.0
20578        } else if show_git_gutter && show_line_numbers {
20579            em_width * 2.0
20580        } else if show_git_gutter || show_line_numbers {
20581            em_width
20582        } else {
20583            px(0.)
20584        };
20585
20586        let shows_folds = is_singleton && gutter_settings.folds;
20587
20588        let right_padding = if shows_folds && show_line_numbers {
20589            em_width * 4.0
20590        } else if shows_folds || (!is_singleton && show_line_numbers) {
20591            em_width * 3.0
20592        } else if show_line_numbers {
20593            em_width
20594        } else {
20595            px(0.)
20596        };
20597
20598        Some(GutterDimensions {
20599            left_padding,
20600            right_padding,
20601            width: line_gutter_width + left_padding + right_padding,
20602            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20603            git_blame_entries_width,
20604        })
20605    }
20606
20607    pub fn render_crease_toggle(
20608        &self,
20609        buffer_row: MultiBufferRow,
20610        row_contains_cursor: bool,
20611        editor: Entity<Editor>,
20612        window: &mut Window,
20613        cx: &mut App,
20614    ) -> Option<AnyElement> {
20615        let folded = self.is_line_folded(buffer_row);
20616        let mut is_foldable = false;
20617
20618        if let Some(crease) = self
20619            .crease_snapshot
20620            .query_row(buffer_row, &self.buffer_snapshot)
20621        {
20622            is_foldable = true;
20623            match crease {
20624                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20625                    if let Some(render_toggle) = render_toggle {
20626                        let toggle_callback =
20627                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20628                                if folded {
20629                                    editor.update(cx, |editor, cx| {
20630                                        editor.fold_at(buffer_row, window, cx)
20631                                    });
20632                                } else {
20633                                    editor.update(cx, |editor, cx| {
20634                                        editor.unfold_at(buffer_row, window, cx)
20635                                    });
20636                                }
20637                            });
20638                        return Some((render_toggle)(
20639                            buffer_row,
20640                            folded,
20641                            toggle_callback,
20642                            window,
20643                            cx,
20644                        ));
20645                    }
20646                }
20647            }
20648        }
20649
20650        is_foldable |= self.starts_indent(buffer_row);
20651
20652        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20653            Some(
20654                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20655                    .toggle_state(folded)
20656                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20657                        if folded {
20658                            this.unfold_at(buffer_row, window, cx);
20659                        } else {
20660                            this.fold_at(buffer_row, window, cx);
20661                        }
20662                    }))
20663                    .into_any_element(),
20664            )
20665        } else {
20666            None
20667        }
20668    }
20669
20670    pub fn render_crease_trailer(
20671        &self,
20672        buffer_row: MultiBufferRow,
20673        window: &mut Window,
20674        cx: &mut App,
20675    ) -> Option<AnyElement> {
20676        let folded = self.is_line_folded(buffer_row);
20677        if let Crease::Inline { render_trailer, .. } = self
20678            .crease_snapshot
20679            .query_row(buffer_row, &self.buffer_snapshot)?
20680        {
20681            let render_trailer = render_trailer.as_ref()?;
20682            Some(render_trailer(buffer_row, folded, window, cx))
20683        } else {
20684            None
20685        }
20686    }
20687}
20688
20689impl Deref for EditorSnapshot {
20690    type Target = DisplaySnapshot;
20691
20692    fn deref(&self) -> &Self::Target {
20693        &self.display_snapshot
20694    }
20695}
20696
20697#[derive(Clone, Debug, PartialEq, Eq)]
20698pub enum EditorEvent {
20699    InputIgnored {
20700        text: Arc<str>,
20701    },
20702    InputHandled {
20703        utf16_range_to_replace: Option<Range<isize>>,
20704        text: Arc<str>,
20705    },
20706    ExcerptsAdded {
20707        buffer: Entity<Buffer>,
20708        predecessor: ExcerptId,
20709        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20710    },
20711    ExcerptsRemoved {
20712        ids: Vec<ExcerptId>,
20713        removed_buffer_ids: Vec<BufferId>,
20714    },
20715    BufferFoldToggled {
20716        ids: Vec<ExcerptId>,
20717        folded: bool,
20718    },
20719    ExcerptsEdited {
20720        ids: Vec<ExcerptId>,
20721    },
20722    ExcerptsExpanded {
20723        ids: Vec<ExcerptId>,
20724    },
20725    BufferEdited,
20726    Edited {
20727        transaction_id: clock::Lamport,
20728    },
20729    Reparsed(BufferId),
20730    Focused,
20731    FocusedIn,
20732    Blurred,
20733    DirtyChanged,
20734    Saved,
20735    TitleChanged,
20736    DiffBaseChanged,
20737    SelectionsChanged {
20738        local: bool,
20739    },
20740    ScrollPositionChanged {
20741        local: bool,
20742        autoscroll: bool,
20743    },
20744    Closed,
20745    TransactionUndone {
20746        transaction_id: clock::Lamport,
20747    },
20748    TransactionBegun {
20749        transaction_id: clock::Lamport,
20750    },
20751    Reloaded,
20752    CursorShapeChanged,
20753    PushedToNavHistory {
20754        anchor: Anchor,
20755        is_deactivate: bool,
20756    },
20757}
20758
20759impl EventEmitter<EditorEvent> for Editor {}
20760
20761impl Focusable for Editor {
20762    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20763        self.focus_handle.clone()
20764    }
20765}
20766
20767impl Render for Editor {
20768    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20769        let settings = ThemeSettings::get_global(cx);
20770
20771        let mut text_style = match self.mode {
20772            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20773                color: cx.theme().colors().editor_foreground,
20774                font_family: settings.ui_font.family.clone(),
20775                font_features: settings.ui_font.features.clone(),
20776                font_fallbacks: settings.ui_font.fallbacks.clone(),
20777                font_size: rems(0.875).into(),
20778                font_weight: settings.ui_font.weight,
20779                line_height: relative(settings.buffer_line_height.value()),
20780                ..Default::default()
20781            },
20782            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20783                color: cx.theme().colors().editor_foreground,
20784                font_family: settings.buffer_font.family.clone(),
20785                font_features: settings.buffer_font.features.clone(),
20786                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20787                font_size: settings.buffer_font_size(cx).into(),
20788                font_weight: settings.buffer_font.weight,
20789                line_height: relative(settings.buffer_line_height.value()),
20790                ..Default::default()
20791            },
20792        };
20793        if let Some(text_style_refinement) = &self.text_style_refinement {
20794            text_style.refine(text_style_refinement)
20795        }
20796
20797        let background = match self.mode {
20798            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20799            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20800            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20801            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20802        };
20803
20804        EditorElement::new(
20805            &cx.entity(),
20806            EditorStyle {
20807                background,
20808                local_player: cx.theme().players().local(),
20809                text: text_style,
20810                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20811                syntax: cx.theme().syntax().clone(),
20812                status: cx.theme().status().clone(),
20813                inlay_hints_style: make_inlay_hints_style(cx),
20814                inline_completion_styles: make_suggestion_styles(cx),
20815                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20816                show_underlines: !self.mode.is_minimap(),
20817            },
20818        )
20819    }
20820}
20821
20822impl EntityInputHandler for Editor {
20823    fn text_for_range(
20824        &mut self,
20825        range_utf16: Range<usize>,
20826        adjusted_range: &mut Option<Range<usize>>,
20827        _: &mut Window,
20828        cx: &mut Context<Self>,
20829    ) -> Option<String> {
20830        let snapshot = self.buffer.read(cx).read(cx);
20831        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20832        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20833        if (start.0..end.0) != range_utf16 {
20834            adjusted_range.replace(start.0..end.0);
20835        }
20836        Some(snapshot.text_for_range(start..end).collect())
20837    }
20838
20839    fn selected_text_range(
20840        &mut self,
20841        ignore_disabled_input: bool,
20842        _: &mut Window,
20843        cx: &mut Context<Self>,
20844    ) -> Option<UTF16Selection> {
20845        // Prevent the IME menu from appearing when holding down an alphabetic key
20846        // while input is disabled.
20847        if !ignore_disabled_input && !self.input_enabled {
20848            return None;
20849        }
20850
20851        let selection = self.selections.newest::<OffsetUtf16>(cx);
20852        let range = selection.range();
20853
20854        Some(UTF16Selection {
20855            range: range.start.0..range.end.0,
20856            reversed: selection.reversed,
20857        })
20858    }
20859
20860    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20861        let snapshot = self.buffer.read(cx).read(cx);
20862        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20863        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20864    }
20865
20866    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20867        self.clear_highlights::<InputComposition>(cx);
20868        self.ime_transaction.take();
20869    }
20870
20871    fn replace_text_in_range(
20872        &mut self,
20873        range_utf16: Option<Range<usize>>,
20874        text: &str,
20875        window: &mut Window,
20876        cx: &mut Context<Self>,
20877    ) {
20878        if !self.input_enabled {
20879            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20880            return;
20881        }
20882
20883        self.transact(window, cx, |this, window, cx| {
20884            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20885                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20886                Some(this.selection_replacement_ranges(range_utf16, cx))
20887            } else {
20888                this.marked_text_ranges(cx)
20889            };
20890
20891            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20892                let newest_selection_id = this.selections.newest_anchor().id;
20893                this.selections
20894                    .all::<OffsetUtf16>(cx)
20895                    .iter()
20896                    .zip(ranges_to_replace.iter())
20897                    .find_map(|(selection, range)| {
20898                        if selection.id == newest_selection_id {
20899                            Some(
20900                                (range.start.0 as isize - selection.head().0 as isize)
20901                                    ..(range.end.0 as isize - selection.head().0 as isize),
20902                            )
20903                        } else {
20904                            None
20905                        }
20906                    })
20907            });
20908
20909            cx.emit(EditorEvent::InputHandled {
20910                utf16_range_to_replace: range_to_replace,
20911                text: text.into(),
20912            });
20913
20914            if let Some(new_selected_ranges) = new_selected_ranges {
20915                this.change_selections(None, window, cx, |selections| {
20916                    selections.select_ranges(new_selected_ranges)
20917                });
20918                this.backspace(&Default::default(), window, cx);
20919            }
20920
20921            this.handle_input(text, window, cx);
20922        });
20923
20924        if let Some(transaction) = self.ime_transaction {
20925            self.buffer.update(cx, |buffer, cx| {
20926                buffer.group_until_transaction(transaction, cx);
20927            });
20928        }
20929
20930        self.unmark_text(window, cx);
20931    }
20932
20933    fn replace_and_mark_text_in_range(
20934        &mut self,
20935        range_utf16: Option<Range<usize>>,
20936        text: &str,
20937        new_selected_range_utf16: Option<Range<usize>>,
20938        window: &mut Window,
20939        cx: &mut Context<Self>,
20940    ) {
20941        if !self.input_enabled {
20942            return;
20943        }
20944
20945        let transaction = self.transact(window, cx, |this, window, cx| {
20946            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20947                let snapshot = this.buffer.read(cx).read(cx);
20948                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20949                    for marked_range in &mut marked_ranges {
20950                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20951                        marked_range.start.0 += relative_range_utf16.start;
20952                        marked_range.start =
20953                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20954                        marked_range.end =
20955                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20956                    }
20957                }
20958                Some(marked_ranges)
20959            } else if let Some(range_utf16) = range_utf16 {
20960                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20961                Some(this.selection_replacement_ranges(range_utf16, cx))
20962            } else {
20963                None
20964            };
20965
20966            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20967                let newest_selection_id = this.selections.newest_anchor().id;
20968                this.selections
20969                    .all::<OffsetUtf16>(cx)
20970                    .iter()
20971                    .zip(ranges_to_replace.iter())
20972                    .find_map(|(selection, range)| {
20973                        if selection.id == newest_selection_id {
20974                            Some(
20975                                (range.start.0 as isize - selection.head().0 as isize)
20976                                    ..(range.end.0 as isize - selection.head().0 as isize),
20977                            )
20978                        } else {
20979                            None
20980                        }
20981                    })
20982            });
20983
20984            cx.emit(EditorEvent::InputHandled {
20985                utf16_range_to_replace: range_to_replace,
20986                text: text.into(),
20987            });
20988
20989            if let Some(ranges) = ranges_to_replace {
20990                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20991            }
20992
20993            let marked_ranges = {
20994                let snapshot = this.buffer.read(cx).read(cx);
20995                this.selections
20996                    .disjoint_anchors()
20997                    .iter()
20998                    .map(|selection| {
20999                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21000                    })
21001                    .collect::<Vec<_>>()
21002            };
21003
21004            if text.is_empty() {
21005                this.unmark_text(window, cx);
21006            } else {
21007                this.highlight_text::<InputComposition>(
21008                    marked_ranges.clone(),
21009                    HighlightStyle {
21010                        underline: Some(UnderlineStyle {
21011                            thickness: px(1.),
21012                            color: None,
21013                            wavy: false,
21014                        }),
21015                        ..Default::default()
21016                    },
21017                    cx,
21018                );
21019            }
21020
21021            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21022            let use_autoclose = this.use_autoclose;
21023            let use_auto_surround = this.use_auto_surround;
21024            this.set_use_autoclose(false);
21025            this.set_use_auto_surround(false);
21026            this.handle_input(text, window, cx);
21027            this.set_use_autoclose(use_autoclose);
21028            this.set_use_auto_surround(use_auto_surround);
21029
21030            if let Some(new_selected_range) = new_selected_range_utf16 {
21031                let snapshot = this.buffer.read(cx).read(cx);
21032                let new_selected_ranges = marked_ranges
21033                    .into_iter()
21034                    .map(|marked_range| {
21035                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21036                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21037                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21038                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21039                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21040                    })
21041                    .collect::<Vec<_>>();
21042
21043                drop(snapshot);
21044                this.change_selections(None, window, cx, |selections| {
21045                    selections.select_ranges(new_selected_ranges)
21046                });
21047            }
21048        });
21049
21050        self.ime_transaction = self.ime_transaction.or(transaction);
21051        if let Some(transaction) = self.ime_transaction {
21052            self.buffer.update(cx, |buffer, cx| {
21053                buffer.group_until_transaction(transaction, cx);
21054            });
21055        }
21056
21057        if self.text_highlights::<InputComposition>(cx).is_none() {
21058            self.ime_transaction.take();
21059        }
21060    }
21061
21062    fn bounds_for_range(
21063        &mut self,
21064        range_utf16: Range<usize>,
21065        element_bounds: gpui::Bounds<Pixels>,
21066        window: &mut Window,
21067        cx: &mut Context<Self>,
21068    ) -> Option<gpui::Bounds<Pixels>> {
21069        let text_layout_details = self.text_layout_details(window);
21070        let gpui::Size {
21071            width: em_width,
21072            height: line_height,
21073        } = self.character_size(window);
21074
21075        let snapshot = self.snapshot(window, cx);
21076        let scroll_position = snapshot.scroll_position();
21077        let scroll_left = scroll_position.x * em_width;
21078
21079        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21080        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21081            + self.gutter_dimensions.width
21082            + self.gutter_dimensions.margin;
21083        let y = line_height * (start.row().as_f32() - scroll_position.y);
21084
21085        Some(Bounds {
21086            origin: element_bounds.origin + point(x, y),
21087            size: size(em_width, line_height),
21088        })
21089    }
21090
21091    fn character_index_for_point(
21092        &mut self,
21093        point: gpui::Point<Pixels>,
21094        _window: &mut Window,
21095        _cx: &mut Context<Self>,
21096    ) -> Option<usize> {
21097        let position_map = self.last_position_map.as_ref()?;
21098        if !position_map.text_hitbox.contains(&point) {
21099            return None;
21100        }
21101        let display_point = position_map.point_for_position(point).previous_valid;
21102        let anchor = position_map
21103            .snapshot
21104            .display_point_to_anchor(display_point, Bias::Left);
21105        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21106        Some(utf16_offset.0)
21107    }
21108}
21109
21110trait SelectionExt {
21111    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21112    fn spanned_rows(
21113        &self,
21114        include_end_if_at_line_start: bool,
21115        map: &DisplaySnapshot,
21116    ) -> Range<MultiBufferRow>;
21117}
21118
21119impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21120    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21121        let start = self
21122            .start
21123            .to_point(&map.buffer_snapshot)
21124            .to_display_point(map);
21125        let end = self
21126            .end
21127            .to_point(&map.buffer_snapshot)
21128            .to_display_point(map);
21129        if self.reversed {
21130            end..start
21131        } else {
21132            start..end
21133        }
21134    }
21135
21136    fn spanned_rows(
21137        &self,
21138        include_end_if_at_line_start: bool,
21139        map: &DisplaySnapshot,
21140    ) -> Range<MultiBufferRow> {
21141        let start = self.start.to_point(&map.buffer_snapshot);
21142        let mut end = self.end.to_point(&map.buffer_snapshot);
21143        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21144            end.row -= 1;
21145        }
21146
21147        let buffer_start = map.prev_line_boundary(start).0;
21148        let buffer_end = map.next_line_boundary(end).0;
21149        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21150    }
21151}
21152
21153impl<T: InvalidationRegion> InvalidationStack<T> {
21154    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21155    where
21156        S: Clone + ToOffset,
21157    {
21158        while let Some(region) = self.last() {
21159            let all_selections_inside_invalidation_ranges =
21160                if selections.len() == region.ranges().len() {
21161                    selections
21162                        .iter()
21163                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21164                        .all(|(selection, invalidation_range)| {
21165                            let head = selection.head().to_offset(buffer);
21166                            invalidation_range.start <= head && invalidation_range.end >= head
21167                        })
21168                } else {
21169                    false
21170                };
21171
21172            if all_selections_inside_invalidation_ranges {
21173                break;
21174            } else {
21175                self.pop();
21176            }
21177        }
21178    }
21179}
21180
21181impl<T> Default for InvalidationStack<T> {
21182    fn default() -> Self {
21183        Self(Default::default())
21184    }
21185}
21186
21187impl<T> Deref for InvalidationStack<T> {
21188    type Target = Vec<T>;
21189
21190    fn deref(&self) -> &Self::Target {
21191        &self.0
21192    }
21193}
21194
21195impl<T> DerefMut for InvalidationStack<T> {
21196    fn deref_mut(&mut self) -> &mut Self::Target {
21197        &mut self.0
21198    }
21199}
21200
21201impl InvalidationRegion for SnippetState {
21202    fn ranges(&self) -> &[Range<Anchor>] {
21203        &self.ranges[self.active_index]
21204    }
21205}
21206
21207fn inline_completion_edit_text(
21208    current_snapshot: &BufferSnapshot,
21209    edits: &[(Range<Anchor>, String)],
21210    edit_preview: &EditPreview,
21211    include_deletions: bool,
21212    cx: &App,
21213) -> HighlightedText {
21214    let edits = edits
21215        .iter()
21216        .map(|(anchor, text)| {
21217            (
21218                anchor.start.text_anchor..anchor.end.text_anchor,
21219                text.clone(),
21220            )
21221        })
21222        .collect::<Vec<_>>();
21223
21224    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21225}
21226
21227pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21228    match severity {
21229        lsp::DiagnosticSeverity::ERROR => colors.error,
21230        lsp::DiagnosticSeverity::WARNING => colors.warning,
21231        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21232        lsp::DiagnosticSeverity::HINT => colors.info,
21233        _ => colors.ignored,
21234    }
21235}
21236
21237pub fn styled_runs_for_code_label<'a>(
21238    label: &'a CodeLabel,
21239    syntax_theme: &'a theme::SyntaxTheme,
21240) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21241    let fade_out = HighlightStyle {
21242        fade_out: Some(0.35),
21243        ..Default::default()
21244    };
21245
21246    let mut prev_end = label.filter_range.end;
21247    label
21248        .runs
21249        .iter()
21250        .enumerate()
21251        .flat_map(move |(ix, (range, highlight_id))| {
21252            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21253                style
21254            } else {
21255                return Default::default();
21256            };
21257            let mut muted_style = style;
21258            muted_style.highlight(fade_out);
21259
21260            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21261            if range.start >= label.filter_range.end {
21262                if range.start > prev_end {
21263                    runs.push((prev_end..range.start, fade_out));
21264                }
21265                runs.push((range.clone(), muted_style));
21266            } else if range.end <= label.filter_range.end {
21267                runs.push((range.clone(), style));
21268            } else {
21269                runs.push((range.start..label.filter_range.end, style));
21270                runs.push((label.filter_range.end..range.end, muted_style));
21271            }
21272            prev_end = cmp::max(prev_end, range.end);
21273
21274            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21275                runs.push((prev_end..label.text.len(), fade_out));
21276            }
21277
21278            runs
21279        })
21280}
21281
21282pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21283    let mut prev_index = 0;
21284    let mut prev_codepoint: Option<char> = None;
21285    text.char_indices()
21286        .chain([(text.len(), '\0')])
21287        .filter_map(move |(index, codepoint)| {
21288            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21289            let is_boundary = index == text.len()
21290                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21291                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21292            if is_boundary {
21293                let chunk = &text[prev_index..index];
21294                prev_index = index;
21295                Some(chunk)
21296            } else {
21297                None
21298            }
21299        })
21300}
21301
21302pub trait RangeToAnchorExt: Sized {
21303    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21304
21305    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21306        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21307        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21308    }
21309}
21310
21311impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21312    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21313        let start_offset = self.start.to_offset(snapshot);
21314        let end_offset = self.end.to_offset(snapshot);
21315        if start_offset == end_offset {
21316            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21317        } else {
21318            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21319        }
21320    }
21321}
21322
21323pub trait RowExt {
21324    fn as_f32(&self) -> f32;
21325
21326    fn next_row(&self) -> Self;
21327
21328    fn previous_row(&self) -> Self;
21329
21330    fn minus(&self, other: Self) -> u32;
21331}
21332
21333impl RowExt for DisplayRow {
21334    fn as_f32(&self) -> f32 {
21335        self.0 as f32
21336    }
21337
21338    fn next_row(&self) -> Self {
21339        Self(self.0 + 1)
21340    }
21341
21342    fn previous_row(&self) -> Self {
21343        Self(self.0.saturating_sub(1))
21344    }
21345
21346    fn minus(&self, other: Self) -> u32 {
21347        self.0 - other.0
21348    }
21349}
21350
21351impl RowExt for MultiBufferRow {
21352    fn as_f32(&self) -> f32 {
21353        self.0 as f32
21354    }
21355
21356    fn next_row(&self) -> Self {
21357        Self(self.0 + 1)
21358    }
21359
21360    fn previous_row(&self) -> Self {
21361        Self(self.0.saturating_sub(1))
21362    }
21363
21364    fn minus(&self, other: Self) -> u32 {
21365        self.0 - other.0
21366    }
21367}
21368
21369trait RowRangeExt {
21370    type Row;
21371
21372    fn len(&self) -> usize;
21373
21374    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21375}
21376
21377impl RowRangeExt for Range<MultiBufferRow> {
21378    type Row = MultiBufferRow;
21379
21380    fn len(&self) -> usize {
21381        (self.end.0 - self.start.0) as usize
21382    }
21383
21384    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21385        (self.start.0..self.end.0).map(MultiBufferRow)
21386    }
21387}
21388
21389impl RowRangeExt for Range<DisplayRow> {
21390    type Row = DisplayRow;
21391
21392    fn len(&self) -> usize {
21393        (self.end.0 - self.start.0) as usize
21394    }
21395
21396    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21397        (self.start.0..self.end.0).map(DisplayRow)
21398    }
21399}
21400
21401/// If select range has more than one line, we
21402/// just point the cursor to range.start.
21403fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21404    if range.start.row == range.end.row {
21405        range
21406    } else {
21407        range.start..range.start
21408    }
21409}
21410pub struct KillRing(ClipboardItem);
21411impl Global for KillRing {}
21412
21413const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21414
21415enum BreakpointPromptEditAction {
21416    Log,
21417    Condition,
21418    HitCondition,
21419}
21420
21421struct BreakpointPromptEditor {
21422    pub(crate) prompt: Entity<Editor>,
21423    editor: WeakEntity<Editor>,
21424    breakpoint_anchor: Anchor,
21425    breakpoint: Breakpoint,
21426    edit_action: BreakpointPromptEditAction,
21427    block_ids: HashSet<CustomBlockId>,
21428    editor_margins: Arc<Mutex<EditorMargins>>,
21429    _subscriptions: Vec<Subscription>,
21430}
21431
21432impl BreakpointPromptEditor {
21433    const MAX_LINES: u8 = 4;
21434
21435    fn new(
21436        editor: WeakEntity<Editor>,
21437        breakpoint_anchor: Anchor,
21438        breakpoint: Breakpoint,
21439        edit_action: BreakpointPromptEditAction,
21440        window: &mut Window,
21441        cx: &mut Context<Self>,
21442    ) -> Self {
21443        let base_text = match edit_action {
21444            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21445            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21446            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21447        }
21448        .map(|msg| msg.to_string())
21449        .unwrap_or_default();
21450
21451        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21452        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21453
21454        let prompt = cx.new(|cx| {
21455            let mut prompt = Editor::new(
21456                EditorMode::AutoHeight {
21457                    max_lines: Self::MAX_LINES as usize,
21458                },
21459                buffer,
21460                None,
21461                window,
21462                cx,
21463            );
21464            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21465            prompt.set_show_cursor_when_unfocused(false, cx);
21466            prompt.set_placeholder_text(
21467                match edit_action {
21468                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21469                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21470                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21471                },
21472                cx,
21473            );
21474
21475            prompt
21476        });
21477
21478        Self {
21479            prompt,
21480            editor,
21481            breakpoint_anchor,
21482            breakpoint,
21483            edit_action,
21484            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21485            block_ids: Default::default(),
21486            _subscriptions: vec![],
21487        }
21488    }
21489
21490    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21491        self.block_ids.extend(block_ids)
21492    }
21493
21494    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21495        if let Some(editor) = self.editor.upgrade() {
21496            let message = self
21497                .prompt
21498                .read(cx)
21499                .buffer
21500                .read(cx)
21501                .as_singleton()
21502                .expect("A multi buffer in breakpoint prompt isn't possible")
21503                .read(cx)
21504                .as_rope()
21505                .to_string();
21506
21507            editor.update(cx, |editor, cx| {
21508                editor.edit_breakpoint_at_anchor(
21509                    self.breakpoint_anchor,
21510                    self.breakpoint.clone(),
21511                    match self.edit_action {
21512                        BreakpointPromptEditAction::Log => {
21513                            BreakpointEditAction::EditLogMessage(message.into())
21514                        }
21515                        BreakpointPromptEditAction::Condition => {
21516                            BreakpointEditAction::EditCondition(message.into())
21517                        }
21518                        BreakpointPromptEditAction::HitCondition => {
21519                            BreakpointEditAction::EditHitCondition(message.into())
21520                        }
21521                    },
21522                    cx,
21523                );
21524
21525                editor.remove_blocks(self.block_ids.clone(), None, cx);
21526                cx.focus_self(window);
21527            });
21528        }
21529    }
21530
21531    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21532        self.editor
21533            .update(cx, |editor, cx| {
21534                editor.remove_blocks(self.block_ids.clone(), None, cx);
21535                window.focus(&editor.focus_handle);
21536            })
21537            .log_err();
21538    }
21539
21540    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21541        let settings = ThemeSettings::get_global(cx);
21542        let text_style = TextStyle {
21543            color: if self.prompt.read(cx).read_only(cx) {
21544                cx.theme().colors().text_disabled
21545            } else {
21546                cx.theme().colors().text
21547            },
21548            font_family: settings.buffer_font.family.clone(),
21549            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21550            font_size: settings.buffer_font_size(cx).into(),
21551            font_weight: settings.buffer_font.weight,
21552            line_height: relative(settings.buffer_line_height.value()),
21553            ..Default::default()
21554        };
21555        EditorElement::new(
21556            &self.prompt,
21557            EditorStyle {
21558                background: cx.theme().colors().editor_background,
21559                local_player: cx.theme().players().local(),
21560                text: text_style,
21561                ..Default::default()
21562            },
21563        )
21564    }
21565}
21566
21567impl Render for BreakpointPromptEditor {
21568    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21569        let editor_margins = *self.editor_margins.lock();
21570        let gutter_dimensions = editor_margins.gutter;
21571        h_flex()
21572            .key_context("Editor")
21573            .bg(cx.theme().colors().editor_background)
21574            .border_y_1()
21575            .border_color(cx.theme().status().info_border)
21576            .size_full()
21577            .py(window.line_height() / 2.5)
21578            .on_action(cx.listener(Self::confirm))
21579            .on_action(cx.listener(Self::cancel))
21580            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21581            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21582    }
21583}
21584
21585impl Focusable for BreakpointPromptEditor {
21586    fn focus_handle(&self, cx: &App) -> FocusHandle {
21587        self.prompt.focus_handle(cx)
21588    }
21589}
21590
21591fn all_edits_insertions_or_deletions(
21592    edits: &Vec<(Range<Anchor>, String)>,
21593    snapshot: &MultiBufferSnapshot,
21594) -> bool {
21595    let mut all_insertions = true;
21596    let mut all_deletions = true;
21597
21598    for (range, new_text) in edits.iter() {
21599        let range_is_empty = range.to_offset(&snapshot).is_empty();
21600        let text_is_empty = new_text.is_empty();
21601
21602        if range_is_empty != text_is_empty {
21603            if range_is_empty {
21604                all_deletions = false;
21605            } else {
21606                all_insertions = false;
21607            }
21608        } else {
21609            return false;
21610        }
21611
21612        if !all_insertions && !all_deletions {
21613            return false;
21614        }
21615    }
21616    all_insertions || all_deletions
21617}
21618
21619struct MissingEditPredictionKeybindingTooltip;
21620
21621impl Render for MissingEditPredictionKeybindingTooltip {
21622    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21623        ui::tooltip_container(window, cx, |container, _, cx| {
21624            container
21625                .flex_shrink_0()
21626                .max_w_80()
21627                .min_h(rems_from_px(124.))
21628                .justify_between()
21629                .child(
21630                    v_flex()
21631                        .flex_1()
21632                        .text_ui_sm(cx)
21633                        .child(Label::new("Conflict with Accept Keybinding"))
21634                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21635                )
21636                .child(
21637                    h_flex()
21638                        .pb_1()
21639                        .gap_1()
21640                        .items_end()
21641                        .w_full()
21642                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21643                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21644                        }))
21645                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21646                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21647                        })),
21648                )
21649        })
21650    }
21651}
21652
21653#[derive(Debug, Clone, Copy, PartialEq)]
21654pub struct LineHighlight {
21655    pub background: Background,
21656    pub border: Option<gpui::Hsla>,
21657    pub include_gutter: bool,
21658    pub type_id: Option<TypeId>,
21659}
21660
21661fn render_diff_hunk_controls(
21662    row: u32,
21663    status: &DiffHunkStatus,
21664    hunk_range: Range<Anchor>,
21665    is_created_file: bool,
21666    line_height: Pixels,
21667    editor: &Entity<Editor>,
21668    _window: &mut Window,
21669    cx: &mut App,
21670) -> AnyElement {
21671    h_flex()
21672        .h(line_height)
21673        .mr_1()
21674        .gap_1()
21675        .px_0p5()
21676        .pb_1()
21677        .border_x_1()
21678        .border_b_1()
21679        .border_color(cx.theme().colors().border_variant)
21680        .rounded_b_lg()
21681        .bg(cx.theme().colors().editor_background)
21682        .gap_1()
21683        .occlude()
21684        .shadow_md()
21685        .child(if status.has_secondary_hunk() {
21686            Button::new(("stage", row as u64), "Stage")
21687                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21688                .tooltip({
21689                    let focus_handle = editor.focus_handle(cx);
21690                    move |window, cx| {
21691                        Tooltip::for_action_in(
21692                            "Stage Hunk",
21693                            &::git::ToggleStaged,
21694                            &focus_handle,
21695                            window,
21696                            cx,
21697                        )
21698                    }
21699                })
21700                .on_click({
21701                    let editor = editor.clone();
21702                    move |_event, _window, cx| {
21703                        editor.update(cx, |editor, cx| {
21704                            editor.stage_or_unstage_diff_hunks(
21705                                true,
21706                                vec![hunk_range.start..hunk_range.start],
21707                                cx,
21708                            );
21709                        });
21710                    }
21711                })
21712        } else {
21713            Button::new(("unstage", row as u64), "Unstage")
21714                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21715                .tooltip({
21716                    let focus_handle = editor.focus_handle(cx);
21717                    move |window, cx| {
21718                        Tooltip::for_action_in(
21719                            "Unstage Hunk",
21720                            &::git::ToggleStaged,
21721                            &focus_handle,
21722                            window,
21723                            cx,
21724                        )
21725                    }
21726                })
21727                .on_click({
21728                    let editor = editor.clone();
21729                    move |_event, _window, cx| {
21730                        editor.update(cx, |editor, cx| {
21731                            editor.stage_or_unstage_diff_hunks(
21732                                false,
21733                                vec![hunk_range.start..hunk_range.start],
21734                                cx,
21735                            );
21736                        });
21737                    }
21738                })
21739        })
21740        .child(
21741            Button::new(("restore", row as u64), "Restore")
21742                .tooltip({
21743                    let focus_handle = editor.focus_handle(cx);
21744                    move |window, cx| {
21745                        Tooltip::for_action_in(
21746                            "Restore Hunk",
21747                            &::git::Restore,
21748                            &focus_handle,
21749                            window,
21750                            cx,
21751                        )
21752                    }
21753                })
21754                .on_click({
21755                    let editor = editor.clone();
21756                    move |_event, window, cx| {
21757                        editor.update(cx, |editor, cx| {
21758                            let snapshot = editor.snapshot(window, cx);
21759                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21760                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21761                        });
21762                    }
21763                })
21764                .disabled(is_created_file),
21765        )
21766        .when(
21767            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21768            |el| {
21769                el.child(
21770                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21771                        .shape(IconButtonShape::Square)
21772                        .icon_size(IconSize::Small)
21773                        // .disabled(!has_multiple_hunks)
21774                        .tooltip({
21775                            let focus_handle = editor.focus_handle(cx);
21776                            move |window, cx| {
21777                                Tooltip::for_action_in(
21778                                    "Next Hunk",
21779                                    &GoToHunk,
21780                                    &focus_handle,
21781                                    window,
21782                                    cx,
21783                                )
21784                            }
21785                        })
21786                        .on_click({
21787                            let editor = editor.clone();
21788                            move |_event, window, cx| {
21789                                editor.update(cx, |editor, cx| {
21790                                    let snapshot = editor.snapshot(window, cx);
21791                                    let position =
21792                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21793                                    editor.go_to_hunk_before_or_after_position(
21794                                        &snapshot,
21795                                        position,
21796                                        Direction::Next,
21797                                        window,
21798                                        cx,
21799                                    );
21800                                    editor.expand_selected_diff_hunks(cx);
21801                                });
21802                            }
21803                        }),
21804                )
21805                .child(
21806                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21807                        .shape(IconButtonShape::Square)
21808                        .icon_size(IconSize::Small)
21809                        // .disabled(!has_multiple_hunks)
21810                        .tooltip({
21811                            let focus_handle = editor.focus_handle(cx);
21812                            move |window, cx| {
21813                                Tooltip::for_action_in(
21814                                    "Previous Hunk",
21815                                    &GoToPreviousHunk,
21816                                    &focus_handle,
21817                                    window,
21818                                    cx,
21819                                )
21820                            }
21821                        })
21822                        .on_click({
21823                            let editor = editor.clone();
21824                            move |_event, window, cx| {
21825                                editor.update(cx, |editor, cx| {
21826                                    let snapshot = editor.snapshot(window, cx);
21827                                    let point =
21828                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21829                                    editor.go_to_hunk_before_or_after_position(
21830                                        &snapshot,
21831                                        point,
21832                                        Direction::Prev,
21833                                        window,
21834                                        cx,
21835                                    );
21836                                    editor.expand_selected_diff_hunks(cx);
21837                                });
21838                            }
21839                        }),
21840                )
21841            },
21842        )
21843        .into_any_element()
21844}