editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, SearchSettings,
   67    ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt,
   78    future::{self, Shared, join},
   79};
   80use fuzzy::StringMatchCandidate;
   81
   82use ::git::blame::BlameEntry;
   83use ::git::{Restore, blame::ParsedCommitMessage};
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use git::blame::{GitBlame, GlobalBlameRenderer};
   89use gpui::{
   90    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   91    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   92    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   93    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   94    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   95    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   96    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   97    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   98};
   99use highlight_matching_bracket::refresh_matching_bracket_highlights;
  100use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  101pub use hover_popover::hover_markdown_style;
  102use hover_popover::{HoverState, hide_hover};
  103use indent_guides::ActiveIndentGuidesState;
  104use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  105pub use inline_completion::Direction;
  106use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  107pub use items::MAX_TAB_TITLE_LEN;
  108use itertools::Itertools;
  109use language::{
  110    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  111    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  112    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  113    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  114    language_settings::{
  115        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  116        all_language_settings, language_settings,
  117    },
  118    point_from_lsp, text_diff_with_options,
  119};
  120use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  121use linked_editing_ranges::refresh_linked_ranges;
  122use markdown::Markdown;
  123use mouse_context_menu::MouseContextMenu;
  124use persistence::DB;
  125use project::{
  126    BreakpointWithPosition, ProjectPath,
  127    debugger::{
  128        breakpoint_store::{
  129            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  130            BreakpointStoreEvent,
  131        },
  132        session::{Session, SessionEvent},
  133    },
  134    project_settings::DiagnosticSeverity,
  135};
  136
  137pub use git::blame::BlameRenderer;
  138pub use proposed_changes_editor::{
  139    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  140};
  141use smallvec::smallvec;
  142use std::{cell::OnceCell, iter::Peekable, ops::Not};
  143use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  144
  145pub use lsp::CompletionContext;
  146use lsp::{
  147    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  148    LanguageServerId, LanguageServerName,
  149};
  150
  151use language::BufferSnapshot;
  152pub use lsp_ext::lsp_tasks;
  153use movement::TextLayoutDetails;
  154pub use multi_buffer::{
  155    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  156    RowInfo, ToOffset, ToPoint,
  157};
  158use multi_buffer::{
  159    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  160    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  161};
  162use parking_lot::Mutex;
  163use project::{
  164    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  165    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  166    TaskSourceKind,
  167    debugger::breakpoint_store::Breakpoint,
  168    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  169    project_settings::{GitGutterSetting, ProjectSettings},
  170};
  171use rand::prelude::*;
  172use rpc::{ErrorExt, proto::*};
  173use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  174use selections_collection::{
  175    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  176};
  177use serde::{Deserialize, Serialize};
  178use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  179use smallvec::SmallVec;
  180use snippet::Snippet;
  181use std::sync::Arc;
  182use std::{
  183    any::TypeId,
  184    borrow::Cow,
  185    cell::RefCell,
  186    cmp::{self, Ordering, Reverse},
  187    mem,
  188    num::NonZeroU32,
  189    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  190    path::{Path, PathBuf},
  191    rc::Rc,
  192    time::{Duration, Instant},
  193};
  194pub use sum_tree::Bias;
  195use sum_tree::TreeMap;
  196use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  197use theme::{
  198    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  199    observe_buffer_font_size_adjustment,
  200};
  201use ui::{
  202    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  203    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  204};
  205use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  206use workspace::{
  207    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  208    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  209    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  210    item::{ItemHandle, PreviewTabsSettings},
  211    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  212    searchable::SearchEvent,
  213};
  214
  215use crate::hover_links::{find_url, find_url_from_range};
  216use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  217
  218pub const FILE_HEADER_HEIGHT: u32 = 2;
  219pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  220pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  221const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  222const MAX_LINE_LEN: usize = 1024;
  223const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  224const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  225pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  226#[doc(hidden)]
  227pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  228const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  229
  230pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  233
  234pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  235pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  236pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  237pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  238
  239pub type RenderDiffHunkControlsFn = Arc<
  240    dyn Fn(
  241        u32,
  242        &DiffHunkStatus,
  243        Range<Anchor>,
  244        bool,
  245        Pixels,
  246        &Entity<Editor>,
  247        &mut Window,
  248        &mut App,
  249    ) -> AnyElement,
  250>;
  251
  252const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  253    alt: true,
  254    shift: true,
  255    control: false,
  256    platform: false,
  257    function: false,
  258};
  259
  260struct InlineValueCache {
  261    enabled: bool,
  262    inlays: Vec<InlayId>,
  263    refresh_task: Task<Option<()>>,
  264}
  265
  266impl InlineValueCache {
  267    fn new(enabled: bool) -> Self {
  268        Self {
  269            enabled,
  270            inlays: Vec::new(),
  271            refresh_task: Task::ready(None),
  272        }
  273    }
  274}
  275
  276#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  277pub enum InlayId {
  278    InlineCompletion(usize),
  279    Hint(usize),
  280    DebuggerValue(usize),
  281}
  282
  283impl InlayId {
  284    fn id(&self) -> usize {
  285        match self {
  286            Self::InlineCompletion(id) => *id,
  287            Self::Hint(id) => *id,
  288            Self::DebuggerValue(id) => *id,
  289        }
  290    }
  291}
  292
  293pub enum ActiveDebugLine {}
  294pub enum DebugStackFrameLine {}
  295enum DocumentHighlightRead {}
  296enum DocumentHighlightWrite {}
  297enum InputComposition {}
  298enum SelectedTextHighlight {}
  299
  300pub enum ConflictsOuter {}
  301pub enum ConflictsOurs {}
  302pub enum ConflictsTheirs {}
  303pub enum ConflictsOursMarker {}
  304pub enum ConflictsTheirsMarker {}
  305
  306#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  307pub enum Navigated {
  308    Yes,
  309    No,
  310}
  311
  312impl Navigated {
  313    pub fn from_bool(yes: bool) -> Navigated {
  314        if yes { Navigated::Yes } else { Navigated::No }
  315    }
  316}
  317
  318#[derive(Debug, Clone, PartialEq, Eq)]
  319enum DisplayDiffHunk {
  320    Folded {
  321        display_row: DisplayRow,
  322    },
  323    Unfolded {
  324        is_created_file: bool,
  325        diff_base_byte_range: Range<usize>,
  326        display_row_range: Range<DisplayRow>,
  327        multi_buffer_range: Range<Anchor>,
  328        status: DiffHunkStatus,
  329    },
  330}
  331
  332pub enum HideMouseCursorOrigin {
  333    TypingAction,
  334    MovementAction,
  335}
  336
  337pub fn init_settings(cx: &mut App) {
  338    EditorSettings::register(cx);
  339}
  340
  341pub fn init(cx: &mut App) {
  342    init_settings(cx);
  343
  344    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  345
  346    workspace::register_project_item::<Editor>(cx);
  347    workspace::FollowableViewRegistry::register::<Editor>(cx);
  348    workspace::register_serializable_item::<Editor>(cx);
  349
  350    cx.observe_new(
  351        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  352            workspace.register_action(Editor::new_file);
  353            workspace.register_action(Editor::new_file_vertical);
  354            workspace.register_action(Editor::new_file_horizontal);
  355            workspace.register_action(Editor::cancel_language_server_work);
  356        },
  357    )
  358    .detach();
  359
  360    cx.on_action(move |_: &workspace::NewFile, cx| {
  361        let app_state = workspace::AppState::global(cx);
  362        if let Some(app_state) = app_state.upgrade() {
  363            workspace::open_new(
  364                Default::default(),
  365                app_state,
  366                cx,
  367                |workspace, window, cx| {
  368                    Editor::new_file(workspace, &Default::default(), window, cx)
  369                },
  370            )
  371            .detach();
  372        }
  373    });
  374    cx.on_action(move |_: &workspace::NewWindow, cx| {
  375        let app_state = workspace::AppState::global(cx);
  376        if let Some(app_state) = app_state.upgrade() {
  377            workspace::open_new(
  378                Default::default(),
  379                app_state,
  380                cx,
  381                |workspace, window, cx| {
  382                    cx.activate(true);
  383                    Editor::new_file(workspace, &Default::default(), window, cx)
  384                },
  385            )
  386            .detach();
  387        }
  388    });
  389}
  390
  391pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  392    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  393}
  394
  395pub trait DiagnosticRenderer {
  396    fn render_group(
  397        &self,
  398        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  399        buffer_id: BufferId,
  400        snapshot: EditorSnapshot,
  401        editor: WeakEntity<Editor>,
  402        cx: &mut App,
  403    ) -> Vec<BlockProperties<Anchor>>;
  404
  405    fn render_hover(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  408        range: Range<Point>,
  409        buffer_id: BufferId,
  410        cx: &mut App,
  411    ) -> Option<Entity<markdown::Markdown>>;
  412
  413    fn open_link(
  414        &self,
  415        editor: &mut Editor,
  416        link: SharedString,
  417        window: &mut Window,
  418        cx: &mut Context<Editor>,
  419    );
  420}
  421
  422pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  423
  424impl GlobalDiagnosticRenderer {
  425    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  426        cx.try_global::<Self>().map(|g| g.0.clone())
  427    }
  428}
  429
  430impl gpui::Global for GlobalDiagnosticRenderer {}
  431pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  432    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  433}
  434
  435pub struct SearchWithinRange;
  436
  437trait InvalidationRegion {
  438    fn ranges(&self) -> &[Range<Anchor>];
  439}
  440
  441#[derive(Clone, Debug, PartialEq)]
  442pub enum SelectPhase {
  443    Begin {
  444        position: DisplayPoint,
  445        add: bool,
  446        click_count: usize,
  447    },
  448    BeginColumnar {
  449        position: DisplayPoint,
  450        reset: bool,
  451        goal_column: u32,
  452    },
  453    Extend {
  454        position: DisplayPoint,
  455        click_count: usize,
  456    },
  457    Update {
  458        position: DisplayPoint,
  459        goal_column: u32,
  460        scroll_delta: gpui::Point<f32>,
  461    },
  462    End,
  463}
  464
  465#[derive(Clone, Debug)]
  466pub enum SelectMode {
  467    Character,
  468    Word(Range<Anchor>),
  469    Line(Range<Anchor>),
  470    All,
  471}
  472
  473#[derive(Clone, PartialEq, Eq, Debug)]
  474pub enum EditorMode {
  475    SingleLine {
  476        auto_width: bool,
  477    },
  478    AutoHeight {
  479        max_lines: usize,
  480    },
  481    Full {
  482        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  483        scale_ui_elements_with_buffer_font_size: bool,
  484        /// When set to `true`, the editor will render a background for the active line.
  485        show_active_line_background: bool,
  486        /// When set to `true`, the editor's height will be determined by its content.
  487        sized_by_content: bool,
  488    },
  489    Minimap {
  490        parent: WeakEntity<Editor>,
  491    },
  492}
  493
  494impl EditorMode {
  495    pub fn full() -> Self {
  496        Self::Full {
  497            scale_ui_elements_with_buffer_font_size: true,
  498            show_active_line_background: true,
  499            sized_by_content: false,
  500        }
  501    }
  502
  503    pub fn is_full(&self) -> bool {
  504        matches!(self, Self::Full { .. })
  505    }
  506
  507    fn is_minimap(&self) -> bool {
  508        matches!(self, Self::Minimap { .. })
  509    }
  510}
  511
  512#[derive(Copy, Clone, Debug)]
  513pub enum SoftWrap {
  514    /// Prefer not to wrap at all.
  515    ///
  516    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  517    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  518    GitDiff,
  519    /// Prefer a single line generally, unless an overly long line is encountered.
  520    None,
  521    /// Soft wrap lines that exceed the editor width.
  522    EditorWidth,
  523    /// Soft wrap lines at the preferred line length.
  524    Column(u32),
  525    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  526    Bounded(u32),
  527}
  528
  529#[derive(Clone)]
  530pub struct EditorStyle {
  531    pub background: Hsla,
  532    pub local_player: PlayerColor,
  533    pub text: TextStyle,
  534    pub scrollbar_width: Pixels,
  535    pub syntax: Arc<SyntaxTheme>,
  536    pub status: StatusColors,
  537    pub inlay_hints_style: HighlightStyle,
  538    pub inline_completion_styles: InlineCompletionStyles,
  539    pub unnecessary_code_fade: f32,
  540    pub show_underlines: bool,
  541}
  542
  543impl Default for EditorStyle {
  544    fn default() -> Self {
  545        Self {
  546            background: Hsla::default(),
  547            local_player: PlayerColor::default(),
  548            text: TextStyle::default(),
  549            scrollbar_width: Pixels::default(),
  550            syntax: Default::default(),
  551            // HACK: Status colors don't have a real default.
  552            // We should look into removing the status colors from the editor
  553            // style and retrieve them directly from the theme.
  554            status: StatusColors::dark(),
  555            inlay_hints_style: HighlightStyle::default(),
  556            inline_completion_styles: InlineCompletionStyles {
  557                insertion: HighlightStyle::default(),
  558                whitespace: HighlightStyle::default(),
  559            },
  560            unnecessary_code_fade: Default::default(),
  561            show_underlines: true,
  562        }
  563    }
  564}
  565
  566pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  567    let show_background = language_settings::language_settings(None, None, cx)
  568        .inlay_hints
  569        .show_background;
  570
  571    HighlightStyle {
  572        color: Some(cx.theme().status().hint),
  573        background_color: show_background.then(|| cx.theme().status().hint_background),
  574        ..HighlightStyle::default()
  575    }
  576}
  577
  578pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  579    InlineCompletionStyles {
  580        insertion: HighlightStyle {
  581            color: Some(cx.theme().status().predictive),
  582            ..HighlightStyle::default()
  583        },
  584        whitespace: HighlightStyle {
  585            background_color: Some(cx.theme().status().created_background),
  586            ..HighlightStyle::default()
  587        },
  588    }
  589}
  590
  591type CompletionId = usize;
  592
  593pub(crate) enum EditDisplayMode {
  594    TabAccept,
  595    DiffPopover,
  596    Inline,
  597}
  598
  599enum InlineCompletion {
  600    Edit {
  601        edits: Vec<(Range<Anchor>, String)>,
  602        edit_preview: Option<EditPreview>,
  603        display_mode: EditDisplayMode,
  604        snapshot: BufferSnapshot,
  605    },
  606    Move {
  607        target: Anchor,
  608        snapshot: BufferSnapshot,
  609    },
  610}
  611
  612struct InlineCompletionState {
  613    inlay_ids: Vec<InlayId>,
  614    completion: InlineCompletion,
  615    completion_id: Option<SharedString>,
  616    invalidation_range: Range<Anchor>,
  617}
  618
  619enum EditPredictionSettings {
  620    Disabled,
  621    Enabled {
  622        show_in_menu: bool,
  623        preview_requires_modifier: bool,
  624    },
  625}
  626
  627enum InlineCompletionHighlight {}
  628
  629#[derive(Debug, Clone)]
  630struct InlineDiagnostic {
  631    message: SharedString,
  632    group_id: usize,
  633    is_primary: bool,
  634    start: Point,
  635    severity: lsp::DiagnosticSeverity,
  636}
  637
  638pub enum MenuInlineCompletionsPolicy {
  639    Never,
  640    ByProvider,
  641}
  642
  643pub enum EditPredictionPreview {
  644    /// Modifier is not pressed
  645    Inactive { released_too_fast: bool },
  646    /// Modifier pressed
  647    Active {
  648        since: Instant,
  649        previous_scroll_position: Option<ScrollAnchor>,
  650    },
  651}
  652
  653impl EditPredictionPreview {
  654    pub fn released_too_fast(&self) -> bool {
  655        match self {
  656            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  657            EditPredictionPreview::Active { .. } => false,
  658        }
  659    }
  660
  661    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  662        if let EditPredictionPreview::Active {
  663            previous_scroll_position,
  664            ..
  665        } = self
  666        {
  667            *previous_scroll_position = scroll_position;
  668        }
  669    }
  670}
  671
  672pub struct ContextMenuOptions {
  673    pub min_entries_visible: usize,
  674    pub max_entries_visible: usize,
  675    pub placement: Option<ContextMenuPlacement>,
  676}
  677
  678#[derive(Debug, Clone, PartialEq, Eq)]
  679pub enum ContextMenuPlacement {
  680    Above,
  681    Below,
  682}
  683
  684#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  685struct EditorActionId(usize);
  686
  687impl EditorActionId {
  688    pub fn post_inc(&mut self) -> Self {
  689        let answer = self.0;
  690
  691        *self = Self(answer + 1);
  692
  693        Self(answer)
  694    }
  695}
  696
  697// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  698// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  699
  700type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  701type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  702
  703#[derive(Default)]
  704struct ScrollbarMarkerState {
  705    scrollbar_size: Size<Pixels>,
  706    dirty: bool,
  707    markers: Arc<[PaintQuad]>,
  708    pending_refresh: Option<Task<Result<()>>>,
  709}
  710
  711impl ScrollbarMarkerState {
  712    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  713        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  714    }
  715}
  716
  717#[derive(Clone, Copy, PartialEq, Eq)]
  718pub enum MinimapVisibility {
  719    Disabled,
  720    Enabled(bool),
  721}
  722
  723impl MinimapVisibility {
  724    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  725        if mode.is_full() {
  726            Self::Enabled(EditorSettings::get_global(cx).minimap.minimap_enabled())
  727        } else {
  728            Self::Disabled
  729        }
  730    }
  731
  732    fn disabled(&self) -> bool {
  733        match *self {
  734            Self::Disabled => true,
  735            _ => false,
  736        }
  737    }
  738
  739    fn visible(&self) -> bool {
  740        match *self {
  741            Self::Enabled(visible) => visible,
  742            _ => false,
  743        }
  744    }
  745
  746    fn toggle_visibility(&self) -> Self {
  747        match *self {
  748            Self::Enabled(visible) => Self::Enabled(!visible),
  749            Self::Disabled => Self::Disabled,
  750        }
  751    }
  752}
  753
  754#[derive(Clone, Debug)]
  755struct RunnableTasks {
  756    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  757    offset: multi_buffer::Anchor,
  758    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  759    column: u32,
  760    // Values of all named captures, including those starting with '_'
  761    extra_variables: HashMap<String, String>,
  762    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  763    context_range: Range<BufferOffset>,
  764}
  765
  766impl RunnableTasks {
  767    fn resolve<'a>(
  768        &'a self,
  769        cx: &'a task::TaskContext,
  770    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  771        self.templates.iter().filter_map(|(kind, template)| {
  772            template
  773                .resolve_task(&kind.to_id_base(), cx)
  774                .map(|task| (kind.clone(), task))
  775        })
  776    }
  777}
  778
  779#[derive(Clone)]
  780struct ResolvedTasks {
  781    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  782    position: Anchor,
  783}
  784
  785#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  786struct BufferOffset(usize);
  787
  788// Addons allow storing per-editor state in other crates (e.g. Vim)
  789pub trait Addon: 'static {
  790    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  791
  792    fn render_buffer_header_controls(
  793        &self,
  794        _: &ExcerptInfo,
  795        _: &Window,
  796        _: &App,
  797    ) -> Option<AnyElement> {
  798        None
  799    }
  800
  801    fn to_any(&self) -> &dyn std::any::Any;
  802
  803    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  804        None
  805    }
  806}
  807
  808/// A set of caret positions, registered when the editor was edited.
  809pub struct ChangeList {
  810    changes: Vec<Vec<Anchor>>,
  811    /// Currently "selected" change.
  812    position: Option<usize>,
  813}
  814
  815impl ChangeList {
  816    pub fn new() -> Self {
  817        Self {
  818            changes: Vec::new(),
  819            position: None,
  820        }
  821    }
  822
  823    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  824    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  825    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  826        if self.changes.is_empty() {
  827            return None;
  828        }
  829
  830        let prev = self.position.unwrap_or(self.changes.len());
  831        let next = if direction == Direction::Prev {
  832            prev.saturating_sub(count)
  833        } else {
  834            (prev + count).min(self.changes.len() - 1)
  835        };
  836        self.position = Some(next);
  837        self.changes.get(next).map(|anchors| anchors.as_slice())
  838    }
  839
  840    /// Adds a new change to the list, resetting the change list position.
  841    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  842        self.position.take();
  843        if pop_state {
  844            self.changes.pop();
  845        }
  846        self.changes.push(new_positions.clone());
  847    }
  848
  849    pub fn last(&self) -> Option<&[Anchor]> {
  850        self.changes.last().map(|anchors| anchors.as_slice())
  851    }
  852}
  853
  854#[derive(Clone)]
  855struct InlineBlamePopoverState {
  856    scroll_handle: ScrollHandle,
  857    commit_message: Option<ParsedCommitMessage>,
  858    markdown: Entity<Markdown>,
  859}
  860
  861struct InlineBlamePopover {
  862    position: gpui::Point<Pixels>,
  863    show_task: Option<Task<()>>,
  864    hide_task: Option<Task<()>>,
  865    popover_bounds: Option<Bounds<Pixels>>,
  866    popover_state: InlineBlamePopoverState,
  867}
  868
  869/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  870/// a breakpoint on them.
  871#[derive(Clone, Copy, Debug)]
  872struct PhantomBreakpointIndicator {
  873    display_row: DisplayRow,
  874    /// There's a small debounce between hovering over the line and showing the indicator.
  875    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  876    is_active: bool,
  877    collides_with_existing_breakpoint: bool,
  878}
  879/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  880///
  881/// See the [module level documentation](self) for more information.
  882pub struct Editor {
  883    focus_handle: FocusHandle,
  884    last_focused_descendant: Option<WeakFocusHandle>,
  885    /// The text buffer being edited
  886    buffer: Entity<MultiBuffer>,
  887    /// Map of how text in the buffer should be displayed.
  888    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  889    pub display_map: Entity<DisplayMap>,
  890    pub selections: SelectionsCollection,
  891    pub scroll_manager: ScrollManager,
  892    /// When inline assist editors are linked, they all render cursors because
  893    /// typing enters text into each of them, even the ones that aren't focused.
  894    pub(crate) show_cursor_when_unfocused: bool,
  895    columnar_selection_tail: Option<Anchor>,
  896    add_selections_state: Option<AddSelectionsState>,
  897    select_next_state: Option<SelectNextState>,
  898    select_prev_state: Option<SelectNextState>,
  899    selection_history: SelectionHistory,
  900    autoclose_regions: Vec<AutocloseRegion>,
  901    snippet_stack: InvalidationStack<SnippetState>,
  902    select_syntax_node_history: SelectSyntaxNodeHistory,
  903    ime_transaction: Option<TransactionId>,
  904    pub diagnostics_max_severity: DiagnosticSeverity,
  905    active_diagnostics: ActiveDiagnostic,
  906    show_inline_diagnostics: bool,
  907    inline_diagnostics_update: Task<()>,
  908    inline_diagnostics_enabled: bool,
  909    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  910    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  911    hard_wrap: Option<usize>,
  912
  913    // TODO: make this a access method
  914    pub project: Option<Entity<Project>>,
  915    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  916    completion_provider: Option<Box<dyn CompletionProvider>>,
  917    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  918    blink_manager: Entity<BlinkManager>,
  919    show_cursor_names: bool,
  920    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  921    pub show_local_selections: bool,
  922    mode: EditorMode,
  923    show_breadcrumbs: bool,
  924    show_gutter: bool,
  925    show_scrollbars: bool,
  926    minimap_visibility: MinimapVisibility,
  927    disable_expand_excerpt_buttons: bool,
  928    show_line_numbers: Option<bool>,
  929    use_relative_line_numbers: Option<bool>,
  930    show_git_diff_gutter: Option<bool>,
  931    show_code_actions: Option<bool>,
  932    show_runnables: Option<bool>,
  933    show_breakpoints: Option<bool>,
  934    show_wrap_guides: Option<bool>,
  935    show_indent_guides: Option<bool>,
  936    placeholder_text: Option<Arc<str>>,
  937    highlight_order: usize,
  938    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  939    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  940    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  941    scrollbar_marker_state: ScrollbarMarkerState,
  942    active_indent_guides_state: ActiveIndentGuidesState,
  943    nav_history: Option<ItemNavHistory>,
  944    context_menu: RefCell<Option<CodeContextMenu>>,
  945    context_menu_options: Option<ContextMenuOptions>,
  946    mouse_context_menu: Option<MouseContextMenu>,
  947    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  948    inline_blame_popover: Option<InlineBlamePopover>,
  949    signature_help_state: SignatureHelpState,
  950    auto_signature_help: Option<bool>,
  951    find_all_references_task_sources: Vec<Anchor>,
  952    next_completion_id: CompletionId,
  953    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  954    code_actions_task: Option<Task<Result<()>>>,
  955    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  956    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  957    document_highlights_task: Option<Task<()>>,
  958    linked_editing_range_task: Option<Task<Option<()>>>,
  959    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  960    pending_rename: Option<RenameState>,
  961    searchable: bool,
  962    cursor_shape: CursorShape,
  963    current_line_highlight: Option<CurrentLineHighlight>,
  964    collapse_matches: bool,
  965    autoindent_mode: Option<AutoindentMode>,
  966    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  967    input_enabled: bool,
  968    use_modal_editing: bool,
  969    read_only: bool,
  970    leader_id: Option<CollaboratorId>,
  971    remote_id: Option<ViewId>,
  972    pub hover_state: HoverState,
  973    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  974    gutter_hovered: bool,
  975    hovered_link_state: Option<HoveredLinkState>,
  976    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  977    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  978    active_inline_completion: Option<InlineCompletionState>,
  979    /// Used to prevent flickering as the user types while the menu is open
  980    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  981    edit_prediction_settings: EditPredictionSettings,
  982    inline_completions_hidden_for_vim_mode: bool,
  983    show_inline_completions_override: Option<bool>,
  984    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  985    edit_prediction_preview: EditPredictionPreview,
  986    edit_prediction_indent_conflict: bool,
  987    edit_prediction_requires_modifier_in_indent_conflict: bool,
  988    inlay_hint_cache: InlayHintCache,
  989    next_inlay_id: usize,
  990    _subscriptions: Vec<Subscription>,
  991    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  992    gutter_dimensions: GutterDimensions,
  993    style: Option<EditorStyle>,
  994    text_style_refinement: Option<TextStyleRefinement>,
  995    next_editor_action_id: EditorActionId,
  996    editor_actions:
  997        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  998    use_autoclose: bool,
  999    use_auto_surround: bool,
 1000    auto_replace_emoji_shortcode: bool,
 1001    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1002    show_git_blame_gutter: bool,
 1003    show_git_blame_inline: bool,
 1004    show_git_blame_inline_delay_task: Option<Task<()>>,
 1005    git_blame_inline_enabled: bool,
 1006    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1007    serialize_dirty_buffers: bool,
 1008    show_selection_menu: Option<bool>,
 1009    blame: Option<Entity<GitBlame>>,
 1010    blame_subscription: Option<Subscription>,
 1011    custom_context_menu: Option<
 1012        Box<
 1013            dyn 'static
 1014                + Fn(
 1015                    &mut Self,
 1016                    DisplayPoint,
 1017                    &mut Window,
 1018                    &mut Context<Self>,
 1019                ) -> Option<Entity<ui::ContextMenu>>,
 1020        >,
 1021    >,
 1022    last_bounds: Option<Bounds<Pixels>>,
 1023    last_position_map: Option<Rc<PositionMap>>,
 1024    expect_bounds_change: Option<Bounds<Pixels>>,
 1025    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1026    tasks_update_task: Option<Task<()>>,
 1027    breakpoint_store: Option<Entity<BreakpointStore>>,
 1028    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1029    in_project_search: bool,
 1030    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1031    breadcrumb_header: Option<String>,
 1032    focused_block: Option<FocusedBlock>,
 1033    next_scroll_position: NextScrollCursorCenterTopBottom,
 1034    addons: HashMap<TypeId, Box<dyn Addon>>,
 1035    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1036    load_diff_task: Option<Shared<Task<()>>>,
 1037    /// Whether we are temporarily displaying a diff other than git's
 1038    temporary_diff_override: bool,
 1039    selection_mark_mode: bool,
 1040    toggle_fold_multiple_buffers: Task<()>,
 1041    _scroll_cursor_center_top_bottom_task: Task<()>,
 1042    serialize_selections: Task<()>,
 1043    serialize_folds: Task<()>,
 1044    mouse_cursor_hidden: bool,
 1045    minimap: Option<Entity<Self>>,
 1046    hide_mouse_mode: HideMouseMode,
 1047    pub change_list: ChangeList,
 1048    inline_value_cache: InlineValueCache,
 1049}
 1050
 1051#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1052enum NextScrollCursorCenterTopBottom {
 1053    #[default]
 1054    Center,
 1055    Top,
 1056    Bottom,
 1057}
 1058
 1059impl NextScrollCursorCenterTopBottom {
 1060    fn next(&self) -> Self {
 1061        match self {
 1062            Self::Center => Self::Top,
 1063            Self::Top => Self::Bottom,
 1064            Self::Bottom => Self::Center,
 1065        }
 1066    }
 1067}
 1068
 1069#[derive(Clone)]
 1070pub struct EditorSnapshot {
 1071    pub mode: EditorMode,
 1072    show_gutter: bool,
 1073    show_line_numbers: Option<bool>,
 1074    show_git_diff_gutter: Option<bool>,
 1075    show_runnables: Option<bool>,
 1076    show_breakpoints: Option<bool>,
 1077    git_blame_gutter_max_author_length: Option<usize>,
 1078    pub display_snapshot: DisplaySnapshot,
 1079    pub placeholder_text: Option<Arc<str>>,
 1080    is_focused: bool,
 1081    scroll_anchor: ScrollAnchor,
 1082    ongoing_scroll: OngoingScroll,
 1083    current_line_highlight: CurrentLineHighlight,
 1084    gutter_hovered: bool,
 1085}
 1086
 1087#[derive(Default, Debug, Clone, Copy)]
 1088pub struct GutterDimensions {
 1089    pub left_padding: Pixels,
 1090    pub right_padding: Pixels,
 1091    pub width: Pixels,
 1092    pub margin: Pixels,
 1093    pub git_blame_entries_width: Option<Pixels>,
 1094}
 1095
 1096impl GutterDimensions {
 1097    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1098        Self {
 1099            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1100            ..Default::default()
 1101        }
 1102    }
 1103
 1104    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1105        -cx.text_system().descent(font_id, font_size)
 1106    }
 1107    /// The full width of the space taken up by the gutter.
 1108    pub fn full_width(&self) -> Pixels {
 1109        self.margin + self.width
 1110    }
 1111
 1112    /// The width of the space reserved for the fold indicators,
 1113    /// use alongside 'justify_end' and `gutter_width` to
 1114    /// right align content with the line numbers
 1115    pub fn fold_area_width(&self) -> Pixels {
 1116        self.margin + self.right_padding
 1117    }
 1118}
 1119
 1120#[derive(Debug)]
 1121pub struct RemoteSelection {
 1122    pub replica_id: ReplicaId,
 1123    pub selection: Selection<Anchor>,
 1124    pub cursor_shape: CursorShape,
 1125    pub collaborator_id: CollaboratorId,
 1126    pub line_mode: bool,
 1127    pub user_name: Option<SharedString>,
 1128    pub color: PlayerColor,
 1129}
 1130
 1131#[derive(Clone, Debug)]
 1132struct SelectionHistoryEntry {
 1133    selections: Arc<[Selection<Anchor>]>,
 1134    select_next_state: Option<SelectNextState>,
 1135    select_prev_state: Option<SelectNextState>,
 1136    add_selections_state: Option<AddSelectionsState>,
 1137}
 1138
 1139enum SelectionHistoryMode {
 1140    Normal,
 1141    Undoing,
 1142    Redoing,
 1143}
 1144
 1145#[derive(Clone, PartialEq, Eq, Hash)]
 1146struct HoveredCursor {
 1147    replica_id: u16,
 1148    selection_id: usize,
 1149}
 1150
 1151impl Default for SelectionHistoryMode {
 1152    fn default() -> Self {
 1153        Self::Normal
 1154    }
 1155}
 1156
 1157#[derive(Default)]
 1158struct SelectionHistory {
 1159    #[allow(clippy::type_complexity)]
 1160    selections_by_transaction:
 1161        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1162    mode: SelectionHistoryMode,
 1163    undo_stack: VecDeque<SelectionHistoryEntry>,
 1164    redo_stack: VecDeque<SelectionHistoryEntry>,
 1165}
 1166
 1167impl SelectionHistory {
 1168    fn insert_transaction(
 1169        &mut self,
 1170        transaction_id: TransactionId,
 1171        selections: Arc<[Selection<Anchor>]>,
 1172    ) {
 1173        self.selections_by_transaction
 1174            .insert(transaction_id, (selections, None));
 1175    }
 1176
 1177    #[allow(clippy::type_complexity)]
 1178    fn transaction(
 1179        &self,
 1180        transaction_id: TransactionId,
 1181    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1182        self.selections_by_transaction.get(&transaction_id)
 1183    }
 1184
 1185    #[allow(clippy::type_complexity)]
 1186    fn transaction_mut(
 1187        &mut self,
 1188        transaction_id: TransactionId,
 1189    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1190        self.selections_by_transaction.get_mut(&transaction_id)
 1191    }
 1192
 1193    fn push(&mut self, entry: SelectionHistoryEntry) {
 1194        if !entry.selections.is_empty() {
 1195            match self.mode {
 1196                SelectionHistoryMode::Normal => {
 1197                    self.push_undo(entry);
 1198                    self.redo_stack.clear();
 1199                }
 1200                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1201                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1202            }
 1203        }
 1204    }
 1205
 1206    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1207        if self
 1208            .undo_stack
 1209            .back()
 1210            .map_or(true, |e| e.selections != entry.selections)
 1211        {
 1212            self.undo_stack.push_back(entry);
 1213            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1214                self.undo_stack.pop_front();
 1215            }
 1216        }
 1217    }
 1218
 1219    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1220        if self
 1221            .redo_stack
 1222            .back()
 1223            .map_or(true, |e| e.selections != entry.selections)
 1224        {
 1225            self.redo_stack.push_back(entry);
 1226            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1227                self.redo_stack.pop_front();
 1228            }
 1229        }
 1230    }
 1231}
 1232
 1233#[derive(Clone, Copy)]
 1234pub struct RowHighlightOptions {
 1235    pub autoscroll: bool,
 1236    pub include_gutter: bool,
 1237}
 1238
 1239impl Default for RowHighlightOptions {
 1240    fn default() -> Self {
 1241        Self {
 1242            autoscroll: Default::default(),
 1243            include_gutter: true,
 1244        }
 1245    }
 1246}
 1247
 1248struct RowHighlight {
 1249    index: usize,
 1250    range: Range<Anchor>,
 1251    color: Hsla,
 1252    options: RowHighlightOptions,
 1253    type_id: TypeId,
 1254}
 1255
 1256#[derive(Clone, Debug)]
 1257struct AddSelectionsState {
 1258    above: bool,
 1259    stack: Vec<usize>,
 1260}
 1261
 1262#[derive(Clone)]
 1263struct SelectNextState {
 1264    query: AhoCorasick,
 1265    wordwise: bool,
 1266    done: bool,
 1267}
 1268
 1269impl std::fmt::Debug for SelectNextState {
 1270    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1271        f.debug_struct(std::any::type_name::<Self>())
 1272            .field("wordwise", &self.wordwise)
 1273            .field("done", &self.done)
 1274            .finish()
 1275    }
 1276}
 1277
 1278#[derive(Debug)]
 1279struct AutocloseRegion {
 1280    selection_id: usize,
 1281    range: Range<Anchor>,
 1282    pair: BracketPair,
 1283}
 1284
 1285#[derive(Debug)]
 1286struct SnippetState {
 1287    ranges: Vec<Vec<Range<Anchor>>>,
 1288    active_index: usize,
 1289    choices: Vec<Option<Vec<String>>>,
 1290}
 1291
 1292#[doc(hidden)]
 1293pub struct RenameState {
 1294    pub range: Range<Anchor>,
 1295    pub old_name: Arc<str>,
 1296    pub editor: Entity<Editor>,
 1297    block_id: CustomBlockId,
 1298}
 1299
 1300struct InvalidationStack<T>(Vec<T>);
 1301
 1302struct RegisteredInlineCompletionProvider {
 1303    provider: Arc<dyn InlineCompletionProviderHandle>,
 1304    _subscription: Subscription,
 1305}
 1306
 1307#[derive(Debug, PartialEq, Eq)]
 1308pub struct ActiveDiagnosticGroup {
 1309    pub active_range: Range<Anchor>,
 1310    pub active_message: String,
 1311    pub group_id: usize,
 1312    pub blocks: HashSet<CustomBlockId>,
 1313}
 1314
 1315#[derive(Debug, PartialEq, Eq)]
 1316
 1317pub(crate) enum ActiveDiagnostic {
 1318    None,
 1319    All,
 1320    Group(ActiveDiagnosticGroup),
 1321}
 1322
 1323#[derive(Serialize, Deserialize, Clone, Debug)]
 1324pub struct ClipboardSelection {
 1325    /// The number of bytes in this selection.
 1326    pub len: usize,
 1327    /// Whether this was a full-line selection.
 1328    pub is_entire_line: bool,
 1329    /// The indentation of the first line when this content was originally copied.
 1330    pub first_line_indent: u32,
 1331}
 1332
 1333// selections, scroll behavior, was newest selection reversed
 1334type SelectSyntaxNodeHistoryState = (
 1335    Box<[Selection<usize>]>,
 1336    SelectSyntaxNodeScrollBehavior,
 1337    bool,
 1338);
 1339
 1340#[derive(Default)]
 1341struct SelectSyntaxNodeHistory {
 1342    stack: Vec<SelectSyntaxNodeHistoryState>,
 1343    // disable temporarily to allow changing selections without losing the stack
 1344    pub disable_clearing: bool,
 1345}
 1346
 1347impl SelectSyntaxNodeHistory {
 1348    pub fn try_clear(&mut self) {
 1349        if !self.disable_clearing {
 1350            self.stack.clear();
 1351        }
 1352    }
 1353
 1354    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1355        self.stack.push(selection);
 1356    }
 1357
 1358    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1359        self.stack.pop()
 1360    }
 1361}
 1362
 1363enum SelectSyntaxNodeScrollBehavior {
 1364    CursorTop,
 1365    FitSelection,
 1366    CursorBottom,
 1367}
 1368
 1369#[derive(Debug)]
 1370pub(crate) struct NavigationData {
 1371    cursor_anchor: Anchor,
 1372    cursor_position: Point,
 1373    scroll_anchor: ScrollAnchor,
 1374    scroll_top_row: u32,
 1375}
 1376
 1377#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1378pub enum GotoDefinitionKind {
 1379    Symbol,
 1380    Declaration,
 1381    Type,
 1382    Implementation,
 1383}
 1384
 1385#[derive(Debug, Clone)]
 1386enum InlayHintRefreshReason {
 1387    ModifiersChanged(bool),
 1388    Toggle(bool),
 1389    SettingsChange(InlayHintSettings),
 1390    NewLinesShown,
 1391    BufferEdited(HashSet<Arc<Language>>),
 1392    RefreshRequested,
 1393    ExcerptsRemoved(Vec<ExcerptId>),
 1394}
 1395
 1396impl InlayHintRefreshReason {
 1397    fn description(&self) -> &'static str {
 1398        match self {
 1399            Self::ModifiersChanged(_) => "modifiers changed",
 1400            Self::Toggle(_) => "toggle",
 1401            Self::SettingsChange(_) => "settings change",
 1402            Self::NewLinesShown => "new lines shown",
 1403            Self::BufferEdited(_) => "buffer edited",
 1404            Self::RefreshRequested => "refresh requested",
 1405            Self::ExcerptsRemoved(_) => "excerpts removed",
 1406        }
 1407    }
 1408}
 1409
 1410pub enum FormatTarget {
 1411    Buffers,
 1412    Ranges(Vec<Range<MultiBufferPoint>>),
 1413}
 1414
 1415pub(crate) struct FocusedBlock {
 1416    id: BlockId,
 1417    focus_handle: WeakFocusHandle,
 1418}
 1419
 1420#[derive(Clone)]
 1421enum JumpData {
 1422    MultiBufferRow {
 1423        row: MultiBufferRow,
 1424        line_offset_from_top: u32,
 1425    },
 1426    MultiBufferPoint {
 1427        excerpt_id: ExcerptId,
 1428        position: Point,
 1429        anchor: text::Anchor,
 1430        line_offset_from_top: u32,
 1431    },
 1432}
 1433
 1434pub enum MultibufferSelectionMode {
 1435    First,
 1436    All,
 1437}
 1438
 1439#[derive(Clone, Copy, Debug, Default)]
 1440pub struct RewrapOptions {
 1441    pub override_language_settings: bool,
 1442    pub preserve_existing_whitespace: bool,
 1443}
 1444
 1445impl Editor {
 1446    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1447        let buffer = cx.new(|cx| Buffer::local("", cx));
 1448        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1449        Self::new(
 1450            EditorMode::SingleLine { auto_width: false },
 1451            buffer,
 1452            None,
 1453            window,
 1454            cx,
 1455        )
 1456    }
 1457
 1458    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1459        let buffer = cx.new(|cx| Buffer::local("", cx));
 1460        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1461        Self::new(EditorMode::full(), buffer, None, window, cx)
 1462    }
 1463
 1464    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1465        let buffer = cx.new(|cx| Buffer::local("", cx));
 1466        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1467        Self::new(
 1468            EditorMode::SingleLine { auto_width: true },
 1469            buffer,
 1470            None,
 1471            window,
 1472            cx,
 1473        )
 1474    }
 1475
 1476    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1477        let buffer = cx.new(|cx| Buffer::local("", cx));
 1478        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1479        Self::new(
 1480            EditorMode::AutoHeight { max_lines },
 1481            buffer,
 1482            None,
 1483            window,
 1484            cx,
 1485        )
 1486    }
 1487
 1488    pub fn for_buffer(
 1489        buffer: Entity<Buffer>,
 1490        project: Option<Entity<Project>>,
 1491        window: &mut Window,
 1492        cx: &mut Context<Self>,
 1493    ) -> Self {
 1494        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1495        Self::new(EditorMode::full(), buffer, project, window, cx)
 1496    }
 1497
 1498    pub fn for_multibuffer(
 1499        buffer: Entity<MultiBuffer>,
 1500        project: Option<Entity<Project>>,
 1501        window: &mut Window,
 1502        cx: &mut Context<Self>,
 1503    ) -> Self {
 1504        Self::new(EditorMode::full(), buffer, project, window, cx)
 1505    }
 1506
 1507    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1508        let mut clone = Self::new(
 1509            self.mode.clone(),
 1510            self.buffer.clone(),
 1511            self.project.clone(),
 1512            window,
 1513            cx,
 1514        );
 1515        self.display_map.update(cx, |display_map, cx| {
 1516            let snapshot = display_map.snapshot(cx);
 1517            clone.display_map.update(cx, |display_map, cx| {
 1518                display_map.set_state(&snapshot, cx);
 1519            });
 1520        });
 1521        clone.folds_did_change(cx);
 1522        clone.selections.clone_state(&self.selections);
 1523        clone.scroll_manager.clone_state(&self.scroll_manager);
 1524        clone.searchable = self.searchable;
 1525        clone.read_only = self.read_only;
 1526        clone
 1527    }
 1528
 1529    pub fn new(
 1530        mode: EditorMode,
 1531        buffer: Entity<MultiBuffer>,
 1532        project: Option<Entity<Project>>,
 1533        window: &mut Window,
 1534        cx: &mut Context<Self>,
 1535    ) -> Self {
 1536        Editor::new_internal(mode, buffer, project, None, window, cx)
 1537    }
 1538
 1539    fn new_internal(
 1540        mode: EditorMode,
 1541        buffer: Entity<MultiBuffer>,
 1542        project: Option<Entity<Project>>,
 1543        display_map: Option<Entity<DisplayMap>>,
 1544        window: &mut Window,
 1545        cx: &mut Context<Self>,
 1546    ) -> Self {
 1547        debug_assert!(
 1548            display_map.is_none() || mode.is_minimap(),
 1549            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1550        );
 1551
 1552        let full_mode = mode.is_full();
 1553        let diagnostics_max_severity = if full_mode {
 1554            EditorSettings::get_global(cx)
 1555                .diagnostics_max_severity
 1556                .unwrap_or(DiagnosticSeverity::Hint)
 1557        } else {
 1558            DiagnosticSeverity::Off
 1559        };
 1560        let style = window.text_style();
 1561        let font_size = style.font_size.to_pixels(window.rem_size());
 1562        let editor = cx.entity().downgrade();
 1563        let fold_placeholder = FoldPlaceholder {
 1564            constrain_width: true,
 1565            render: Arc::new(move |fold_id, fold_range, cx| {
 1566                let editor = editor.clone();
 1567                div()
 1568                    .id(fold_id)
 1569                    .bg(cx.theme().colors().ghost_element_background)
 1570                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1571                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1572                    .rounded_xs()
 1573                    .size_full()
 1574                    .cursor_pointer()
 1575                    .child("")
 1576                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1577                    .on_click(move |_, _window, cx| {
 1578                        editor
 1579                            .update(cx, |editor, cx| {
 1580                                editor.unfold_ranges(
 1581                                    &[fold_range.start..fold_range.end],
 1582                                    true,
 1583                                    false,
 1584                                    cx,
 1585                                );
 1586                                cx.stop_propagation();
 1587                            })
 1588                            .ok();
 1589                    })
 1590                    .into_any()
 1591            }),
 1592            merge_adjacent: true,
 1593            ..FoldPlaceholder::default()
 1594        };
 1595        let display_map = display_map.unwrap_or_else(|| {
 1596            cx.new(|cx| {
 1597                DisplayMap::new(
 1598                    buffer.clone(),
 1599                    style.font(),
 1600                    font_size,
 1601                    None,
 1602                    FILE_HEADER_HEIGHT,
 1603                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1604                    fold_placeholder,
 1605                    diagnostics_max_severity,
 1606                    cx,
 1607                )
 1608            })
 1609        });
 1610
 1611        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1612
 1613        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1614
 1615        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1616            .then(|| language_settings::SoftWrap::None);
 1617
 1618        let mut project_subscriptions = Vec::new();
 1619        if mode.is_full() {
 1620            if let Some(project) = project.as_ref() {
 1621                project_subscriptions.push(cx.subscribe_in(
 1622                    project,
 1623                    window,
 1624                    |editor, _, event, window, cx| match event {
 1625                        project::Event::RefreshCodeLens => {
 1626                            // we always query lens with actions, without storing them, always refreshing them
 1627                        }
 1628                        project::Event::RefreshInlayHints => {
 1629                            editor
 1630                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1631                        }
 1632                        project::Event::SnippetEdit(id, snippet_edits) => {
 1633                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1634                                let focus_handle = editor.focus_handle(cx);
 1635                                if focus_handle.is_focused(window) {
 1636                                    let snapshot = buffer.read(cx).snapshot();
 1637                                    for (range, snippet) in snippet_edits {
 1638                                        let editor_range =
 1639                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1640                                        editor
 1641                                            .insert_snippet(
 1642                                                &[editor_range],
 1643                                                snippet.clone(),
 1644                                                window,
 1645                                                cx,
 1646                                            )
 1647                                            .ok();
 1648                                    }
 1649                                }
 1650                            }
 1651                        }
 1652                        _ => {}
 1653                    },
 1654                ));
 1655                if let Some(task_inventory) = project
 1656                    .read(cx)
 1657                    .task_store()
 1658                    .read(cx)
 1659                    .task_inventory()
 1660                    .cloned()
 1661                {
 1662                    project_subscriptions.push(cx.observe_in(
 1663                        &task_inventory,
 1664                        window,
 1665                        |editor, _, window, cx| {
 1666                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1667                        },
 1668                    ));
 1669                };
 1670
 1671                project_subscriptions.push(cx.subscribe_in(
 1672                    &project.read(cx).breakpoint_store(),
 1673                    window,
 1674                    |editor, _, event, window, cx| match event {
 1675                        BreakpointStoreEvent::ClearDebugLines => {
 1676                            editor.clear_row_highlights::<ActiveDebugLine>();
 1677                            editor.refresh_inline_values(cx);
 1678                        }
 1679                        BreakpointStoreEvent::SetDebugLine => {
 1680                            if editor.go_to_active_debug_line(window, cx) {
 1681                                cx.stop_propagation();
 1682                            }
 1683
 1684                            editor.refresh_inline_values(cx);
 1685                        }
 1686                        _ => {}
 1687                    },
 1688                ));
 1689            }
 1690        }
 1691
 1692        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1693
 1694        let inlay_hint_settings =
 1695            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1696        let focus_handle = cx.focus_handle();
 1697        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1698            .detach();
 1699        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1700            .detach();
 1701        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1702            .detach();
 1703        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1704            .detach();
 1705
 1706        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1707            Some(false)
 1708        } else {
 1709            None
 1710        };
 1711
 1712        let breakpoint_store = match (&mode, project.as_ref()) {
 1713            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1714            _ => None,
 1715        };
 1716
 1717        let mut code_action_providers = Vec::new();
 1718        let mut load_uncommitted_diff = None;
 1719        if let Some(project) = project.clone() {
 1720            load_uncommitted_diff = Some(
 1721                update_uncommitted_diff_for_buffer(
 1722                    cx.entity(),
 1723                    &project,
 1724                    buffer.read(cx).all_buffers(),
 1725                    buffer.clone(),
 1726                    cx,
 1727                )
 1728                .shared(),
 1729            );
 1730            code_action_providers.push(Rc::new(project) as Rc<_>);
 1731        }
 1732
 1733        let mut this = Self {
 1734            focus_handle,
 1735            show_cursor_when_unfocused: false,
 1736            last_focused_descendant: None,
 1737            buffer: buffer.clone(),
 1738            display_map: display_map.clone(),
 1739            selections,
 1740            scroll_manager: ScrollManager::new(cx),
 1741            columnar_selection_tail: None,
 1742            add_selections_state: None,
 1743            select_next_state: None,
 1744            select_prev_state: None,
 1745            selection_history: SelectionHistory::default(),
 1746            autoclose_regions: Vec::new(),
 1747            snippet_stack: InvalidationStack::default(),
 1748            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1749            ime_transaction: None,
 1750            active_diagnostics: ActiveDiagnostic::None,
 1751            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1752            inline_diagnostics_update: Task::ready(()),
 1753            inline_diagnostics: Vec::new(),
 1754            soft_wrap_mode_override,
 1755            diagnostics_max_severity,
 1756            hard_wrap: None,
 1757            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1758            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1759            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1760            project,
 1761            blink_manager: blink_manager.clone(),
 1762            show_local_selections: true,
 1763            show_scrollbars: full_mode,
 1764            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1765            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1766            show_gutter: mode.is_full(),
 1767            show_line_numbers: None,
 1768            use_relative_line_numbers: None,
 1769            disable_expand_excerpt_buttons: false,
 1770            show_git_diff_gutter: None,
 1771            show_code_actions: None,
 1772            show_runnables: None,
 1773            show_breakpoints: None,
 1774            show_wrap_guides: None,
 1775            show_indent_guides,
 1776            placeholder_text: None,
 1777            highlight_order: 0,
 1778            highlighted_rows: HashMap::default(),
 1779            background_highlights: TreeMap::default(),
 1780            gutter_highlights: TreeMap::default(),
 1781            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1782            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1783            nav_history: None,
 1784            context_menu: RefCell::new(None),
 1785            context_menu_options: None,
 1786            mouse_context_menu: None,
 1787            completion_tasks: Vec::new(),
 1788            inline_blame_popover: None,
 1789            signature_help_state: SignatureHelpState::default(),
 1790            auto_signature_help: None,
 1791            find_all_references_task_sources: Vec::new(),
 1792            next_completion_id: 0,
 1793            next_inlay_id: 0,
 1794            code_action_providers,
 1795            available_code_actions: None,
 1796            code_actions_task: None,
 1797            quick_selection_highlight_task: None,
 1798            debounced_selection_highlight_task: None,
 1799            document_highlights_task: None,
 1800            linked_editing_range_task: None,
 1801            pending_rename: None,
 1802            searchable: true,
 1803            cursor_shape: EditorSettings::get_global(cx)
 1804                .cursor_shape
 1805                .unwrap_or_default(),
 1806            current_line_highlight: None,
 1807            autoindent_mode: Some(AutoindentMode::EachLine),
 1808            collapse_matches: false,
 1809            workspace: None,
 1810            input_enabled: true,
 1811            use_modal_editing: mode.is_full(),
 1812            read_only: mode.is_minimap(),
 1813            use_autoclose: true,
 1814            use_auto_surround: true,
 1815            auto_replace_emoji_shortcode: false,
 1816            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1817            leader_id: None,
 1818            remote_id: None,
 1819            hover_state: HoverState::default(),
 1820            pending_mouse_down: None,
 1821            hovered_link_state: None,
 1822            edit_prediction_provider: None,
 1823            active_inline_completion: None,
 1824            stale_inline_completion_in_menu: None,
 1825            edit_prediction_preview: EditPredictionPreview::Inactive {
 1826                released_too_fast: false,
 1827            },
 1828            inline_diagnostics_enabled: mode.is_full(),
 1829            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1830            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1831
 1832            gutter_hovered: false,
 1833            pixel_position_of_newest_cursor: None,
 1834            last_bounds: None,
 1835            last_position_map: None,
 1836            expect_bounds_change: None,
 1837            gutter_dimensions: GutterDimensions::default(),
 1838            style: None,
 1839            show_cursor_names: false,
 1840            hovered_cursors: HashMap::default(),
 1841            next_editor_action_id: EditorActionId::default(),
 1842            editor_actions: Rc::default(),
 1843            inline_completions_hidden_for_vim_mode: false,
 1844            show_inline_completions_override: None,
 1845            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1846            edit_prediction_settings: EditPredictionSettings::Disabled,
 1847            edit_prediction_indent_conflict: false,
 1848            edit_prediction_requires_modifier_in_indent_conflict: true,
 1849            custom_context_menu: None,
 1850            show_git_blame_gutter: false,
 1851            show_git_blame_inline: false,
 1852            show_selection_menu: None,
 1853            show_git_blame_inline_delay_task: None,
 1854            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1855            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1856            serialize_dirty_buffers: !mode.is_minimap()
 1857                && ProjectSettings::get_global(cx)
 1858                    .session
 1859                    .restore_unsaved_buffers,
 1860            blame: None,
 1861            blame_subscription: None,
 1862            tasks: BTreeMap::default(),
 1863
 1864            breakpoint_store,
 1865            gutter_breakpoint_indicator: (None, None),
 1866            _subscriptions: vec![
 1867                cx.observe(&buffer, Self::on_buffer_changed),
 1868                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1869                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1870                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1871                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1872                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1873                cx.observe_window_activation(window, |editor, window, cx| {
 1874                    let active = window.is_window_active();
 1875                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1876                        if active {
 1877                            blink_manager.enable(cx);
 1878                        } else {
 1879                            blink_manager.disable(cx);
 1880                        }
 1881                    });
 1882                }),
 1883            ],
 1884            tasks_update_task: None,
 1885            linked_edit_ranges: Default::default(),
 1886            in_project_search: false,
 1887            previous_search_ranges: None,
 1888            breadcrumb_header: None,
 1889            focused_block: None,
 1890            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1891            addons: HashMap::default(),
 1892            registered_buffers: HashMap::default(),
 1893            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1894            selection_mark_mode: false,
 1895            toggle_fold_multiple_buffers: Task::ready(()),
 1896            serialize_selections: Task::ready(()),
 1897            serialize_folds: Task::ready(()),
 1898            text_style_refinement: None,
 1899            load_diff_task: load_uncommitted_diff,
 1900            temporary_diff_override: false,
 1901            mouse_cursor_hidden: false,
 1902            minimap: None,
 1903            hide_mouse_mode: EditorSettings::get_global(cx)
 1904                .hide_mouse
 1905                .unwrap_or_default(),
 1906            change_list: ChangeList::new(),
 1907            mode,
 1908        };
 1909        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1910            this._subscriptions
 1911                .push(cx.observe(breakpoints, |_, _, cx| {
 1912                    cx.notify();
 1913                }));
 1914        }
 1915        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1916        this._subscriptions.extend(project_subscriptions);
 1917
 1918        this._subscriptions.push(cx.subscribe_in(
 1919            &cx.entity(),
 1920            window,
 1921            |editor, _, e: &EditorEvent, window, cx| match e {
 1922                EditorEvent::ScrollPositionChanged { local, .. } => {
 1923                    if *local {
 1924                        let new_anchor = editor.scroll_manager.anchor();
 1925                        let snapshot = editor.snapshot(window, cx);
 1926                        editor.update_restoration_data(cx, move |data| {
 1927                            data.scroll_position = (
 1928                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1929                                new_anchor.offset,
 1930                            );
 1931                        });
 1932                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1933                        editor.inline_blame_popover.take();
 1934                    }
 1935                }
 1936                EditorEvent::Edited { .. } => {
 1937                    if !vim_enabled(cx) {
 1938                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1939                        let pop_state = editor
 1940                            .change_list
 1941                            .last()
 1942                            .map(|previous| {
 1943                                previous.len() == selections.len()
 1944                                    && previous.iter().enumerate().all(|(ix, p)| {
 1945                                        p.to_display_point(&map).row()
 1946                                            == selections[ix].head().row()
 1947                                    })
 1948                            })
 1949                            .unwrap_or(false);
 1950                        let new_positions = selections
 1951                            .into_iter()
 1952                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1953                            .collect();
 1954                        editor
 1955                            .change_list
 1956                            .push_to_change_list(pop_state, new_positions);
 1957                    }
 1958                }
 1959                _ => (),
 1960            },
 1961        ));
 1962
 1963        if let Some(dap_store) = this
 1964            .project
 1965            .as_ref()
 1966            .map(|project| project.read(cx).dap_store())
 1967        {
 1968            let weak_editor = cx.weak_entity();
 1969
 1970            this._subscriptions
 1971                .push(
 1972                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1973                        let session_entity = cx.entity();
 1974                        weak_editor
 1975                            .update(cx, |editor, cx| {
 1976                                editor._subscriptions.push(
 1977                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1978                                );
 1979                            })
 1980                            .ok();
 1981                    }),
 1982                );
 1983
 1984            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1985                this._subscriptions
 1986                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1987            }
 1988        }
 1989
 1990        this.end_selection(window, cx);
 1991        this.scroll_manager.show_scrollbars(window, cx);
 1992        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1993
 1994        if full_mode {
 1995            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1996            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1997
 1998            if this.git_blame_inline_enabled {
 1999                this.start_git_blame_inline(false, window, cx);
 2000            }
 2001
 2002            this.go_to_active_debug_line(window, cx);
 2003
 2004            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2005                if let Some(project) = this.project.as_ref() {
 2006                    let handle = project.update(cx, |project, cx| {
 2007                        project.register_buffer_with_language_servers(&buffer, cx)
 2008                    });
 2009                    this.registered_buffers
 2010                        .insert(buffer.read(cx).remote_id(), handle);
 2011                }
 2012            }
 2013
 2014            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2015        }
 2016
 2017        this.report_editor_event("Editor Opened", None, cx);
 2018        this
 2019    }
 2020
 2021    pub fn deploy_mouse_context_menu(
 2022        &mut self,
 2023        position: gpui::Point<Pixels>,
 2024        context_menu: Entity<ContextMenu>,
 2025        window: &mut Window,
 2026        cx: &mut Context<Self>,
 2027    ) {
 2028        self.mouse_context_menu = Some(MouseContextMenu::new(
 2029            self,
 2030            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2031            context_menu,
 2032            window,
 2033            cx,
 2034        ));
 2035    }
 2036
 2037    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2038        self.mouse_context_menu
 2039            .as_ref()
 2040            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2041    }
 2042
 2043    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2044        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2045    }
 2046
 2047    fn key_context_internal(
 2048        &self,
 2049        has_active_edit_prediction: bool,
 2050        window: &Window,
 2051        cx: &App,
 2052    ) -> KeyContext {
 2053        let mut key_context = KeyContext::new_with_defaults();
 2054        key_context.add("Editor");
 2055        let mode = match self.mode {
 2056            EditorMode::SingleLine { .. } => "single_line",
 2057            EditorMode::AutoHeight { .. } => "auto_height",
 2058            EditorMode::Minimap { .. } => "minimap",
 2059            EditorMode::Full { .. } => "full",
 2060        };
 2061
 2062        if EditorSettings::jupyter_enabled(cx) {
 2063            key_context.add("jupyter");
 2064        }
 2065
 2066        key_context.set("mode", mode);
 2067        if self.pending_rename.is_some() {
 2068            key_context.add("renaming");
 2069        }
 2070
 2071        match self.context_menu.borrow().as_ref() {
 2072            Some(CodeContextMenu::Completions(_)) => {
 2073                key_context.add("menu");
 2074                key_context.add("showing_completions");
 2075            }
 2076            Some(CodeContextMenu::CodeActions(_)) => {
 2077                key_context.add("menu");
 2078                key_context.add("showing_code_actions")
 2079            }
 2080            None => {}
 2081        }
 2082
 2083        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2084        if !self.focus_handle(cx).contains_focused(window, cx)
 2085            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2086        {
 2087            for addon in self.addons.values() {
 2088                addon.extend_key_context(&mut key_context, cx)
 2089            }
 2090        }
 2091
 2092        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2093            if let Some(extension) = singleton_buffer
 2094                .read(cx)
 2095                .file()
 2096                .and_then(|file| file.path().extension()?.to_str())
 2097            {
 2098                key_context.set("extension", extension.to_string());
 2099            }
 2100        } else {
 2101            key_context.add("multibuffer");
 2102        }
 2103
 2104        if has_active_edit_prediction {
 2105            if self.edit_prediction_in_conflict() {
 2106                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2107            } else {
 2108                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2109                key_context.add("copilot_suggestion");
 2110            }
 2111        }
 2112
 2113        if self.selection_mark_mode {
 2114            key_context.add("selection_mode");
 2115        }
 2116
 2117        key_context
 2118    }
 2119
 2120    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2121        self.mouse_cursor_hidden = match origin {
 2122            HideMouseCursorOrigin::TypingAction => {
 2123                matches!(
 2124                    self.hide_mouse_mode,
 2125                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2126                )
 2127            }
 2128            HideMouseCursorOrigin::MovementAction => {
 2129                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2130            }
 2131        };
 2132    }
 2133
 2134    pub fn edit_prediction_in_conflict(&self) -> bool {
 2135        if !self.show_edit_predictions_in_menu() {
 2136            return false;
 2137        }
 2138
 2139        let showing_completions = self
 2140            .context_menu
 2141            .borrow()
 2142            .as_ref()
 2143            .map_or(false, |context| {
 2144                matches!(context, CodeContextMenu::Completions(_))
 2145            });
 2146
 2147        showing_completions
 2148            || self.edit_prediction_requires_modifier()
 2149            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2150            // bindings to insert tab characters.
 2151            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2152    }
 2153
 2154    pub fn accept_edit_prediction_keybind(
 2155        &self,
 2156        window: &Window,
 2157        cx: &App,
 2158    ) -> AcceptEditPredictionBinding {
 2159        let key_context = self.key_context_internal(true, window, cx);
 2160        let in_conflict = self.edit_prediction_in_conflict();
 2161
 2162        AcceptEditPredictionBinding(
 2163            window
 2164                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2165                .into_iter()
 2166                .filter(|binding| {
 2167                    !in_conflict
 2168                        || binding
 2169                            .keystrokes()
 2170                            .first()
 2171                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2172                })
 2173                .rev()
 2174                .min_by_key(|binding| {
 2175                    binding
 2176                        .keystrokes()
 2177                        .first()
 2178                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2179                }),
 2180        )
 2181    }
 2182
 2183    pub fn new_file(
 2184        workspace: &mut Workspace,
 2185        _: &workspace::NewFile,
 2186        window: &mut Window,
 2187        cx: &mut Context<Workspace>,
 2188    ) {
 2189        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2190            "Failed to create buffer",
 2191            window,
 2192            cx,
 2193            |e, _, _| match e.error_code() {
 2194                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2195                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2196                e.error_tag("required").unwrap_or("the latest version")
 2197            )),
 2198                _ => None,
 2199            },
 2200        );
 2201    }
 2202
 2203    pub fn new_in_workspace(
 2204        workspace: &mut Workspace,
 2205        window: &mut Window,
 2206        cx: &mut Context<Workspace>,
 2207    ) -> Task<Result<Entity<Editor>>> {
 2208        let project = workspace.project().clone();
 2209        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2210
 2211        cx.spawn_in(window, async move |workspace, cx| {
 2212            let buffer = create.await?;
 2213            workspace.update_in(cx, |workspace, window, cx| {
 2214                let editor =
 2215                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2216                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2217                editor
 2218            })
 2219        })
 2220    }
 2221
 2222    fn new_file_vertical(
 2223        workspace: &mut Workspace,
 2224        _: &workspace::NewFileSplitVertical,
 2225        window: &mut Window,
 2226        cx: &mut Context<Workspace>,
 2227    ) {
 2228        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2229    }
 2230
 2231    fn new_file_horizontal(
 2232        workspace: &mut Workspace,
 2233        _: &workspace::NewFileSplitHorizontal,
 2234        window: &mut Window,
 2235        cx: &mut Context<Workspace>,
 2236    ) {
 2237        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2238    }
 2239
 2240    fn new_file_in_direction(
 2241        workspace: &mut Workspace,
 2242        direction: SplitDirection,
 2243        window: &mut Window,
 2244        cx: &mut Context<Workspace>,
 2245    ) {
 2246        let project = workspace.project().clone();
 2247        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2248
 2249        cx.spawn_in(window, async move |workspace, cx| {
 2250            let buffer = create.await?;
 2251            workspace.update_in(cx, move |workspace, window, cx| {
 2252                workspace.split_item(
 2253                    direction,
 2254                    Box::new(
 2255                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2256                    ),
 2257                    window,
 2258                    cx,
 2259                )
 2260            })?;
 2261            anyhow::Ok(())
 2262        })
 2263        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2264            match e.error_code() {
 2265                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2266                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2267                e.error_tag("required").unwrap_or("the latest version")
 2268            )),
 2269                _ => None,
 2270            }
 2271        });
 2272    }
 2273
 2274    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2275        self.leader_id
 2276    }
 2277
 2278    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2279        &self.buffer
 2280    }
 2281
 2282    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2283        self.workspace.as_ref()?.0.upgrade()
 2284    }
 2285
 2286    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2287        self.buffer().read(cx).title(cx)
 2288    }
 2289
 2290    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2291        let git_blame_gutter_max_author_length = self
 2292            .render_git_blame_gutter(cx)
 2293            .then(|| {
 2294                if let Some(blame) = self.blame.as_ref() {
 2295                    let max_author_length =
 2296                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2297                    Some(max_author_length)
 2298                } else {
 2299                    None
 2300                }
 2301            })
 2302            .flatten();
 2303
 2304        EditorSnapshot {
 2305            mode: self.mode.clone(),
 2306            show_gutter: self.show_gutter,
 2307            show_line_numbers: self.show_line_numbers,
 2308            show_git_diff_gutter: self.show_git_diff_gutter,
 2309            show_runnables: self.show_runnables,
 2310            show_breakpoints: self.show_breakpoints,
 2311            git_blame_gutter_max_author_length,
 2312            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2313            scroll_anchor: self.scroll_manager.anchor(),
 2314            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2315            placeholder_text: self.placeholder_text.clone(),
 2316            is_focused: self.focus_handle.is_focused(window),
 2317            current_line_highlight: self
 2318                .current_line_highlight
 2319                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2320            gutter_hovered: self.gutter_hovered,
 2321        }
 2322    }
 2323
 2324    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2325        self.buffer.read(cx).language_at(point, cx)
 2326    }
 2327
 2328    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2329        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2330    }
 2331
 2332    pub fn active_excerpt(
 2333        &self,
 2334        cx: &App,
 2335    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2336        self.buffer
 2337            .read(cx)
 2338            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2339    }
 2340
 2341    pub fn mode(&self) -> &EditorMode {
 2342        &self.mode
 2343    }
 2344
 2345    pub fn set_mode(&mut self, mode: EditorMode) {
 2346        self.mode = mode;
 2347    }
 2348
 2349    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2350        self.collaboration_hub.as_deref()
 2351    }
 2352
 2353    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2354        self.collaboration_hub = Some(hub);
 2355    }
 2356
 2357    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2358        self.in_project_search = in_project_search;
 2359    }
 2360
 2361    pub fn set_custom_context_menu(
 2362        &mut self,
 2363        f: impl 'static
 2364        + Fn(
 2365            &mut Self,
 2366            DisplayPoint,
 2367            &mut Window,
 2368            &mut Context<Self>,
 2369        ) -> Option<Entity<ui::ContextMenu>>,
 2370    ) {
 2371        self.custom_context_menu = Some(Box::new(f))
 2372    }
 2373
 2374    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2375        self.completion_provider = provider;
 2376    }
 2377
 2378    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2379        self.semantics_provider.clone()
 2380    }
 2381
 2382    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2383        self.semantics_provider = provider;
 2384    }
 2385
 2386    pub fn set_edit_prediction_provider<T>(
 2387        &mut self,
 2388        provider: Option<Entity<T>>,
 2389        window: &mut Window,
 2390        cx: &mut Context<Self>,
 2391    ) where
 2392        T: EditPredictionProvider,
 2393    {
 2394        self.edit_prediction_provider =
 2395            provider.map(|provider| RegisteredInlineCompletionProvider {
 2396                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2397                    if this.focus_handle.is_focused(window) {
 2398                        this.update_visible_inline_completion(window, cx);
 2399                    }
 2400                }),
 2401                provider: Arc::new(provider),
 2402            });
 2403        self.update_edit_prediction_settings(cx);
 2404        self.refresh_inline_completion(false, false, window, cx);
 2405    }
 2406
 2407    pub fn placeholder_text(&self) -> Option<&str> {
 2408        self.placeholder_text.as_deref()
 2409    }
 2410
 2411    pub fn set_placeholder_text(
 2412        &mut self,
 2413        placeholder_text: impl Into<Arc<str>>,
 2414        cx: &mut Context<Self>,
 2415    ) {
 2416        let placeholder_text = Some(placeholder_text.into());
 2417        if self.placeholder_text != placeholder_text {
 2418            self.placeholder_text = placeholder_text;
 2419            cx.notify();
 2420        }
 2421    }
 2422
 2423    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2424        self.cursor_shape = cursor_shape;
 2425
 2426        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2427        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2428
 2429        cx.notify();
 2430    }
 2431
 2432    pub fn set_current_line_highlight(
 2433        &mut self,
 2434        current_line_highlight: Option<CurrentLineHighlight>,
 2435    ) {
 2436        self.current_line_highlight = current_line_highlight;
 2437    }
 2438
 2439    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2440        self.collapse_matches = collapse_matches;
 2441    }
 2442
 2443    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2444        let buffers = self.buffer.read(cx).all_buffers();
 2445        let Some(project) = self.project.as_ref() else {
 2446            return;
 2447        };
 2448        project.update(cx, |project, cx| {
 2449            for buffer in buffers {
 2450                self.registered_buffers
 2451                    .entry(buffer.read(cx).remote_id())
 2452                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2453            }
 2454        })
 2455    }
 2456
 2457    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2458        if self.collapse_matches {
 2459            return range.start..range.start;
 2460        }
 2461        range.clone()
 2462    }
 2463
 2464    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2465        if self.display_map.read(cx).clip_at_line_ends != clip {
 2466            self.display_map
 2467                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2468        }
 2469    }
 2470
 2471    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2472        self.input_enabled = input_enabled;
 2473    }
 2474
 2475    pub fn set_inline_completions_hidden_for_vim_mode(
 2476        &mut self,
 2477        hidden: bool,
 2478        window: &mut Window,
 2479        cx: &mut Context<Self>,
 2480    ) {
 2481        if hidden != self.inline_completions_hidden_for_vim_mode {
 2482            self.inline_completions_hidden_for_vim_mode = hidden;
 2483            if hidden {
 2484                self.update_visible_inline_completion(window, cx);
 2485            } else {
 2486                self.refresh_inline_completion(true, false, window, cx);
 2487            }
 2488        }
 2489    }
 2490
 2491    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2492        self.menu_inline_completions_policy = value;
 2493    }
 2494
 2495    pub fn set_autoindent(&mut self, autoindent: bool) {
 2496        if autoindent {
 2497            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2498        } else {
 2499            self.autoindent_mode = None;
 2500        }
 2501    }
 2502
 2503    pub fn read_only(&self, cx: &App) -> bool {
 2504        self.read_only || self.buffer.read(cx).read_only()
 2505    }
 2506
 2507    pub fn set_read_only(&mut self, read_only: bool) {
 2508        self.read_only = read_only;
 2509    }
 2510
 2511    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2512        self.use_autoclose = autoclose;
 2513    }
 2514
 2515    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2516        self.use_auto_surround = auto_surround;
 2517    }
 2518
 2519    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2520        self.auto_replace_emoji_shortcode = auto_replace;
 2521    }
 2522
 2523    pub fn toggle_edit_predictions(
 2524        &mut self,
 2525        _: &ToggleEditPrediction,
 2526        window: &mut Window,
 2527        cx: &mut Context<Self>,
 2528    ) {
 2529        if self.show_inline_completions_override.is_some() {
 2530            self.set_show_edit_predictions(None, window, cx);
 2531        } else {
 2532            let show_edit_predictions = !self.edit_predictions_enabled();
 2533            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2534        }
 2535    }
 2536
 2537    pub fn set_show_edit_predictions(
 2538        &mut self,
 2539        show_edit_predictions: Option<bool>,
 2540        window: &mut Window,
 2541        cx: &mut Context<Self>,
 2542    ) {
 2543        self.show_inline_completions_override = show_edit_predictions;
 2544        self.update_edit_prediction_settings(cx);
 2545
 2546        if let Some(false) = show_edit_predictions {
 2547            self.discard_inline_completion(false, cx);
 2548        } else {
 2549            self.refresh_inline_completion(false, true, window, cx);
 2550        }
 2551    }
 2552
 2553    fn inline_completions_disabled_in_scope(
 2554        &self,
 2555        buffer: &Entity<Buffer>,
 2556        buffer_position: language::Anchor,
 2557        cx: &App,
 2558    ) -> bool {
 2559        let snapshot = buffer.read(cx).snapshot();
 2560        let settings = snapshot.settings_at(buffer_position, cx);
 2561
 2562        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2563            return false;
 2564        };
 2565
 2566        scope.override_name().map_or(false, |scope_name| {
 2567            settings
 2568                .edit_predictions_disabled_in
 2569                .iter()
 2570                .any(|s| s == scope_name)
 2571        })
 2572    }
 2573
 2574    pub fn set_use_modal_editing(&mut self, to: bool) {
 2575        self.use_modal_editing = to;
 2576    }
 2577
 2578    pub fn use_modal_editing(&self) -> bool {
 2579        self.use_modal_editing
 2580    }
 2581
 2582    fn selections_did_change(
 2583        &mut self,
 2584        local: bool,
 2585        old_cursor_position: &Anchor,
 2586        show_completions: bool,
 2587        window: &mut Window,
 2588        cx: &mut Context<Self>,
 2589    ) {
 2590        window.invalidate_character_coordinates();
 2591
 2592        // Copy selections to primary selection buffer
 2593        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2594        if local {
 2595            let selections = self.selections.all::<usize>(cx);
 2596            let buffer_handle = self.buffer.read(cx).read(cx);
 2597
 2598            let mut text = String::new();
 2599            for (index, selection) in selections.iter().enumerate() {
 2600                let text_for_selection = buffer_handle
 2601                    .text_for_range(selection.start..selection.end)
 2602                    .collect::<String>();
 2603
 2604                text.push_str(&text_for_selection);
 2605                if index != selections.len() - 1 {
 2606                    text.push('\n');
 2607                }
 2608            }
 2609
 2610            if !text.is_empty() {
 2611                cx.write_to_primary(ClipboardItem::new_string(text));
 2612            }
 2613        }
 2614
 2615        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2616            self.buffer.update(cx, |buffer, cx| {
 2617                buffer.set_active_selections(
 2618                    &self.selections.disjoint_anchors(),
 2619                    self.selections.line_mode,
 2620                    self.cursor_shape,
 2621                    cx,
 2622                )
 2623            });
 2624        }
 2625        let display_map = self
 2626            .display_map
 2627            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2628        let buffer = &display_map.buffer_snapshot;
 2629        self.add_selections_state = None;
 2630        self.select_next_state = None;
 2631        self.select_prev_state = None;
 2632        self.select_syntax_node_history.try_clear();
 2633        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2634        self.snippet_stack
 2635            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2636        self.take_rename(false, window, cx);
 2637
 2638        let new_cursor_position = self.selections.newest_anchor().head();
 2639
 2640        self.push_to_nav_history(
 2641            *old_cursor_position,
 2642            Some(new_cursor_position.to_point(buffer)),
 2643            false,
 2644            cx,
 2645        );
 2646
 2647        if local {
 2648            let new_cursor_position = self.selections.newest_anchor().head();
 2649            let mut context_menu = self.context_menu.borrow_mut();
 2650            let completion_menu = match context_menu.as_ref() {
 2651                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2652                _ => {
 2653                    *context_menu = None;
 2654                    None
 2655                }
 2656            };
 2657            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2658                if !self.registered_buffers.contains_key(&buffer_id) {
 2659                    if let Some(project) = self.project.as_ref() {
 2660                        project.update(cx, |project, cx| {
 2661                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2662                                return;
 2663                            };
 2664                            self.registered_buffers.insert(
 2665                                buffer_id,
 2666                                project.register_buffer_with_language_servers(&buffer, cx),
 2667                            );
 2668                        })
 2669                    }
 2670                }
 2671            }
 2672
 2673            if let Some(completion_menu) = completion_menu {
 2674                let cursor_position = new_cursor_position.to_offset(buffer);
 2675                let (word_range, kind) =
 2676                    buffer.surrounding_word(completion_menu.initial_position, true);
 2677                if kind == Some(CharKind::Word)
 2678                    && word_range.to_inclusive().contains(&cursor_position)
 2679                {
 2680                    let mut completion_menu = completion_menu.clone();
 2681                    drop(context_menu);
 2682
 2683                    let query = Self::completion_query(buffer, cursor_position);
 2684                    cx.spawn(async move |this, cx| {
 2685                        completion_menu
 2686                            .filter(query.as_deref(), cx.background_executor().clone())
 2687                            .await;
 2688
 2689                        this.update(cx, |this, cx| {
 2690                            let mut context_menu = this.context_menu.borrow_mut();
 2691                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2692                            else {
 2693                                return;
 2694                            };
 2695
 2696                            if menu.id > completion_menu.id {
 2697                                return;
 2698                            }
 2699
 2700                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2701                            drop(context_menu);
 2702                            cx.notify();
 2703                        })
 2704                    })
 2705                    .detach();
 2706
 2707                    if show_completions {
 2708                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2709                    }
 2710                } else {
 2711                    drop(context_menu);
 2712                    self.hide_context_menu(window, cx);
 2713                }
 2714            } else {
 2715                drop(context_menu);
 2716            }
 2717
 2718            hide_hover(self, cx);
 2719
 2720            if old_cursor_position.to_display_point(&display_map).row()
 2721                != new_cursor_position.to_display_point(&display_map).row()
 2722            {
 2723                self.available_code_actions.take();
 2724            }
 2725            self.refresh_code_actions(window, cx);
 2726            self.refresh_document_highlights(cx);
 2727            self.refresh_selected_text_highlights(false, window, cx);
 2728            refresh_matching_bracket_highlights(self, window, cx);
 2729            self.update_visible_inline_completion(window, cx);
 2730            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2731            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2732            self.inline_blame_popover.take();
 2733            if self.git_blame_inline_enabled {
 2734                self.start_inline_blame_timer(window, cx);
 2735            }
 2736        }
 2737
 2738        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2739        cx.emit(EditorEvent::SelectionsChanged { local });
 2740
 2741        let selections = &self.selections.disjoint;
 2742        if selections.len() == 1 {
 2743            cx.emit(SearchEvent::ActiveMatchChanged)
 2744        }
 2745        if local {
 2746            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2747                let inmemory_selections = selections
 2748                    .iter()
 2749                    .map(|s| {
 2750                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2751                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2752                    })
 2753                    .collect();
 2754                self.update_restoration_data(cx, |data| {
 2755                    data.selections = inmemory_selections;
 2756                });
 2757
 2758                if WorkspaceSettings::get(None, cx).restore_on_startup
 2759                    != RestoreOnStartupBehavior::None
 2760                {
 2761                    if let Some(workspace_id) =
 2762                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2763                    {
 2764                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2765                        let selections = selections.clone();
 2766                        let background_executor = cx.background_executor().clone();
 2767                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2768                        self.serialize_selections = cx.background_spawn(async move {
 2769                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2770                    let db_selections = selections
 2771                        .iter()
 2772                        .map(|selection| {
 2773                            (
 2774                                selection.start.to_offset(&snapshot),
 2775                                selection.end.to_offset(&snapshot),
 2776                            )
 2777                        })
 2778                        .collect();
 2779
 2780                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2781                        .await
 2782                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2783                        .log_err();
 2784                });
 2785                    }
 2786                }
 2787            }
 2788        }
 2789
 2790        cx.notify();
 2791    }
 2792
 2793    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2794        use text::ToOffset as _;
 2795        use text::ToPoint as _;
 2796
 2797        if self.mode.is_minimap()
 2798            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2799        {
 2800            return;
 2801        }
 2802
 2803        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2804            return;
 2805        };
 2806
 2807        let snapshot = singleton.read(cx).snapshot();
 2808        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2809            let display_snapshot = display_map.snapshot(cx);
 2810
 2811            display_snapshot
 2812                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2813                .map(|fold| {
 2814                    fold.range.start.text_anchor.to_point(&snapshot)
 2815                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2816                })
 2817                .collect()
 2818        });
 2819        self.update_restoration_data(cx, |data| {
 2820            data.folds = inmemory_folds;
 2821        });
 2822
 2823        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2824            return;
 2825        };
 2826        let background_executor = cx.background_executor().clone();
 2827        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2828        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2829            display_map
 2830                .snapshot(cx)
 2831                .folds_in_range(0..snapshot.len())
 2832                .map(|fold| {
 2833                    (
 2834                        fold.range.start.text_anchor.to_offset(&snapshot),
 2835                        fold.range.end.text_anchor.to_offset(&snapshot),
 2836                    )
 2837                })
 2838                .collect()
 2839        });
 2840        self.serialize_folds = cx.background_spawn(async move {
 2841            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2842            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2843                .await
 2844                .with_context(|| {
 2845                    format!(
 2846                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2847                    )
 2848                })
 2849                .log_err();
 2850        });
 2851    }
 2852
 2853    pub fn sync_selections(
 2854        &mut self,
 2855        other: Entity<Editor>,
 2856        cx: &mut Context<Self>,
 2857    ) -> gpui::Subscription {
 2858        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2859        self.selections.change_with(cx, |selections| {
 2860            selections.select_anchors(other_selections);
 2861        });
 2862
 2863        let other_subscription =
 2864            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2865                EditorEvent::SelectionsChanged { local: true } => {
 2866                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2867                    if other_selections.is_empty() {
 2868                        return;
 2869                    }
 2870                    this.selections.change_with(cx, |selections| {
 2871                        selections.select_anchors(other_selections);
 2872                    });
 2873                }
 2874                _ => {}
 2875            });
 2876
 2877        let this_subscription =
 2878            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2879                EditorEvent::SelectionsChanged { local: true } => {
 2880                    let these_selections = this.selections.disjoint.to_vec();
 2881                    if these_selections.is_empty() {
 2882                        return;
 2883                    }
 2884                    other.update(cx, |other_editor, cx| {
 2885                        other_editor.selections.change_with(cx, |selections| {
 2886                            selections.select_anchors(these_selections);
 2887                        })
 2888                    });
 2889                }
 2890                _ => {}
 2891            });
 2892
 2893        Subscription::join(other_subscription, this_subscription)
 2894    }
 2895
 2896    pub fn change_selections<R>(
 2897        &mut self,
 2898        autoscroll: Option<Autoscroll>,
 2899        window: &mut Window,
 2900        cx: &mut Context<Self>,
 2901        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2902    ) -> R {
 2903        self.change_selections_inner(autoscroll, true, window, cx, change)
 2904    }
 2905
 2906    fn change_selections_inner<R>(
 2907        &mut self,
 2908        autoscroll: Option<Autoscroll>,
 2909        request_completions: bool,
 2910        window: &mut Window,
 2911        cx: &mut Context<Self>,
 2912        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2913    ) -> R {
 2914        let old_cursor_position = self.selections.newest_anchor().head();
 2915        self.push_to_selection_history();
 2916
 2917        let (changed, result) = self.selections.change_with(cx, change);
 2918
 2919        if changed {
 2920            if let Some(autoscroll) = autoscroll {
 2921                self.request_autoscroll(autoscroll, cx);
 2922            }
 2923            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2924
 2925            if self.should_open_signature_help_automatically(
 2926                &old_cursor_position,
 2927                self.signature_help_state.backspace_pressed(),
 2928                cx,
 2929            ) {
 2930                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2931            }
 2932            self.signature_help_state.set_backspace_pressed(false);
 2933        }
 2934
 2935        result
 2936    }
 2937
 2938    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2939    where
 2940        I: IntoIterator<Item = (Range<S>, T)>,
 2941        S: ToOffset,
 2942        T: Into<Arc<str>>,
 2943    {
 2944        if self.read_only(cx) {
 2945            return;
 2946        }
 2947
 2948        self.buffer
 2949            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2950    }
 2951
 2952    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2953    where
 2954        I: IntoIterator<Item = (Range<S>, T)>,
 2955        S: ToOffset,
 2956        T: Into<Arc<str>>,
 2957    {
 2958        if self.read_only(cx) {
 2959            return;
 2960        }
 2961
 2962        self.buffer.update(cx, |buffer, cx| {
 2963            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2964        });
 2965    }
 2966
 2967    pub fn edit_with_block_indent<I, S, T>(
 2968        &mut self,
 2969        edits: I,
 2970        original_indent_columns: Vec<Option<u32>>,
 2971        cx: &mut Context<Self>,
 2972    ) where
 2973        I: IntoIterator<Item = (Range<S>, T)>,
 2974        S: ToOffset,
 2975        T: Into<Arc<str>>,
 2976    {
 2977        if self.read_only(cx) {
 2978            return;
 2979        }
 2980
 2981        self.buffer.update(cx, |buffer, cx| {
 2982            buffer.edit(
 2983                edits,
 2984                Some(AutoindentMode::Block {
 2985                    original_indent_columns,
 2986                }),
 2987                cx,
 2988            )
 2989        });
 2990    }
 2991
 2992    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2993        self.hide_context_menu(window, cx);
 2994
 2995        match phase {
 2996            SelectPhase::Begin {
 2997                position,
 2998                add,
 2999                click_count,
 3000            } => self.begin_selection(position, add, click_count, window, cx),
 3001            SelectPhase::BeginColumnar {
 3002                position,
 3003                goal_column,
 3004                reset,
 3005            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3006            SelectPhase::Extend {
 3007                position,
 3008                click_count,
 3009            } => self.extend_selection(position, click_count, window, cx),
 3010            SelectPhase::Update {
 3011                position,
 3012                goal_column,
 3013                scroll_delta,
 3014            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3015            SelectPhase::End => self.end_selection(window, cx),
 3016        }
 3017    }
 3018
 3019    fn extend_selection(
 3020        &mut self,
 3021        position: DisplayPoint,
 3022        click_count: usize,
 3023        window: &mut Window,
 3024        cx: &mut Context<Self>,
 3025    ) {
 3026        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3027        let tail = self.selections.newest::<usize>(cx).tail();
 3028        self.begin_selection(position, false, click_count, window, cx);
 3029
 3030        let position = position.to_offset(&display_map, Bias::Left);
 3031        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3032
 3033        let mut pending_selection = self
 3034            .selections
 3035            .pending_anchor()
 3036            .expect("extend_selection not called with pending selection");
 3037        if position >= tail {
 3038            pending_selection.start = tail_anchor;
 3039        } else {
 3040            pending_selection.end = tail_anchor;
 3041            pending_selection.reversed = true;
 3042        }
 3043
 3044        let mut pending_mode = self.selections.pending_mode().unwrap();
 3045        match &mut pending_mode {
 3046            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3047            _ => {}
 3048        }
 3049
 3050        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3051
 3052        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3053            s.set_pending(pending_selection, pending_mode)
 3054        });
 3055    }
 3056
 3057    fn begin_selection(
 3058        &mut self,
 3059        position: DisplayPoint,
 3060        add: bool,
 3061        click_count: usize,
 3062        window: &mut Window,
 3063        cx: &mut Context<Self>,
 3064    ) {
 3065        if !self.focus_handle.is_focused(window) {
 3066            self.last_focused_descendant = None;
 3067            window.focus(&self.focus_handle);
 3068        }
 3069
 3070        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3071        let buffer = &display_map.buffer_snapshot;
 3072        let position = display_map.clip_point(position, Bias::Left);
 3073
 3074        let start;
 3075        let end;
 3076        let mode;
 3077        let mut auto_scroll;
 3078        match click_count {
 3079            1 => {
 3080                start = buffer.anchor_before(position.to_point(&display_map));
 3081                end = start;
 3082                mode = SelectMode::Character;
 3083                auto_scroll = true;
 3084            }
 3085            2 => {
 3086                let range = movement::surrounding_word(&display_map, position);
 3087                start = buffer.anchor_before(range.start.to_point(&display_map));
 3088                end = buffer.anchor_before(range.end.to_point(&display_map));
 3089                mode = SelectMode::Word(start..end);
 3090                auto_scroll = true;
 3091            }
 3092            3 => {
 3093                let position = display_map
 3094                    .clip_point(position, Bias::Left)
 3095                    .to_point(&display_map);
 3096                let line_start = display_map.prev_line_boundary(position).0;
 3097                let next_line_start = buffer.clip_point(
 3098                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3099                    Bias::Left,
 3100                );
 3101                start = buffer.anchor_before(line_start);
 3102                end = buffer.anchor_before(next_line_start);
 3103                mode = SelectMode::Line(start..end);
 3104                auto_scroll = true;
 3105            }
 3106            _ => {
 3107                start = buffer.anchor_before(0);
 3108                end = buffer.anchor_before(buffer.len());
 3109                mode = SelectMode::All;
 3110                auto_scroll = false;
 3111            }
 3112        }
 3113        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3114
 3115        let point_to_delete: Option<usize> = {
 3116            let selected_points: Vec<Selection<Point>> =
 3117                self.selections.disjoint_in_range(start..end, cx);
 3118
 3119            if !add || click_count > 1 {
 3120                None
 3121            } else if !selected_points.is_empty() {
 3122                Some(selected_points[0].id)
 3123            } else {
 3124                let clicked_point_already_selected =
 3125                    self.selections.disjoint.iter().find(|selection| {
 3126                        selection.start.to_point(buffer) == start.to_point(buffer)
 3127                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3128                    });
 3129
 3130                clicked_point_already_selected.map(|selection| selection.id)
 3131            }
 3132        };
 3133
 3134        let selections_count = self.selections.count();
 3135
 3136        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3137            if let Some(point_to_delete) = point_to_delete {
 3138                s.delete(point_to_delete);
 3139
 3140                if selections_count == 1 {
 3141                    s.set_pending_anchor_range(start..end, mode);
 3142                }
 3143            } else {
 3144                if !add {
 3145                    s.clear_disjoint();
 3146                }
 3147
 3148                s.set_pending_anchor_range(start..end, mode);
 3149            }
 3150        });
 3151    }
 3152
 3153    fn begin_columnar_selection(
 3154        &mut self,
 3155        position: DisplayPoint,
 3156        goal_column: u32,
 3157        reset: bool,
 3158        window: &mut Window,
 3159        cx: &mut Context<Self>,
 3160    ) {
 3161        if !self.focus_handle.is_focused(window) {
 3162            self.last_focused_descendant = None;
 3163            window.focus(&self.focus_handle);
 3164        }
 3165
 3166        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3167
 3168        if reset {
 3169            let pointer_position = display_map
 3170                .buffer_snapshot
 3171                .anchor_before(position.to_point(&display_map));
 3172
 3173            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3174                s.clear_disjoint();
 3175                s.set_pending_anchor_range(
 3176                    pointer_position..pointer_position,
 3177                    SelectMode::Character,
 3178                );
 3179            });
 3180        }
 3181
 3182        let tail = self.selections.newest::<Point>(cx).tail();
 3183        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3184
 3185        if !reset {
 3186            self.select_columns(
 3187                tail.to_display_point(&display_map),
 3188                position,
 3189                goal_column,
 3190                &display_map,
 3191                window,
 3192                cx,
 3193            );
 3194        }
 3195    }
 3196
 3197    fn update_selection(
 3198        &mut self,
 3199        position: DisplayPoint,
 3200        goal_column: u32,
 3201        scroll_delta: gpui::Point<f32>,
 3202        window: &mut Window,
 3203        cx: &mut Context<Self>,
 3204    ) {
 3205        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3206
 3207        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3208            let tail = tail.to_display_point(&display_map);
 3209            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3210        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3211            let buffer = self.buffer.read(cx).snapshot(cx);
 3212            let head;
 3213            let tail;
 3214            let mode = self.selections.pending_mode().unwrap();
 3215            match &mode {
 3216                SelectMode::Character => {
 3217                    head = position.to_point(&display_map);
 3218                    tail = pending.tail().to_point(&buffer);
 3219                }
 3220                SelectMode::Word(original_range) => {
 3221                    let original_display_range = original_range.start.to_display_point(&display_map)
 3222                        ..original_range.end.to_display_point(&display_map);
 3223                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3224                        ..original_display_range.end.to_point(&display_map);
 3225                    if movement::is_inside_word(&display_map, position)
 3226                        || original_display_range.contains(&position)
 3227                    {
 3228                        let word_range = movement::surrounding_word(&display_map, position);
 3229                        if word_range.start < original_display_range.start {
 3230                            head = word_range.start.to_point(&display_map);
 3231                        } else {
 3232                            head = word_range.end.to_point(&display_map);
 3233                        }
 3234                    } else {
 3235                        head = position.to_point(&display_map);
 3236                    }
 3237
 3238                    if head <= original_buffer_range.start {
 3239                        tail = original_buffer_range.end;
 3240                    } else {
 3241                        tail = original_buffer_range.start;
 3242                    }
 3243                }
 3244                SelectMode::Line(original_range) => {
 3245                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3246
 3247                    let position = display_map
 3248                        .clip_point(position, Bias::Left)
 3249                        .to_point(&display_map);
 3250                    let line_start = display_map.prev_line_boundary(position).0;
 3251                    let next_line_start = buffer.clip_point(
 3252                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3253                        Bias::Left,
 3254                    );
 3255
 3256                    if line_start < original_range.start {
 3257                        head = line_start
 3258                    } else {
 3259                        head = next_line_start
 3260                    }
 3261
 3262                    if head <= original_range.start {
 3263                        tail = original_range.end;
 3264                    } else {
 3265                        tail = original_range.start;
 3266                    }
 3267                }
 3268                SelectMode::All => {
 3269                    return;
 3270                }
 3271            };
 3272
 3273            if head < tail {
 3274                pending.start = buffer.anchor_before(head);
 3275                pending.end = buffer.anchor_before(tail);
 3276                pending.reversed = true;
 3277            } else {
 3278                pending.start = buffer.anchor_before(tail);
 3279                pending.end = buffer.anchor_before(head);
 3280                pending.reversed = false;
 3281            }
 3282
 3283            self.change_selections(None, window, cx, |s| {
 3284                s.set_pending(pending, mode);
 3285            });
 3286        } else {
 3287            log::error!("update_selection dispatched with no pending selection");
 3288            return;
 3289        }
 3290
 3291        self.apply_scroll_delta(scroll_delta, window, cx);
 3292        cx.notify();
 3293    }
 3294
 3295    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3296        self.columnar_selection_tail.take();
 3297        if self.selections.pending_anchor().is_some() {
 3298            let selections = self.selections.all::<usize>(cx);
 3299            self.change_selections(None, window, cx, |s| {
 3300                s.select(selections);
 3301                s.clear_pending();
 3302            });
 3303        }
 3304    }
 3305
 3306    fn select_columns(
 3307        &mut self,
 3308        tail: DisplayPoint,
 3309        head: DisplayPoint,
 3310        goal_column: u32,
 3311        display_map: &DisplaySnapshot,
 3312        window: &mut Window,
 3313        cx: &mut Context<Self>,
 3314    ) {
 3315        let start_row = cmp::min(tail.row(), head.row());
 3316        let end_row = cmp::max(tail.row(), head.row());
 3317        let start_column = cmp::min(tail.column(), goal_column);
 3318        let end_column = cmp::max(tail.column(), goal_column);
 3319        let reversed = start_column < tail.column();
 3320
 3321        let selection_ranges = (start_row.0..=end_row.0)
 3322            .map(DisplayRow)
 3323            .filter_map(|row| {
 3324                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3325                    let start = display_map
 3326                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3327                        .to_point(display_map);
 3328                    let end = display_map
 3329                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3330                        .to_point(display_map);
 3331                    if reversed {
 3332                        Some(end..start)
 3333                    } else {
 3334                        Some(start..end)
 3335                    }
 3336                } else {
 3337                    None
 3338                }
 3339            })
 3340            .collect::<Vec<_>>();
 3341
 3342        self.change_selections(None, window, cx, |s| {
 3343            s.select_ranges(selection_ranges);
 3344        });
 3345        cx.notify();
 3346    }
 3347
 3348    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3349        self.selections
 3350            .all_adjusted(cx)
 3351            .iter()
 3352            .any(|selection| !selection.is_empty())
 3353    }
 3354
 3355    pub fn has_pending_nonempty_selection(&self) -> bool {
 3356        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3357            Some(Selection { start, end, .. }) => start != end,
 3358            None => false,
 3359        };
 3360
 3361        pending_nonempty_selection
 3362            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3363    }
 3364
 3365    pub fn has_pending_selection(&self) -> bool {
 3366        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3367    }
 3368
 3369    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3370        self.selection_mark_mode = false;
 3371
 3372        if self.clear_expanded_diff_hunks(cx) {
 3373            cx.notify();
 3374            return;
 3375        }
 3376        if self.dismiss_menus_and_popups(true, window, cx) {
 3377            return;
 3378        }
 3379
 3380        if self.mode.is_full()
 3381            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3382        {
 3383            return;
 3384        }
 3385
 3386        cx.propagate();
 3387    }
 3388
 3389    pub fn dismiss_menus_and_popups(
 3390        &mut self,
 3391        is_user_requested: bool,
 3392        window: &mut Window,
 3393        cx: &mut Context<Self>,
 3394    ) -> bool {
 3395        if self.take_rename(false, window, cx).is_some() {
 3396            return true;
 3397        }
 3398
 3399        if hide_hover(self, cx) {
 3400            return true;
 3401        }
 3402
 3403        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3404            return true;
 3405        }
 3406
 3407        if self.hide_context_menu(window, cx).is_some() {
 3408            return true;
 3409        }
 3410
 3411        if self.mouse_context_menu.take().is_some() {
 3412            return true;
 3413        }
 3414
 3415        if is_user_requested && self.discard_inline_completion(true, cx) {
 3416            return true;
 3417        }
 3418
 3419        if self.snippet_stack.pop().is_some() {
 3420            return true;
 3421        }
 3422
 3423        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3424            self.dismiss_diagnostics(cx);
 3425            return true;
 3426        }
 3427
 3428        false
 3429    }
 3430
 3431    fn linked_editing_ranges_for(
 3432        &self,
 3433        selection: Range<text::Anchor>,
 3434        cx: &App,
 3435    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3436        if self.linked_edit_ranges.is_empty() {
 3437            return None;
 3438        }
 3439        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3440            selection.end.buffer_id.and_then(|end_buffer_id| {
 3441                if selection.start.buffer_id != Some(end_buffer_id) {
 3442                    return None;
 3443                }
 3444                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3445                let snapshot = buffer.read(cx).snapshot();
 3446                self.linked_edit_ranges
 3447                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3448                    .map(|ranges| (ranges, snapshot, buffer))
 3449            })?;
 3450        use text::ToOffset as TO;
 3451        // find offset from the start of current range to current cursor position
 3452        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3453
 3454        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3455        let start_difference = start_offset - start_byte_offset;
 3456        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3457        let end_difference = end_offset - start_byte_offset;
 3458        // Current range has associated linked ranges.
 3459        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3460        for range in linked_ranges.iter() {
 3461            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3462            let end_offset = start_offset + end_difference;
 3463            let start_offset = start_offset + start_difference;
 3464            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3465                continue;
 3466            }
 3467            if self.selections.disjoint_anchor_ranges().any(|s| {
 3468                if s.start.buffer_id != selection.start.buffer_id
 3469                    || s.end.buffer_id != selection.end.buffer_id
 3470                {
 3471                    return false;
 3472                }
 3473                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3474                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3475            }) {
 3476                continue;
 3477            }
 3478            let start = buffer_snapshot.anchor_after(start_offset);
 3479            let end = buffer_snapshot.anchor_after(end_offset);
 3480            linked_edits
 3481                .entry(buffer.clone())
 3482                .or_default()
 3483                .push(start..end);
 3484        }
 3485        Some(linked_edits)
 3486    }
 3487
 3488    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3489        let text: Arc<str> = text.into();
 3490
 3491        if self.read_only(cx) {
 3492            return;
 3493        }
 3494
 3495        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3496
 3497        let selections = self.selections.all_adjusted(cx);
 3498        let mut bracket_inserted = false;
 3499        let mut edits = Vec::new();
 3500        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3501        let mut new_selections = Vec::with_capacity(selections.len());
 3502        let mut new_autoclose_regions = Vec::new();
 3503        let snapshot = self.buffer.read(cx).read(cx);
 3504        let mut clear_linked_edit_ranges = false;
 3505
 3506        for (selection, autoclose_region) in
 3507            self.selections_with_autoclose_regions(selections, &snapshot)
 3508        {
 3509            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3510                // Determine if the inserted text matches the opening or closing
 3511                // bracket of any of this language's bracket pairs.
 3512                let mut bracket_pair = None;
 3513                let mut is_bracket_pair_start = false;
 3514                let mut is_bracket_pair_end = false;
 3515                if !text.is_empty() {
 3516                    let mut bracket_pair_matching_end = None;
 3517                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3518                    //  and they are removing the character that triggered IME popup.
 3519                    for (pair, enabled) in scope.brackets() {
 3520                        if !pair.close && !pair.surround {
 3521                            continue;
 3522                        }
 3523
 3524                        if enabled && pair.start.ends_with(text.as_ref()) {
 3525                            let prefix_len = pair.start.len() - text.len();
 3526                            let preceding_text_matches_prefix = prefix_len == 0
 3527                                || (selection.start.column >= (prefix_len as u32)
 3528                                    && snapshot.contains_str_at(
 3529                                        Point::new(
 3530                                            selection.start.row,
 3531                                            selection.start.column - (prefix_len as u32),
 3532                                        ),
 3533                                        &pair.start[..prefix_len],
 3534                                    ));
 3535                            if preceding_text_matches_prefix {
 3536                                bracket_pair = Some(pair.clone());
 3537                                is_bracket_pair_start = true;
 3538                                break;
 3539                            }
 3540                        }
 3541                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3542                        {
 3543                            // take first bracket pair matching end, but don't break in case a later bracket
 3544                            // pair matches start
 3545                            bracket_pair_matching_end = Some(pair.clone());
 3546                        }
 3547                    }
 3548                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3549                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3550                        is_bracket_pair_end = true;
 3551                    }
 3552                }
 3553
 3554                if let Some(bracket_pair) = bracket_pair {
 3555                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3556                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3557                    let auto_surround =
 3558                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3559                    if selection.is_empty() {
 3560                        if is_bracket_pair_start {
 3561                            // If the inserted text is a suffix of an opening bracket and the
 3562                            // selection is preceded by the rest of the opening bracket, then
 3563                            // insert the closing bracket.
 3564                            let following_text_allows_autoclose = snapshot
 3565                                .chars_at(selection.start)
 3566                                .next()
 3567                                .map_or(true, |c| scope.should_autoclose_before(c));
 3568
 3569                            let preceding_text_allows_autoclose = selection.start.column == 0
 3570                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3571                                    true,
 3572                                    |c| {
 3573                                        bracket_pair.start != bracket_pair.end
 3574                                            || !snapshot
 3575                                                .char_classifier_at(selection.start)
 3576                                                .is_word(c)
 3577                                    },
 3578                                );
 3579
 3580                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3581                                && bracket_pair.start.len() == 1
 3582                            {
 3583                                let target = bracket_pair.start.chars().next().unwrap();
 3584                                let current_line_count = snapshot
 3585                                    .reversed_chars_at(selection.start)
 3586                                    .take_while(|&c| c != '\n')
 3587                                    .filter(|&c| c == target)
 3588                                    .count();
 3589                                current_line_count % 2 == 1
 3590                            } else {
 3591                                false
 3592                            };
 3593
 3594                            if autoclose
 3595                                && bracket_pair.close
 3596                                && following_text_allows_autoclose
 3597                                && preceding_text_allows_autoclose
 3598                                && !is_closing_quote
 3599                            {
 3600                                let anchor = snapshot.anchor_before(selection.end);
 3601                                new_selections.push((selection.map(|_| anchor), text.len()));
 3602                                new_autoclose_regions.push((
 3603                                    anchor,
 3604                                    text.len(),
 3605                                    selection.id,
 3606                                    bracket_pair.clone(),
 3607                                ));
 3608                                edits.push((
 3609                                    selection.range(),
 3610                                    format!("{}{}", text, bracket_pair.end).into(),
 3611                                ));
 3612                                bracket_inserted = true;
 3613                                continue;
 3614                            }
 3615                        }
 3616
 3617                        if let Some(region) = autoclose_region {
 3618                            // If the selection is followed by an auto-inserted closing bracket,
 3619                            // then don't insert that closing bracket again; just move the selection
 3620                            // past the closing bracket.
 3621                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3622                                && text.as_ref() == region.pair.end.as_str();
 3623                            if should_skip {
 3624                                let anchor = snapshot.anchor_after(selection.end);
 3625                                new_selections
 3626                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3627                                continue;
 3628                            }
 3629                        }
 3630
 3631                        let always_treat_brackets_as_autoclosed = snapshot
 3632                            .language_settings_at(selection.start, cx)
 3633                            .always_treat_brackets_as_autoclosed;
 3634                        if always_treat_brackets_as_autoclosed
 3635                            && is_bracket_pair_end
 3636                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3637                        {
 3638                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3639                            // and the inserted text is a closing bracket and the selection is followed
 3640                            // by the closing bracket then move the selection past the closing bracket.
 3641                            let anchor = snapshot.anchor_after(selection.end);
 3642                            new_selections.push((selection.map(|_| anchor), text.len()));
 3643                            continue;
 3644                        }
 3645                    }
 3646                    // If an opening bracket is 1 character long and is typed while
 3647                    // text is selected, then surround that text with the bracket pair.
 3648                    else if auto_surround
 3649                        && bracket_pair.surround
 3650                        && is_bracket_pair_start
 3651                        && bracket_pair.start.chars().count() == 1
 3652                    {
 3653                        edits.push((selection.start..selection.start, text.clone()));
 3654                        edits.push((
 3655                            selection.end..selection.end,
 3656                            bracket_pair.end.as_str().into(),
 3657                        ));
 3658                        bracket_inserted = true;
 3659                        new_selections.push((
 3660                            Selection {
 3661                                id: selection.id,
 3662                                start: snapshot.anchor_after(selection.start),
 3663                                end: snapshot.anchor_before(selection.end),
 3664                                reversed: selection.reversed,
 3665                                goal: selection.goal,
 3666                            },
 3667                            0,
 3668                        ));
 3669                        continue;
 3670                    }
 3671                }
 3672            }
 3673
 3674            if self.auto_replace_emoji_shortcode
 3675                && selection.is_empty()
 3676                && text.as_ref().ends_with(':')
 3677            {
 3678                if let Some(possible_emoji_short_code) =
 3679                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3680                {
 3681                    if !possible_emoji_short_code.is_empty() {
 3682                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3683                            let emoji_shortcode_start = Point::new(
 3684                                selection.start.row,
 3685                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3686                            );
 3687
 3688                            // Remove shortcode from buffer
 3689                            edits.push((
 3690                                emoji_shortcode_start..selection.start,
 3691                                "".to_string().into(),
 3692                            ));
 3693                            new_selections.push((
 3694                                Selection {
 3695                                    id: selection.id,
 3696                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3697                                    end: snapshot.anchor_before(selection.start),
 3698                                    reversed: selection.reversed,
 3699                                    goal: selection.goal,
 3700                                },
 3701                                0,
 3702                            ));
 3703
 3704                            // Insert emoji
 3705                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3706                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3707                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3708
 3709                            continue;
 3710                        }
 3711                    }
 3712                }
 3713            }
 3714
 3715            // If not handling any auto-close operation, then just replace the selected
 3716            // text with the given input and move the selection to the end of the
 3717            // newly inserted text.
 3718            let anchor = snapshot.anchor_after(selection.end);
 3719            if !self.linked_edit_ranges.is_empty() {
 3720                let start_anchor = snapshot.anchor_before(selection.start);
 3721
 3722                let is_word_char = text.chars().next().map_or(true, |char| {
 3723                    let classifier = snapshot
 3724                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3725                        .ignore_punctuation(true);
 3726                    classifier.is_word(char)
 3727                });
 3728
 3729                if is_word_char {
 3730                    if let Some(ranges) = self
 3731                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3732                    {
 3733                        for (buffer, edits) in ranges {
 3734                            linked_edits
 3735                                .entry(buffer.clone())
 3736                                .or_default()
 3737                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3738                        }
 3739                    }
 3740                } else {
 3741                    clear_linked_edit_ranges = true;
 3742                }
 3743            }
 3744
 3745            new_selections.push((selection.map(|_| anchor), 0));
 3746            edits.push((selection.start..selection.end, text.clone()));
 3747        }
 3748
 3749        drop(snapshot);
 3750
 3751        self.transact(window, cx, |this, window, cx| {
 3752            if clear_linked_edit_ranges {
 3753                this.linked_edit_ranges.clear();
 3754            }
 3755            let initial_buffer_versions =
 3756                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3757
 3758            this.buffer.update(cx, |buffer, cx| {
 3759                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3760            });
 3761            for (buffer, edits) in linked_edits {
 3762                buffer.update(cx, |buffer, cx| {
 3763                    let snapshot = buffer.snapshot();
 3764                    let edits = edits
 3765                        .into_iter()
 3766                        .map(|(range, text)| {
 3767                            use text::ToPoint as TP;
 3768                            let end_point = TP::to_point(&range.end, &snapshot);
 3769                            let start_point = TP::to_point(&range.start, &snapshot);
 3770                            (start_point..end_point, text)
 3771                        })
 3772                        .sorted_by_key(|(range, _)| range.start);
 3773                    buffer.edit(edits, None, cx);
 3774                })
 3775            }
 3776            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3777            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3778            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3779            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3780                .zip(new_selection_deltas)
 3781                .map(|(selection, delta)| Selection {
 3782                    id: selection.id,
 3783                    start: selection.start + delta,
 3784                    end: selection.end + delta,
 3785                    reversed: selection.reversed,
 3786                    goal: SelectionGoal::None,
 3787                })
 3788                .collect::<Vec<_>>();
 3789
 3790            let mut i = 0;
 3791            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3792                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3793                let start = map.buffer_snapshot.anchor_before(position);
 3794                let end = map.buffer_snapshot.anchor_after(position);
 3795                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3796                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3797                        Ordering::Less => i += 1,
 3798                        Ordering::Greater => break,
 3799                        Ordering::Equal => {
 3800                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3801                                Ordering::Less => i += 1,
 3802                                Ordering::Equal => break,
 3803                                Ordering::Greater => break,
 3804                            }
 3805                        }
 3806                    }
 3807                }
 3808                this.autoclose_regions.insert(
 3809                    i,
 3810                    AutocloseRegion {
 3811                        selection_id,
 3812                        range: start..end,
 3813                        pair,
 3814                    },
 3815                );
 3816            }
 3817
 3818            let had_active_inline_completion = this.has_active_inline_completion();
 3819            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3820                s.select(new_selections)
 3821            });
 3822
 3823            if !bracket_inserted {
 3824                if let Some(on_type_format_task) =
 3825                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3826                {
 3827                    on_type_format_task.detach_and_log_err(cx);
 3828                }
 3829            }
 3830
 3831            let editor_settings = EditorSettings::get_global(cx);
 3832            if bracket_inserted
 3833                && (editor_settings.auto_signature_help
 3834                    || editor_settings.show_signature_help_after_edits)
 3835            {
 3836                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3837            }
 3838
 3839            let trigger_in_words =
 3840                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3841            if this.hard_wrap.is_some() {
 3842                let latest: Range<Point> = this.selections.newest(cx).range();
 3843                if latest.is_empty()
 3844                    && this
 3845                        .buffer()
 3846                        .read(cx)
 3847                        .snapshot(cx)
 3848                        .line_len(MultiBufferRow(latest.start.row))
 3849                        == latest.start.column
 3850                {
 3851                    this.rewrap_impl(
 3852                        RewrapOptions {
 3853                            override_language_settings: true,
 3854                            preserve_existing_whitespace: true,
 3855                        },
 3856                        cx,
 3857                    )
 3858                }
 3859            }
 3860            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3861            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3862            this.refresh_inline_completion(true, false, window, cx);
 3863            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3864        });
 3865    }
 3866
 3867    fn find_possible_emoji_shortcode_at_position(
 3868        snapshot: &MultiBufferSnapshot,
 3869        position: Point,
 3870    ) -> Option<String> {
 3871        let mut chars = Vec::new();
 3872        let mut found_colon = false;
 3873        for char in snapshot.reversed_chars_at(position).take(100) {
 3874            // Found a possible emoji shortcode in the middle of the buffer
 3875            if found_colon {
 3876                if char.is_whitespace() {
 3877                    chars.reverse();
 3878                    return Some(chars.iter().collect());
 3879                }
 3880                // If the previous character is not a whitespace, we are in the middle of a word
 3881                // and we only want to complete the shortcode if the word is made up of other emojis
 3882                let mut containing_word = String::new();
 3883                for ch in snapshot
 3884                    .reversed_chars_at(position)
 3885                    .skip(chars.len() + 1)
 3886                    .take(100)
 3887                {
 3888                    if ch.is_whitespace() {
 3889                        break;
 3890                    }
 3891                    containing_word.push(ch);
 3892                }
 3893                let containing_word = containing_word.chars().rev().collect::<String>();
 3894                if util::word_consists_of_emojis(containing_word.as_str()) {
 3895                    chars.reverse();
 3896                    return Some(chars.iter().collect());
 3897                }
 3898            }
 3899
 3900            if char.is_whitespace() || !char.is_ascii() {
 3901                return None;
 3902            }
 3903            if char == ':' {
 3904                found_colon = true;
 3905            } else {
 3906                chars.push(char);
 3907            }
 3908        }
 3909        // Found a possible emoji shortcode at the beginning of the buffer
 3910        chars.reverse();
 3911        Some(chars.iter().collect())
 3912    }
 3913
 3914    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3915        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3916        self.transact(window, cx, |this, window, cx| {
 3917            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3918                let selections = this.selections.all::<usize>(cx);
 3919                let multi_buffer = this.buffer.read(cx);
 3920                let buffer = multi_buffer.snapshot(cx);
 3921                selections
 3922                    .iter()
 3923                    .map(|selection| {
 3924                        let start_point = selection.start.to_point(&buffer);
 3925                        let mut existing_indent =
 3926                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3927                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3928                        let start = selection.start;
 3929                        let end = selection.end;
 3930                        let selection_is_empty = start == end;
 3931                        let language_scope = buffer.language_scope_at(start);
 3932                        let (
 3933                            comment_delimiter,
 3934                            doc_delimiter,
 3935                            insert_extra_newline,
 3936                            indent_on_newline,
 3937                            indent_on_extra_newline,
 3938                        ) = if let Some(language) = &language_scope {
 3939                            let mut insert_extra_newline =
 3940                                insert_extra_newline_brackets(&buffer, start..end, language)
 3941                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3942
 3943                            // Comment extension on newline is allowed only for cursor selections
 3944                            let comment_delimiter = maybe!({
 3945                                if !selection_is_empty {
 3946                                    return None;
 3947                                }
 3948
 3949                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3950                                    return None;
 3951                                }
 3952
 3953                                let delimiters = language.line_comment_prefixes();
 3954                                let max_len_of_delimiter =
 3955                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3956                                let (snapshot, range) =
 3957                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3958
 3959                                let num_of_whitespaces = snapshot
 3960                                    .chars_for_range(range.clone())
 3961                                    .take_while(|c| c.is_whitespace())
 3962                                    .count();
 3963                                let comment_candidate = snapshot
 3964                                    .chars_for_range(range)
 3965                                    .skip(num_of_whitespaces)
 3966                                    .take(max_len_of_delimiter)
 3967                                    .collect::<String>();
 3968                                let (delimiter, trimmed_len) = delimiters
 3969                                    .iter()
 3970                                    .filter_map(|delimiter| {
 3971                                        let prefix = delimiter.trim_end();
 3972                                        if comment_candidate.starts_with(prefix) {
 3973                                            Some((delimiter, prefix.len()))
 3974                                        } else {
 3975                                            None
 3976                                        }
 3977                                    })
 3978                                    .max_by_key(|(_, len)| *len)?;
 3979
 3980                                let cursor_is_placed_after_comment_marker =
 3981                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 3982                                if cursor_is_placed_after_comment_marker {
 3983                                    Some(delimiter.clone())
 3984                                } else {
 3985                                    None
 3986                                }
 3987                            });
 3988
 3989                            let mut indent_on_newline = IndentSize::spaces(0);
 3990                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 3991
 3992                            let doc_delimiter = maybe!({
 3993                                if !selection_is_empty {
 3994                                    return None;
 3995                                }
 3996
 3997                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3998                                    return None;
 3999                                }
 4000
 4001                                let DocumentationConfig {
 4002                                    start: start_tag,
 4003                                    end: end_tag,
 4004                                    prefix: delimiter,
 4005                                    tab_size: len,
 4006                                } = language.documentation()?;
 4007
 4008                                let (snapshot, range) =
 4009                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4010
 4011                                let num_of_whitespaces = snapshot
 4012                                    .chars_for_range(range.clone())
 4013                                    .take_while(|c| c.is_whitespace())
 4014                                    .count();
 4015
 4016                                let cursor_is_after_start_tag = {
 4017                                    let start_tag_len = start_tag.len();
 4018                                    let start_tag_line = snapshot
 4019                                        .chars_for_range(range.clone())
 4020                                        .skip(num_of_whitespaces)
 4021                                        .take(start_tag_len)
 4022                                        .collect::<String>();
 4023                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4024                                        num_of_whitespaces + start_tag_len
 4025                                            <= start_point.column as usize
 4026                                    } else {
 4027                                        false
 4028                                    }
 4029                                };
 4030
 4031                                let cursor_is_after_delimiter = {
 4032                                    let delimiter_trim = delimiter.trim_end();
 4033                                    let delimiter_line = snapshot
 4034                                        .chars_for_range(range.clone())
 4035                                        .skip(num_of_whitespaces)
 4036                                        .take(delimiter_trim.len())
 4037                                        .collect::<String>();
 4038                                    if delimiter_line.starts_with(delimiter_trim) {
 4039                                        num_of_whitespaces + delimiter_trim.len()
 4040                                            <= start_point.column as usize
 4041                                    } else {
 4042                                        false
 4043                                    }
 4044                                };
 4045
 4046                                let cursor_is_before_end_tag_if_exists = {
 4047                                    let mut char_position = 0u32;
 4048                                    let mut end_tag_offset = None;
 4049
 4050                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4051                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4052                                            let chars_before_match =
 4053                                                chunk[..byte_pos].chars().count() as u32;
 4054                                            end_tag_offset =
 4055                                                Some(char_position + chars_before_match);
 4056                                            break 'outer;
 4057                                        }
 4058                                        char_position += chunk.chars().count() as u32;
 4059                                    }
 4060
 4061                                    if let Some(end_tag_offset) = end_tag_offset {
 4062                                        let cursor_is_before_end_tag =
 4063                                            start_point.column <= end_tag_offset;
 4064                                        if cursor_is_after_start_tag {
 4065                                            if cursor_is_before_end_tag {
 4066                                                insert_extra_newline = true;
 4067                                            }
 4068                                            let cursor_is_at_start_of_end_tag =
 4069                                                start_point.column == end_tag_offset;
 4070                                            if cursor_is_at_start_of_end_tag {
 4071                                                indent_on_extra_newline.len = (*len).into();
 4072                                            }
 4073                                        }
 4074                                        cursor_is_before_end_tag
 4075                                    } else {
 4076                                        true
 4077                                    }
 4078                                };
 4079
 4080                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4081                                    && cursor_is_before_end_tag_if_exists
 4082                                {
 4083                                    if cursor_is_after_start_tag {
 4084                                        indent_on_newline.len = (*len).into();
 4085                                    }
 4086                                    Some(delimiter.clone())
 4087                                } else {
 4088                                    None
 4089                                }
 4090                            });
 4091
 4092                            (
 4093                                comment_delimiter,
 4094                                doc_delimiter,
 4095                                insert_extra_newline,
 4096                                indent_on_newline,
 4097                                indent_on_extra_newline,
 4098                            )
 4099                        } else {
 4100                            (
 4101                                None,
 4102                                None,
 4103                                false,
 4104                                IndentSize::default(),
 4105                                IndentSize::default(),
 4106                            )
 4107                        };
 4108
 4109                        let prevent_auto_indent = doc_delimiter.is_some();
 4110                        let delimiter = comment_delimiter.or(doc_delimiter);
 4111
 4112                        let capacity_for_delimiter =
 4113                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4114                        let mut new_text = String::with_capacity(
 4115                            1 + capacity_for_delimiter
 4116                                + existing_indent.len as usize
 4117                                + indent_on_newline.len as usize
 4118                                + indent_on_extra_newline.len as usize,
 4119                        );
 4120                        new_text.push('\n');
 4121                        new_text.extend(existing_indent.chars());
 4122                        new_text.extend(indent_on_newline.chars());
 4123
 4124                        if let Some(delimiter) = &delimiter {
 4125                            new_text.push_str(delimiter);
 4126                        }
 4127
 4128                        if insert_extra_newline {
 4129                            new_text.push('\n');
 4130                            new_text.extend(existing_indent.chars());
 4131                            new_text.extend(indent_on_extra_newline.chars());
 4132                        }
 4133
 4134                        let anchor = buffer.anchor_after(end);
 4135                        let new_selection = selection.map(|_| anchor);
 4136                        (
 4137                            ((start..end, new_text), prevent_auto_indent),
 4138                            (insert_extra_newline, new_selection),
 4139                        )
 4140                    })
 4141                    .unzip()
 4142            };
 4143
 4144            let mut auto_indent_edits = Vec::new();
 4145            let mut edits = Vec::new();
 4146            for (edit, prevent_auto_indent) in edits_with_flags {
 4147                if prevent_auto_indent {
 4148                    edits.push(edit);
 4149                } else {
 4150                    auto_indent_edits.push(edit);
 4151                }
 4152            }
 4153            if !edits.is_empty() {
 4154                this.edit(edits, cx);
 4155            }
 4156            if !auto_indent_edits.is_empty() {
 4157                this.edit_with_autoindent(auto_indent_edits, cx);
 4158            }
 4159
 4160            let buffer = this.buffer.read(cx).snapshot(cx);
 4161            let new_selections = selection_info
 4162                .into_iter()
 4163                .map(|(extra_newline_inserted, new_selection)| {
 4164                    let mut cursor = new_selection.end.to_point(&buffer);
 4165                    if extra_newline_inserted {
 4166                        cursor.row -= 1;
 4167                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4168                    }
 4169                    new_selection.map(|_| cursor)
 4170                })
 4171                .collect();
 4172
 4173            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4174                s.select(new_selections)
 4175            });
 4176            this.refresh_inline_completion(true, false, window, cx);
 4177        });
 4178    }
 4179
 4180    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4181        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4182
 4183        let buffer = self.buffer.read(cx);
 4184        let snapshot = buffer.snapshot(cx);
 4185
 4186        let mut edits = Vec::new();
 4187        let mut rows = Vec::new();
 4188
 4189        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4190            let cursor = selection.head();
 4191            let row = cursor.row;
 4192
 4193            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4194
 4195            let newline = "\n".to_string();
 4196            edits.push((start_of_line..start_of_line, newline));
 4197
 4198            rows.push(row + rows_inserted as u32);
 4199        }
 4200
 4201        self.transact(window, cx, |editor, window, cx| {
 4202            editor.edit(edits, cx);
 4203
 4204            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4205                let mut index = 0;
 4206                s.move_cursors_with(|map, _, _| {
 4207                    let row = rows[index];
 4208                    index += 1;
 4209
 4210                    let point = Point::new(row, 0);
 4211                    let boundary = map.next_line_boundary(point).1;
 4212                    let clipped = map.clip_point(boundary, Bias::Left);
 4213
 4214                    (clipped, SelectionGoal::None)
 4215                });
 4216            });
 4217
 4218            let mut indent_edits = Vec::new();
 4219            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4220            for row in rows {
 4221                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4222                for (row, indent) in indents {
 4223                    if indent.len == 0 {
 4224                        continue;
 4225                    }
 4226
 4227                    let text = match indent.kind {
 4228                        IndentKind::Space => " ".repeat(indent.len as usize),
 4229                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4230                    };
 4231                    let point = Point::new(row.0, 0);
 4232                    indent_edits.push((point..point, text));
 4233                }
 4234            }
 4235            editor.edit(indent_edits, cx);
 4236        });
 4237    }
 4238
 4239    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4240        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4241
 4242        let buffer = self.buffer.read(cx);
 4243        let snapshot = buffer.snapshot(cx);
 4244
 4245        let mut edits = Vec::new();
 4246        let mut rows = Vec::new();
 4247        let mut rows_inserted = 0;
 4248
 4249        for selection in self.selections.all_adjusted(cx) {
 4250            let cursor = selection.head();
 4251            let row = cursor.row;
 4252
 4253            let point = Point::new(row + 1, 0);
 4254            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4255
 4256            let newline = "\n".to_string();
 4257            edits.push((start_of_line..start_of_line, newline));
 4258
 4259            rows_inserted += 1;
 4260            rows.push(row + rows_inserted);
 4261        }
 4262
 4263        self.transact(window, cx, |editor, window, cx| {
 4264            editor.edit(edits, cx);
 4265
 4266            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4267                let mut index = 0;
 4268                s.move_cursors_with(|map, _, _| {
 4269                    let row = rows[index];
 4270                    index += 1;
 4271
 4272                    let point = Point::new(row, 0);
 4273                    let boundary = map.next_line_boundary(point).1;
 4274                    let clipped = map.clip_point(boundary, Bias::Left);
 4275
 4276                    (clipped, SelectionGoal::None)
 4277                });
 4278            });
 4279
 4280            let mut indent_edits = Vec::new();
 4281            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4282            for row in rows {
 4283                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4284                for (row, indent) in indents {
 4285                    if indent.len == 0 {
 4286                        continue;
 4287                    }
 4288
 4289                    let text = match indent.kind {
 4290                        IndentKind::Space => " ".repeat(indent.len as usize),
 4291                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4292                    };
 4293                    let point = Point::new(row.0, 0);
 4294                    indent_edits.push((point..point, text));
 4295                }
 4296            }
 4297            editor.edit(indent_edits, cx);
 4298        });
 4299    }
 4300
 4301    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4302        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4303            original_indent_columns: Vec::new(),
 4304        });
 4305        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4306    }
 4307
 4308    fn insert_with_autoindent_mode(
 4309        &mut self,
 4310        text: &str,
 4311        autoindent_mode: Option<AutoindentMode>,
 4312        window: &mut Window,
 4313        cx: &mut Context<Self>,
 4314    ) {
 4315        if self.read_only(cx) {
 4316            return;
 4317        }
 4318
 4319        let text: Arc<str> = text.into();
 4320        self.transact(window, cx, |this, window, cx| {
 4321            let old_selections = this.selections.all_adjusted(cx);
 4322            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4323                let anchors = {
 4324                    let snapshot = buffer.read(cx);
 4325                    old_selections
 4326                        .iter()
 4327                        .map(|s| {
 4328                            let anchor = snapshot.anchor_after(s.head());
 4329                            s.map(|_| anchor)
 4330                        })
 4331                        .collect::<Vec<_>>()
 4332                };
 4333                buffer.edit(
 4334                    old_selections
 4335                        .iter()
 4336                        .map(|s| (s.start..s.end, text.clone())),
 4337                    autoindent_mode,
 4338                    cx,
 4339                );
 4340                anchors
 4341            });
 4342
 4343            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4344                s.select_anchors(selection_anchors);
 4345            });
 4346
 4347            cx.notify();
 4348        });
 4349    }
 4350
 4351    fn trigger_completion_on_input(
 4352        &mut self,
 4353        text: &str,
 4354        trigger_in_words: bool,
 4355        window: &mut Window,
 4356        cx: &mut Context<Self>,
 4357    ) {
 4358        let ignore_completion_provider = self
 4359            .context_menu
 4360            .borrow()
 4361            .as_ref()
 4362            .map(|menu| match menu {
 4363                CodeContextMenu::Completions(completions_menu) => {
 4364                    completions_menu.ignore_completion_provider
 4365                }
 4366                CodeContextMenu::CodeActions(_) => false,
 4367            })
 4368            .unwrap_or(false);
 4369
 4370        if ignore_completion_provider {
 4371            self.show_word_completions(&ShowWordCompletions, window, cx);
 4372        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4373            self.show_completions(
 4374                &ShowCompletions {
 4375                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4376                },
 4377                window,
 4378                cx,
 4379            );
 4380        } else {
 4381            self.hide_context_menu(window, cx);
 4382        }
 4383    }
 4384
 4385    fn is_completion_trigger(
 4386        &self,
 4387        text: &str,
 4388        trigger_in_words: bool,
 4389        cx: &mut Context<Self>,
 4390    ) -> bool {
 4391        let position = self.selections.newest_anchor().head();
 4392        let multibuffer = self.buffer.read(cx);
 4393        let Some(buffer) = position
 4394            .buffer_id
 4395            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4396        else {
 4397            return false;
 4398        };
 4399
 4400        if let Some(completion_provider) = &self.completion_provider {
 4401            completion_provider.is_completion_trigger(
 4402                &buffer,
 4403                position.text_anchor,
 4404                text,
 4405                trigger_in_words,
 4406                cx,
 4407            )
 4408        } else {
 4409            false
 4410        }
 4411    }
 4412
 4413    /// If any empty selections is touching the start of its innermost containing autoclose
 4414    /// region, expand it to select the brackets.
 4415    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4416        let selections = self.selections.all::<usize>(cx);
 4417        let buffer = self.buffer.read(cx).read(cx);
 4418        let new_selections = self
 4419            .selections_with_autoclose_regions(selections, &buffer)
 4420            .map(|(mut selection, region)| {
 4421                if !selection.is_empty() {
 4422                    return selection;
 4423                }
 4424
 4425                if let Some(region) = region {
 4426                    let mut range = region.range.to_offset(&buffer);
 4427                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4428                        range.start -= region.pair.start.len();
 4429                        if buffer.contains_str_at(range.start, &region.pair.start)
 4430                            && buffer.contains_str_at(range.end, &region.pair.end)
 4431                        {
 4432                            range.end += region.pair.end.len();
 4433                            selection.start = range.start;
 4434                            selection.end = range.end;
 4435
 4436                            return selection;
 4437                        }
 4438                    }
 4439                }
 4440
 4441                let always_treat_brackets_as_autoclosed = buffer
 4442                    .language_settings_at(selection.start, cx)
 4443                    .always_treat_brackets_as_autoclosed;
 4444
 4445                if !always_treat_brackets_as_autoclosed {
 4446                    return selection;
 4447                }
 4448
 4449                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4450                    for (pair, enabled) in scope.brackets() {
 4451                        if !enabled || !pair.close {
 4452                            continue;
 4453                        }
 4454
 4455                        if buffer.contains_str_at(selection.start, &pair.end) {
 4456                            let pair_start_len = pair.start.len();
 4457                            if buffer.contains_str_at(
 4458                                selection.start.saturating_sub(pair_start_len),
 4459                                &pair.start,
 4460                            ) {
 4461                                selection.start -= pair_start_len;
 4462                                selection.end += pair.end.len();
 4463
 4464                                return selection;
 4465                            }
 4466                        }
 4467                    }
 4468                }
 4469
 4470                selection
 4471            })
 4472            .collect();
 4473
 4474        drop(buffer);
 4475        self.change_selections(None, window, cx, |selections| {
 4476            selections.select(new_selections)
 4477        });
 4478    }
 4479
 4480    /// Iterate the given selections, and for each one, find the smallest surrounding
 4481    /// autoclose region. This uses the ordering of the selections and the autoclose
 4482    /// regions to avoid repeated comparisons.
 4483    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4484        &'a self,
 4485        selections: impl IntoIterator<Item = Selection<D>>,
 4486        buffer: &'a MultiBufferSnapshot,
 4487    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4488        let mut i = 0;
 4489        let mut regions = self.autoclose_regions.as_slice();
 4490        selections.into_iter().map(move |selection| {
 4491            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4492
 4493            let mut enclosing = None;
 4494            while let Some(pair_state) = regions.get(i) {
 4495                if pair_state.range.end.to_offset(buffer) < range.start {
 4496                    regions = &regions[i + 1..];
 4497                    i = 0;
 4498                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4499                    break;
 4500                } else {
 4501                    if pair_state.selection_id == selection.id {
 4502                        enclosing = Some(pair_state);
 4503                    }
 4504                    i += 1;
 4505                }
 4506            }
 4507
 4508            (selection, enclosing)
 4509        })
 4510    }
 4511
 4512    /// Remove any autoclose regions that no longer contain their selection.
 4513    fn invalidate_autoclose_regions(
 4514        &mut self,
 4515        mut selections: &[Selection<Anchor>],
 4516        buffer: &MultiBufferSnapshot,
 4517    ) {
 4518        self.autoclose_regions.retain(|state| {
 4519            let mut i = 0;
 4520            while let Some(selection) = selections.get(i) {
 4521                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4522                    selections = &selections[1..];
 4523                    continue;
 4524                }
 4525                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4526                    break;
 4527                }
 4528                if selection.id == state.selection_id {
 4529                    return true;
 4530                } else {
 4531                    i += 1;
 4532                }
 4533            }
 4534            false
 4535        });
 4536    }
 4537
 4538    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4539        let offset = position.to_offset(buffer);
 4540        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4541        if offset > word_range.start && kind == Some(CharKind::Word) {
 4542            Some(
 4543                buffer
 4544                    .text_for_range(word_range.start..offset)
 4545                    .collect::<String>(),
 4546            )
 4547        } else {
 4548            None
 4549        }
 4550    }
 4551
 4552    pub fn toggle_inline_values(
 4553        &mut self,
 4554        _: &ToggleInlineValues,
 4555        _: &mut Window,
 4556        cx: &mut Context<Self>,
 4557    ) {
 4558        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4559
 4560        self.refresh_inline_values(cx);
 4561    }
 4562
 4563    pub fn toggle_inlay_hints(
 4564        &mut self,
 4565        _: &ToggleInlayHints,
 4566        _: &mut Window,
 4567        cx: &mut Context<Self>,
 4568    ) {
 4569        self.refresh_inlay_hints(
 4570            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4571            cx,
 4572        );
 4573    }
 4574
 4575    pub fn inlay_hints_enabled(&self) -> bool {
 4576        self.inlay_hint_cache.enabled
 4577    }
 4578
 4579    pub fn inline_values_enabled(&self) -> bool {
 4580        self.inline_value_cache.enabled
 4581    }
 4582
 4583    #[cfg(any(test, feature = "test-support"))]
 4584    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4585        self.display_map
 4586            .read(cx)
 4587            .current_inlays()
 4588            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4589            .cloned()
 4590            .collect()
 4591    }
 4592
 4593    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4594        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4595            return;
 4596        }
 4597
 4598        let reason_description = reason.description();
 4599        let ignore_debounce = matches!(
 4600            reason,
 4601            InlayHintRefreshReason::SettingsChange(_)
 4602                | InlayHintRefreshReason::Toggle(_)
 4603                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4604                | InlayHintRefreshReason::ModifiersChanged(_)
 4605        );
 4606        let (invalidate_cache, required_languages) = match reason {
 4607            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4608                match self.inlay_hint_cache.modifiers_override(enabled) {
 4609                    Some(enabled) => {
 4610                        if enabled {
 4611                            (InvalidationStrategy::RefreshRequested, None)
 4612                        } else {
 4613                            self.splice_inlays(
 4614                                &self
 4615                                    .visible_inlay_hints(cx)
 4616                                    .iter()
 4617                                    .map(|inlay| inlay.id)
 4618                                    .collect::<Vec<InlayId>>(),
 4619                                Vec::new(),
 4620                                cx,
 4621                            );
 4622                            return;
 4623                        }
 4624                    }
 4625                    None => return,
 4626                }
 4627            }
 4628            InlayHintRefreshReason::Toggle(enabled) => {
 4629                if self.inlay_hint_cache.toggle(enabled) {
 4630                    if enabled {
 4631                        (InvalidationStrategy::RefreshRequested, None)
 4632                    } else {
 4633                        self.splice_inlays(
 4634                            &self
 4635                                .visible_inlay_hints(cx)
 4636                                .iter()
 4637                                .map(|inlay| inlay.id)
 4638                                .collect::<Vec<InlayId>>(),
 4639                            Vec::new(),
 4640                            cx,
 4641                        );
 4642                        return;
 4643                    }
 4644                } else {
 4645                    return;
 4646                }
 4647            }
 4648            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4649                match self.inlay_hint_cache.update_settings(
 4650                    &self.buffer,
 4651                    new_settings,
 4652                    self.visible_inlay_hints(cx),
 4653                    cx,
 4654                ) {
 4655                    ControlFlow::Break(Some(InlaySplice {
 4656                        to_remove,
 4657                        to_insert,
 4658                    })) => {
 4659                        self.splice_inlays(&to_remove, to_insert, cx);
 4660                        return;
 4661                    }
 4662                    ControlFlow::Break(None) => return,
 4663                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4664                }
 4665            }
 4666            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4667                if let Some(InlaySplice {
 4668                    to_remove,
 4669                    to_insert,
 4670                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4671                {
 4672                    self.splice_inlays(&to_remove, to_insert, cx);
 4673                }
 4674                self.display_map.update(cx, |display_map, _| {
 4675                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4676                });
 4677                return;
 4678            }
 4679            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4680            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4681                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4682            }
 4683            InlayHintRefreshReason::RefreshRequested => {
 4684                (InvalidationStrategy::RefreshRequested, None)
 4685            }
 4686        };
 4687
 4688        if let Some(InlaySplice {
 4689            to_remove,
 4690            to_insert,
 4691        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4692            reason_description,
 4693            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4694            invalidate_cache,
 4695            ignore_debounce,
 4696            cx,
 4697        ) {
 4698            self.splice_inlays(&to_remove, to_insert, cx);
 4699        }
 4700    }
 4701
 4702    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4703        self.display_map
 4704            .read(cx)
 4705            .current_inlays()
 4706            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4707            .cloned()
 4708            .collect()
 4709    }
 4710
 4711    pub fn excerpts_for_inlay_hints_query(
 4712        &self,
 4713        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4714        cx: &mut Context<Editor>,
 4715    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4716        let Some(project) = self.project.as_ref() else {
 4717            return HashMap::default();
 4718        };
 4719        let project = project.read(cx);
 4720        let multi_buffer = self.buffer().read(cx);
 4721        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4722        let multi_buffer_visible_start = self
 4723            .scroll_manager
 4724            .anchor()
 4725            .anchor
 4726            .to_point(&multi_buffer_snapshot);
 4727        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4728            multi_buffer_visible_start
 4729                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4730            Bias::Left,
 4731        );
 4732        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4733        multi_buffer_snapshot
 4734            .range_to_buffer_ranges(multi_buffer_visible_range)
 4735            .into_iter()
 4736            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4737            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4738                let buffer_file = project::File::from_dyn(buffer.file())?;
 4739                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4740                let worktree_entry = buffer_worktree
 4741                    .read(cx)
 4742                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4743                if worktree_entry.is_ignored {
 4744                    return None;
 4745                }
 4746
 4747                let language = buffer.language()?;
 4748                if let Some(restrict_to_languages) = restrict_to_languages {
 4749                    if !restrict_to_languages.contains(language) {
 4750                        return None;
 4751                    }
 4752                }
 4753                Some((
 4754                    excerpt_id,
 4755                    (
 4756                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4757                        buffer.version().clone(),
 4758                        excerpt_visible_range,
 4759                    ),
 4760                ))
 4761            })
 4762            .collect()
 4763    }
 4764
 4765    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4766        TextLayoutDetails {
 4767            text_system: window.text_system().clone(),
 4768            editor_style: self.style.clone().unwrap(),
 4769            rem_size: window.rem_size(),
 4770            scroll_anchor: self.scroll_manager.anchor(),
 4771            visible_rows: self.visible_line_count(),
 4772            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4773        }
 4774    }
 4775
 4776    pub fn splice_inlays(
 4777        &self,
 4778        to_remove: &[InlayId],
 4779        to_insert: Vec<Inlay>,
 4780        cx: &mut Context<Self>,
 4781    ) {
 4782        self.display_map.update(cx, |display_map, cx| {
 4783            display_map.splice_inlays(to_remove, to_insert, cx)
 4784        });
 4785        cx.notify();
 4786    }
 4787
 4788    fn trigger_on_type_formatting(
 4789        &self,
 4790        input: String,
 4791        window: &mut Window,
 4792        cx: &mut Context<Self>,
 4793    ) -> Option<Task<Result<()>>> {
 4794        if input.len() != 1 {
 4795            return None;
 4796        }
 4797
 4798        let project = self.project.as_ref()?;
 4799        let position = self.selections.newest_anchor().head();
 4800        let (buffer, buffer_position) = self
 4801            .buffer
 4802            .read(cx)
 4803            .text_anchor_for_position(position, cx)?;
 4804
 4805        let settings = language_settings::language_settings(
 4806            buffer
 4807                .read(cx)
 4808                .language_at(buffer_position)
 4809                .map(|l| l.name()),
 4810            buffer.read(cx).file(),
 4811            cx,
 4812        );
 4813        if !settings.use_on_type_format {
 4814            return None;
 4815        }
 4816
 4817        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4818        // hence we do LSP request & edit on host side only — add formats to host's history.
 4819        let push_to_lsp_host_history = true;
 4820        // If this is not the host, append its history with new edits.
 4821        let push_to_client_history = project.read(cx).is_via_collab();
 4822
 4823        let on_type_formatting = project.update(cx, |project, cx| {
 4824            project.on_type_format(
 4825                buffer.clone(),
 4826                buffer_position,
 4827                input,
 4828                push_to_lsp_host_history,
 4829                cx,
 4830            )
 4831        });
 4832        Some(cx.spawn_in(window, async move |editor, cx| {
 4833            if let Some(transaction) = on_type_formatting.await? {
 4834                if push_to_client_history {
 4835                    buffer
 4836                        .update(cx, |buffer, _| {
 4837                            buffer.push_transaction(transaction, Instant::now());
 4838                            buffer.finalize_last_transaction();
 4839                        })
 4840                        .ok();
 4841                }
 4842                editor.update(cx, |editor, cx| {
 4843                    editor.refresh_document_highlights(cx);
 4844                })?;
 4845            }
 4846            Ok(())
 4847        }))
 4848    }
 4849
 4850    pub fn show_word_completions(
 4851        &mut self,
 4852        _: &ShowWordCompletions,
 4853        window: &mut Window,
 4854        cx: &mut Context<Self>,
 4855    ) {
 4856        self.open_completions_menu(true, None, window, cx);
 4857    }
 4858
 4859    pub fn show_completions(
 4860        &mut self,
 4861        options: &ShowCompletions,
 4862        window: &mut Window,
 4863        cx: &mut Context<Self>,
 4864    ) {
 4865        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4866    }
 4867
 4868    fn open_completions_menu(
 4869        &mut self,
 4870        ignore_completion_provider: bool,
 4871        trigger: Option<&str>,
 4872        window: &mut Window,
 4873        cx: &mut Context<Self>,
 4874    ) {
 4875        if self.pending_rename.is_some() {
 4876            return;
 4877        }
 4878        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4879            return;
 4880        }
 4881
 4882        let position = self.selections.newest_anchor().head();
 4883        if position.diff_base_anchor.is_some() {
 4884            return;
 4885        }
 4886        let (buffer, buffer_position) =
 4887            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4888                output
 4889            } else {
 4890                return;
 4891            };
 4892        let buffer_snapshot = buffer.read(cx).snapshot();
 4893        let show_completion_documentation = buffer_snapshot
 4894            .settings_at(buffer_position, cx)
 4895            .show_completion_documentation;
 4896
 4897        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4898
 4899        let trigger_kind = match trigger {
 4900            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4901                CompletionTriggerKind::TRIGGER_CHARACTER
 4902            }
 4903            _ => CompletionTriggerKind::INVOKED,
 4904        };
 4905        let completion_context = CompletionContext {
 4906            trigger_character: trigger.and_then(|trigger| {
 4907                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4908                    Some(String::from(trigger))
 4909                } else {
 4910                    None
 4911                }
 4912            }),
 4913            trigger_kind,
 4914        };
 4915
 4916        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4917        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4918            let word_to_exclude = buffer_snapshot
 4919                .text_for_range(old_range.clone())
 4920                .collect::<String>();
 4921            (
 4922                buffer_snapshot.anchor_before(old_range.start)
 4923                    ..buffer_snapshot.anchor_after(old_range.end),
 4924                Some(word_to_exclude),
 4925            )
 4926        } else {
 4927            (buffer_position..buffer_position, None)
 4928        };
 4929
 4930        let completion_settings = language_settings(
 4931            buffer_snapshot
 4932                .language_at(buffer_position)
 4933                .map(|language| language.name()),
 4934            buffer_snapshot.file(),
 4935            cx,
 4936        )
 4937        .completions;
 4938
 4939        // The document can be large, so stay in reasonable bounds when searching for words,
 4940        // otherwise completion pop-up might be slow to appear.
 4941        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4942        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4943        let min_word_search = buffer_snapshot.clip_point(
 4944            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4945            Bias::Left,
 4946        );
 4947        let max_word_search = buffer_snapshot.clip_point(
 4948            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4949            Bias::Right,
 4950        );
 4951        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4952            ..buffer_snapshot.point_to_offset(max_word_search);
 4953
 4954        let provider = self
 4955            .completion_provider
 4956            .as_ref()
 4957            .filter(|_| !ignore_completion_provider);
 4958        let skip_digits = query
 4959            .as_ref()
 4960            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4961
 4962        let (mut words, provided_completions) = match provider {
 4963            Some(provider) => {
 4964                let completions = provider.completions(
 4965                    position.excerpt_id,
 4966                    &buffer,
 4967                    buffer_position,
 4968                    completion_context,
 4969                    window,
 4970                    cx,
 4971                );
 4972
 4973                let words = match completion_settings.words {
 4974                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4975                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4976                        .background_spawn(async move {
 4977                            buffer_snapshot.words_in_range(WordsQuery {
 4978                                fuzzy_contents: None,
 4979                                range: word_search_range,
 4980                                skip_digits,
 4981                            })
 4982                        }),
 4983                };
 4984
 4985                (words, completions)
 4986            }
 4987            None => (
 4988                cx.background_spawn(async move {
 4989                    buffer_snapshot.words_in_range(WordsQuery {
 4990                        fuzzy_contents: None,
 4991                        range: word_search_range,
 4992                        skip_digits,
 4993                    })
 4994                }),
 4995                Task::ready(Ok(None)),
 4996            ),
 4997        };
 4998
 4999        let sort_completions = provider
 5000            .as_ref()
 5001            .map_or(false, |provider| provider.sort_completions());
 5002
 5003        let filter_completions = provider
 5004            .as_ref()
 5005            .map_or(true, |provider| provider.filter_completions());
 5006
 5007        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5008
 5009        let id = post_inc(&mut self.next_completion_id);
 5010        let task = cx.spawn_in(window, async move |editor, cx| {
 5011            async move {
 5012                editor.update(cx, |this, _| {
 5013                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5014                })?;
 5015
 5016                let mut completions = Vec::new();
 5017                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5018                    completions.extend(provided_completions);
 5019                    if completion_settings.words == WordsCompletionMode::Fallback {
 5020                        words = Task::ready(BTreeMap::default());
 5021                    }
 5022                }
 5023
 5024                let mut words = words.await;
 5025                if let Some(word_to_exclude) = &word_to_exclude {
 5026                    words.remove(word_to_exclude);
 5027                }
 5028                for lsp_completion in &completions {
 5029                    words.remove(&lsp_completion.new_text);
 5030                }
 5031                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5032                    replace_range: old_range.clone(),
 5033                    new_text: word.clone(),
 5034                    label: CodeLabel::plain(word, None),
 5035                    icon_path: None,
 5036                    documentation: None,
 5037                    source: CompletionSource::BufferWord {
 5038                        word_range,
 5039                        resolved: false,
 5040                    },
 5041                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5042                    confirm: None,
 5043                }));
 5044
 5045                let menu = if completions.is_empty() {
 5046                    None
 5047                } else {
 5048                    let mut menu = CompletionsMenu::new(
 5049                        id,
 5050                        sort_completions,
 5051                        show_completion_documentation,
 5052                        ignore_completion_provider,
 5053                        position,
 5054                        buffer.clone(),
 5055                        completions.into(),
 5056                        snippet_sort_order,
 5057                    );
 5058
 5059                    menu.filter(
 5060                        if filter_completions {
 5061                            query.as_deref()
 5062                        } else {
 5063                            None
 5064                        },
 5065                        cx.background_executor().clone(),
 5066                    )
 5067                    .await;
 5068
 5069                    menu.visible().then_some(menu)
 5070                };
 5071
 5072                editor.update_in(cx, |editor, window, cx| {
 5073                    match editor.context_menu.borrow().as_ref() {
 5074                        None => {}
 5075                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5076                            if prev_menu.id > id {
 5077                                return;
 5078                            }
 5079                        }
 5080                        _ => return,
 5081                    }
 5082
 5083                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5084                        let mut menu = menu.unwrap();
 5085                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5086                        crate::hover_popover::hide_hover(editor, cx);
 5087                        *editor.context_menu.borrow_mut() =
 5088                            Some(CodeContextMenu::Completions(menu));
 5089
 5090                        if editor.show_edit_predictions_in_menu() {
 5091                            editor.update_visible_inline_completion(window, cx);
 5092                        } else {
 5093                            editor.discard_inline_completion(false, cx);
 5094                        }
 5095
 5096                        cx.notify();
 5097                    } else if editor.completion_tasks.len() <= 1 {
 5098                        // If there are no more completion tasks and the last menu was
 5099                        // empty, we should hide it.
 5100                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5101                        // If it was already hidden and we don't show inline
 5102                        // completions in the menu, we should also show the
 5103                        // inline-completion when available.
 5104                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5105                            editor.update_visible_inline_completion(window, cx);
 5106                        }
 5107                    }
 5108                })?;
 5109
 5110                anyhow::Ok(())
 5111            }
 5112            .log_err()
 5113            .await
 5114        });
 5115
 5116        self.completion_tasks.push((id, task));
 5117    }
 5118
 5119    #[cfg(feature = "test-support")]
 5120    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5121        let menu = self.context_menu.borrow();
 5122        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5123            let completions = menu.completions.borrow();
 5124            Some(completions.to_vec())
 5125        } else {
 5126            None
 5127        }
 5128    }
 5129
 5130    pub fn confirm_completion(
 5131        &mut self,
 5132        action: &ConfirmCompletion,
 5133        window: &mut Window,
 5134        cx: &mut Context<Self>,
 5135    ) -> Option<Task<Result<()>>> {
 5136        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5137        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5138    }
 5139
 5140    pub fn confirm_completion_insert(
 5141        &mut self,
 5142        _: &ConfirmCompletionInsert,
 5143        window: &mut Window,
 5144        cx: &mut Context<Self>,
 5145    ) -> Option<Task<Result<()>>> {
 5146        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5147        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5148    }
 5149
 5150    pub fn confirm_completion_replace(
 5151        &mut self,
 5152        _: &ConfirmCompletionReplace,
 5153        window: &mut Window,
 5154        cx: &mut Context<Self>,
 5155    ) -> Option<Task<Result<()>>> {
 5156        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5157        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5158    }
 5159
 5160    pub fn compose_completion(
 5161        &mut self,
 5162        action: &ComposeCompletion,
 5163        window: &mut Window,
 5164        cx: &mut Context<Self>,
 5165    ) -> Option<Task<Result<()>>> {
 5166        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5167        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5168    }
 5169
 5170    fn do_completion(
 5171        &mut self,
 5172        item_ix: Option<usize>,
 5173        intent: CompletionIntent,
 5174        window: &mut Window,
 5175        cx: &mut Context<Editor>,
 5176    ) -> Option<Task<Result<()>>> {
 5177        use language::ToOffset as _;
 5178
 5179        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5180        else {
 5181            return None;
 5182        };
 5183
 5184        let candidate_id = {
 5185            let entries = completions_menu.entries.borrow();
 5186            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5187            if self.show_edit_predictions_in_menu() {
 5188                self.discard_inline_completion(true, cx);
 5189            }
 5190            mat.candidate_id
 5191        };
 5192
 5193        let buffer_handle = completions_menu.buffer;
 5194        let completion = completions_menu
 5195            .completions
 5196            .borrow()
 5197            .get(candidate_id)?
 5198            .clone();
 5199        cx.stop_propagation();
 5200
 5201        let snapshot = self.buffer.read(cx).snapshot(cx);
 5202        let newest_anchor = self.selections.newest_anchor();
 5203
 5204        let snippet;
 5205        let new_text;
 5206        if completion.is_snippet() {
 5207            let mut snippet_source = completion.new_text.clone();
 5208            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5209                if scope.prefers_label_for_snippet_in_completion() {
 5210                    if let Some(label) = completion.label() {
 5211                        if matches!(
 5212                            completion.kind(),
 5213                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5214                        ) {
 5215                            snippet_source = label;
 5216                        }
 5217                    }
 5218                }
 5219            }
 5220            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5221            new_text = snippet.as_ref().unwrap().text.clone();
 5222        } else {
 5223            snippet = None;
 5224            new_text = completion.new_text.clone();
 5225        };
 5226
 5227        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5228        let buffer = buffer_handle.read(cx);
 5229        let replace_range_multibuffer = {
 5230            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5231            let multibuffer_anchor = snapshot
 5232                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5233                .unwrap()
 5234                ..snapshot
 5235                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5236                    .unwrap();
 5237            multibuffer_anchor.start.to_offset(&snapshot)
 5238                ..multibuffer_anchor.end.to_offset(&snapshot)
 5239        };
 5240        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5241            return None;
 5242        }
 5243
 5244        let old_text = buffer
 5245            .text_for_range(replace_range.clone())
 5246            .collect::<String>();
 5247        let lookbehind = newest_anchor
 5248            .start
 5249            .text_anchor
 5250            .to_offset(buffer)
 5251            .saturating_sub(replace_range.start);
 5252        let lookahead = replace_range
 5253            .end
 5254            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5255        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5256        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5257
 5258        let selections = self.selections.all::<usize>(cx);
 5259        let mut ranges = Vec::new();
 5260        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5261
 5262        for selection in &selections {
 5263            let range = if selection.id == newest_anchor.id {
 5264                replace_range_multibuffer.clone()
 5265            } else {
 5266                let mut range = selection.range();
 5267
 5268                // if prefix is present, don't duplicate it
 5269                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5270                    range.start = range.start.saturating_sub(lookbehind);
 5271
 5272                    // if suffix is also present, mimic the newest cursor and replace it
 5273                    if selection.id != newest_anchor.id
 5274                        && snapshot.contains_str_at(range.end, suffix)
 5275                    {
 5276                        range.end += lookahead;
 5277                    }
 5278                }
 5279                range
 5280            };
 5281
 5282            ranges.push(range.clone());
 5283
 5284            if !self.linked_edit_ranges.is_empty() {
 5285                let start_anchor = snapshot.anchor_before(range.start);
 5286                let end_anchor = snapshot.anchor_after(range.end);
 5287                if let Some(ranges) = self
 5288                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5289                {
 5290                    for (buffer, edits) in ranges {
 5291                        linked_edits
 5292                            .entry(buffer.clone())
 5293                            .or_default()
 5294                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5295                    }
 5296                }
 5297            }
 5298        }
 5299
 5300        cx.emit(EditorEvent::InputHandled {
 5301            utf16_range_to_replace: None,
 5302            text: new_text.clone().into(),
 5303        });
 5304
 5305        self.transact(window, cx, |this, window, cx| {
 5306            if let Some(mut snippet) = snippet {
 5307                snippet.text = new_text.to_string();
 5308                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5309            } else {
 5310                this.buffer.update(cx, |buffer, cx| {
 5311                    let auto_indent = match completion.insert_text_mode {
 5312                        Some(InsertTextMode::AS_IS) => None,
 5313                        _ => this.autoindent_mode.clone(),
 5314                    };
 5315                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5316                    buffer.edit(edits, auto_indent, cx);
 5317                });
 5318            }
 5319            for (buffer, edits) in linked_edits {
 5320                buffer.update(cx, |buffer, cx| {
 5321                    let snapshot = buffer.snapshot();
 5322                    let edits = edits
 5323                        .into_iter()
 5324                        .map(|(range, text)| {
 5325                            use text::ToPoint as TP;
 5326                            let end_point = TP::to_point(&range.end, &snapshot);
 5327                            let start_point = TP::to_point(&range.start, &snapshot);
 5328                            (start_point..end_point, text)
 5329                        })
 5330                        .sorted_by_key(|(range, _)| range.start);
 5331                    buffer.edit(edits, None, cx);
 5332                })
 5333            }
 5334
 5335            this.refresh_inline_completion(true, false, window, cx);
 5336        });
 5337
 5338        let show_new_completions_on_confirm = completion
 5339            .confirm
 5340            .as_ref()
 5341            .map_or(false, |confirm| confirm(intent, window, cx));
 5342        if show_new_completions_on_confirm {
 5343            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5344        }
 5345
 5346        let provider = self.completion_provider.as_ref()?;
 5347        drop(completion);
 5348        let apply_edits = provider.apply_additional_edits_for_completion(
 5349            buffer_handle,
 5350            completions_menu.completions.clone(),
 5351            candidate_id,
 5352            true,
 5353            cx,
 5354        );
 5355
 5356        let editor_settings = EditorSettings::get_global(cx);
 5357        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5358            // After the code completion is finished, users often want to know what signatures are needed.
 5359            // so we should automatically call signature_help
 5360            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5361        }
 5362
 5363        Some(cx.foreground_executor().spawn(async move {
 5364            apply_edits.await?;
 5365            Ok(())
 5366        }))
 5367    }
 5368
 5369    pub fn toggle_code_actions(
 5370        &mut self,
 5371        action: &ToggleCodeActions,
 5372        window: &mut Window,
 5373        cx: &mut Context<Self>,
 5374    ) {
 5375        let quick_launch = action.quick_launch;
 5376        let mut context_menu = self.context_menu.borrow_mut();
 5377        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5378            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 5379                // Toggle if we're selecting the same one
 5380                *context_menu = None;
 5381                cx.notify();
 5382                return;
 5383            } else {
 5384                // Otherwise, clear it and start a new one
 5385                *context_menu = None;
 5386                cx.notify();
 5387            }
 5388        }
 5389        drop(context_menu);
 5390        let snapshot = self.snapshot(window, cx);
 5391        let deployed_from_indicator = action.deployed_from_indicator;
 5392        let mut task = self.code_actions_task.take();
 5393        let action = action.clone();
 5394        cx.spawn_in(window, async move |editor, cx| {
 5395            while let Some(prev_task) = task {
 5396                prev_task.await.log_err();
 5397                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5398            }
 5399
 5400            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5401                if editor.focus_handle.is_focused(window) {
 5402                    let multibuffer_point = action
 5403                        .deployed_from_indicator
 5404                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 5405                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 5406                    let (buffer, buffer_row) = snapshot
 5407                        .buffer_snapshot
 5408                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5409                        .and_then(|(buffer_snapshot, range)| {
 5410                            editor
 5411                                .buffer
 5412                                .read(cx)
 5413                                .buffer(buffer_snapshot.remote_id())
 5414                                .map(|buffer| (buffer, range.start.row))
 5415                        })?;
 5416                    let (_, code_actions) = editor
 5417                        .available_code_actions
 5418                        .clone()
 5419                        .and_then(|(location, code_actions)| {
 5420                            let snapshot = location.buffer.read(cx).snapshot();
 5421                            let point_range = location.range.to_point(&snapshot);
 5422                            let point_range = point_range.start.row..=point_range.end.row;
 5423                            if point_range.contains(&buffer_row) {
 5424                                Some((location, code_actions))
 5425                            } else {
 5426                                None
 5427                            }
 5428                        })
 5429                        .unzip();
 5430                    let buffer_id = buffer.read(cx).remote_id();
 5431                    let tasks = editor
 5432                        .tasks
 5433                        .get(&(buffer_id, buffer_row))
 5434                        .map(|t| Arc::new(t.to_owned()));
 5435                    if tasks.is_none() && code_actions.is_none() {
 5436                        return None;
 5437                    }
 5438
 5439                    editor.completion_tasks.clear();
 5440                    editor.discard_inline_completion(false, cx);
 5441                    let task_context =
 5442                        tasks
 5443                            .as_ref()
 5444                            .zip(editor.project.clone())
 5445                            .map(|(tasks, project)| {
 5446                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5447                            });
 5448
 5449                    Some(cx.spawn_in(window, async move |editor, cx| {
 5450                        let task_context = match task_context {
 5451                            Some(task_context) => task_context.await,
 5452                            None => None,
 5453                        };
 5454                        let resolved_tasks =
 5455                            tasks
 5456                                .zip(task_context.clone())
 5457                                .map(|(tasks, task_context)| ResolvedTasks {
 5458                                    templates: tasks.resolve(&task_context).collect(),
 5459                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5460                                        multibuffer_point.row,
 5461                                        tasks.column,
 5462                                    )),
 5463                                });
 5464                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5465                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5466                                maybe!({
 5467                                    let project = editor.project.as_ref()?;
 5468                                    let dap_store = project.read(cx).dap_store();
 5469                                    let mut scenarios = vec![];
 5470                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5471                                    let buffer = buffer.read(cx);
 5472                                    let language = buffer.language()?;
 5473                                    let file = buffer.file();
 5474                                    let debug_adapter =
 5475                                        language_settings(language.name().into(), file, cx)
 5476                                            .debuggers
 5477                                            .first()
 5478                                            .map(SharedString::from)
 5479                                            .or_else(|| {
 5480                                                language
 5481                                                    .config()
 5482                                                    .debuggers
 5483                                                    .first()
 5484                                                    .map(SharedString::from)
 5485                                            })?;
 5486
 5487                                    dap_store.update(cx, |dap_store, cx| {
 5488                                        for (_, task) in &resolved_tasks.templates {
 5489                                            if let Some(scenario) = dap_store
 5490                                                .debug_scenario_for_build_task(
 5491                                                    task.original_task().clone(),
 5492                                                    debug_adapter.clone().into(),
 5493                                                    task.display_label().to_owned().into(),
 5494                                                    cx,
 5495                                                )
 5496                                            {
 5497                                                scenarios.push(scenario);
 5498                                            }
 5499                                        }
 5500                                    });
 5501                                    Some(scenarios)
 5502                                })
 5503                                .unwrap_or_default()
 5504                            } else {
 5505                                vec![]
 5506                            }
 5507                        })?;
 5508                        let spawn_straight_away = quick_launch
 5509                            && resolved_tasks
 5510                                .as_ref()
 5511                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5512                            && code_actions
 5513                                .as_ref()
 5514                                .map_or(true, |actions| actions.is_empty())
 5515                            && debug_scenarios.is_empty();
 5516                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5517                            crate::hover_popover::hide_hover(editor, cx);
 5518                            *editor.context_menu.borrow_mut() =
 5519                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5520                                    buffer,
 5521                                    actions: CodeActionContents::new(
 5522                                        resolved_tasks,
 5523                                        code_actions,
 5524                                        debug_scenarios,
 5525                                        task_context.unwrap_or_default(),
 5526                                    ),
 5527                                    selected_item: Default::default(),
 5528                                    scroll_handle: UniformListScrollHandle::default(),
 5529                                    deployed_from_indicator,
 5530                                }));
 5531                            if spawn_straight_away {
 5532                                if let Some(task) = editor.confirm_code_action(
 5533                                    &ConfirmCodeAction { item_ix: Some(0) },
 5534                                    window,
 5535                                    cx,
 5536                                ) {
 5537                                    cx.notify();
 5538                                    return task;
 5539                                }
 5540                            }
 5541                            cx.notify();
 5542                            Task::ready(Ok(()))
 5543                        }) {
 5544                            task.await
 5545                        } else {
 5546                            Ok(())
 5547                        }
 5548                    }))
 5549                } else {
 5550                    Some(Task::ready(Ok(())))
 5551                }
 5552            })?;
 5553            if let Some(task) = spawned_test_task {
 5554                task.await?;
 5555            }
 5556
 5557            anyhow::Ok(())
 5558        })
 5559        .detach_and_log_err(cx);
 5560    }
 5561
 5562    pub fn confirm_code_action(
 5563        &mut self,
 5564        action: &ConfirmCodeAction,
 5565        window: &mut Window,
 5566        cx: &mut Context<Self>,
 5567    ) -> Option<Task<Result<()>>> {
 5568        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5569
 5570        let actions_menu =
 5571            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5572                menu
 5573            } else {
 5574                return None;
 5575            };
 5576
 5577        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5578        let action = actions_menu.actions.get(action_ix)?;
 5579        let title = action.label();
 5580        let buffer = actions_menu.buffer;
 5581        let workspace = self.workspace()?;
 5582
 5583        match action {
 5584            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5585                workspace.update(cx, |workspace, cx| {
 5586                    workspace.schedule_resolved_task(
 5587                        task_source_kind,
 5588                        resolved_task,
 5589                        false,
 5590                        window,
 5591                        cx,
 5592                    );
 5593
 5594                    Some(Task::ready(Ok(())))
 5595                })
 5596            }
 5597            CodeActionsItem::CodeAction {
 5598                excerpt_id,
 5599                action,
 5600                provider,
 5601            } => {
 5602                let apply_code_action =
 5603                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5604                let workspace = workspace.downgrade();
 5605                Some(cx.spawn_in(window, async move |editor, cx| {
 5606                    let project_transaction = apply_code_action.await?;
 5607                    Self::open_project_transaction(
 5608                        &editor,
 5609                        workspace,
 5610                        project_transaction,
 5611                        title,
 5612                        cx,
 5613                    )
 5614                    .await
 5615                }))
 5616            }
 5617            CodeActionsItem::DebugScenario(scenario) => {
 5618                let context = actions_menu.actions.context.clone();
 5619
 5620                workspace.update(cx, |workspace, cx| {
 5621                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5622                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5623                });
 5624                Some(Task::ready(Ok(())))
 5625            }
 5626        }
 5627    }
 5628
 5629    pub async fn open_project_transaction(
 5630        this: &WeakEntity<Editor>,
 5631        workspace: WeakEntity<Workspace>,
 5632        transaction: ProjectTransaction,
 5633        title: String,
 5634        cx: &mut AsyncWindowContext,
 5635    ) -> Result<()> {
 5636        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5637        cx.update(|_, cx| {
 5638            entries.sort_unstable_by_key(|(buffer, _)| {
 5639                buffer.read(cx).file().map(|f| f.path().clone())
 5640            });
 5641        })?;
 5642
 5643        // If the project transaction's edits are all contained within this editor, then
 5644        // avoid opening a new editor to display them.
 5645
 5646        if let Some((buffer, transaction)) = entries.first() {
 5647            if entries.len() == 1 {
 5648                let excerpt = this.update(cx, |editor, cx| {
 5649                    editor
 5650                        .buffer()
 5651                        .read(cx)
 5652                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5653                })?;
 5654                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5655                    if excerpted_buffer == *buffer {
 5656                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5657                            let excerpt_range = excerpt_range.to_offset(buffer);
 5658                            buffer
 5659                                .edited_ranges_for_transaction::<usize>(transaction)
 5660                                .all(|range| {
 5661                                    excerpt_range.start <= range.start
 5662                                        && excerpt_range.end >= range.end
 5663                                })
 5664                        })?;
 5665
 5666                        if all_edits_within_excerpt {
 5667                            return Ok(());
 5668                        }
 5669                    }
 5670                }
 5671            }
 5672        } else {
 5673            return Ok(());
 5674        }
 5675
 5676        let mut ranges_to_highlight = Vec::new();
 5677        let excerpt_buffer = cx.new(|cx| {
 5678            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5679            for (buffer_handle, transaction) in &entries {
 5680                let edited_ranges = buffer_handle
 5681                    .read(cx)
 5682                    .edited_ranges_for_transaction::<Point>(transaction)
 5683                    .collect::<Vec<_>>();
 5684                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5685                    PathKey::for_buffer(buffer_handle, cx),
 5686                    buffer_handle.clone(),
 5687                    edited_ranges,
 5688                    DEFAULT_MULTIBUFFER_CONTEXT,
 5689                    cx,
 5690                );
 5691
 5692                ranges_to_highlight.extend(ranges);
 5693            }
 5694            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5695            multibuffer
 5696        })?;
 5697
 5698        workspace.update_in(cx, |workspace, window, cx| {
 5699            let project = workspace.project().clone();
 5700            let editor =
 5701                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5702            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5703            editor.update(cx, |editor, cx| {
 5704                editor.highlight_background::<Self>(
 5705                    &ranges_to_highlight,
 5706                    |theme| theme.editor_highlighted_line_background,
 5707                    cx,
 5708                );
 5709            });
 5710        })?;
 5711
 5712        Ok(())
 5713    }
 5714
 5715    pub fn clear_code_action_providers(&mut self) {
 5716        self.code_action_providers.clear();
 5717        self.available_code_actions.take();
 5718    }
 5719
 5720    pub fn add_code_action_provider(
 5721        &mut self,
 5722        provider: Rc<dyn CodeActionProvider>,
 5723        window: &mut Window,
 5724        cx: &mut Context<Self>,
 5725    ) {
 5726        if self
 5727            .code_action_providers
 5728            .iter()
 5729            .any(|existing_provider| existing_provider.id() == provider.id())
 5730        {
 5731            return;
 5732        }
 5733
 5734        self.code_action_providers.push(provider);
 5735        self.refresh_code_actions(window, cx);
 5736    }
 5737
 5738    pub fn remove_code_action_provider(
 5739        &mut self,
 5740        id: Arc<str>,
 5741        window: &mut Window,
 5742        cx: &mut Context<Self>,
 5743    ) {
 5744        self.code_action_providers
 5745            .retain(|provider| provider.id() != id);
 5746        self.refresh_code_actions(window, cx);
 5747    }
 5748
 5749    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5750        let newest_selection = self.selections.newest_anchor().clone();
 5751        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5752        let buffer = self.buffer.read(cx);
 5753        if newest_selection.head().diff_base_anchor.is_some() {
 5754            return None;
 5755        }
 5756        let (start_buffer, start) =
 5757            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5758        let (end_buffer, end) =
 5759            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5760        if start_buffer != end_buffer {
 5761            return None;
 5762        }
 5763
 5764        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5765            cx.background_executor()
 5766                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5767                .await;
 5768
 5769            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5770                let providers = this.code_action_providers.clone();
 5771                let tasks = this
 5772                    .code_action_providers
 5773                    .iter()
 5774                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5775                    .collect::<Vec<_>>();
 5776                (providers, tasks)
 5777            })?;
 5778
 5779            let mut actions = Vec::new();
 5780            for (provider, provider_actions) in
 5781                providers.into_iter().zip(future::join_all(tasks).await)
 5782            {
 5783                if let Some(provider_actions) = provider_actions.log_err() {
 5784                    actions.extend(provider_actions.into_iter().map(|action| {
 5785                        AvailableCodeAction {
 5786                            excerpt_id: newest_selection.start.excerpt_id,
 5787                            action,
 5788                            provider: provider.clone(),
 5789                        }
 5790                    }));
 5791                }
 5792            }
 5793
 5794            this.update(cx, |this, cx| {
 5795                this.available_code_actions = if actions.is_empty() {
 5796                    None
 5797                } else {
 5798                    Some((
 5799                        Location {
 5800                            buffer: start_buffer,
 5801                            range: start..end,
 5802                        },
 5803                        actions.into(),
 5804                    ))
 5805                };
 5806                cx.notify();
 5807            })
 5808        }));
 5809        None
 5810    }
 5811
 5812    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5813        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5814            self.show_git_blame_inline = false;
 5815
 5816            self.show_git_blame_inline_delay_task =
 5817                Some(cx.spawn_in(window, async move |this, cx| {
 5818                    cx.background_executor().timer(delay).await;
 5819
 5820                    this.update(cx, |this, cx| {
 5821                        this.show_git_blame_inline = true;
 5822                        cx.notify();
 5823                    })
 5824                    .log_err();
 5825                }));
 5826        }
 5827    }
 5828
 5829    fn show_blame_popover(
 5830        &mut self,
 5831        blame_entry: &BlameEntry,
 5832        position: gpui::Point<Pixels>,
 5833        cx: &mut Context<Self>,
 5834    ) {
 5835        if let Some(state) = &mut self.inline_blame_popover {
 5836            state.hide_task.take();
 5837            cx.notify();
 5838        } else {
 5839            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5840            let show_task = cx.spawn(async move |editor, cx| {
 5841                cx.background_executor()
 5842                    .timer(std::time::Duration::from_millis(delay))
 5843                    .await;
 5844                editor
 5845                    .update(cx, |editor, cx| {
 5846                        if let Some(state) = &mut editor.inline_blame_popover {
 5847                            state.show_task = None;
 5848                            cx.notify();
 5849                        }
 5850                    })
 5851                    .ok();
 5852            });
 5853            let Some(blame) = self.blame.as_ref() else {
 5854                return;
 5855            };
 5856            let blame = blame.read(cx);
 5857            let details = blame.details_for_entry(&blame_entry);
 5858            let markdown = cx.new(|cx| {
 5859                Markdown::new(
 5860                    details
 5861                        .as_ref()
 5862                        .map(|message| message.message.clone())
 5863                        .unwrap_or_default(),
 5864                    None,
 5865                    None,
 5866                    cx,
 5867                )
 5868            });
 5869            self.inline_blame_popover = Some(InlineBlamePopover {
 5870                position,
 5871                show_task: Some(show_task),
 5872                hide_task: None,
 5873                popover_bounds: None,
 5874                popover_state: InlineBlamePopoverState {
 5875                    scroll_handle: ScrollHandle::new(),
 5876                    commit_message: details,
 5877                    markdown,
 5878                },
 5879            });
 5880        }
 5881    }
 5882
 5883    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5884        if let Some(state) = &mut self.inline_blame_popover {
 5885            if state.show_task.is_some() {
 5886                self.inline_blame_popover.take();
 5887                cx.notify();
 5888            } else {
 5889                let hide_task = cx.spawn(async move |editor, cx| {
 5890                    cx.background_executor()
 5891                        .timer(std::time::Duration::from_millis(100))
 5892                        .await;
 5893                    editor
 5894                        .update(cx, |editor, cx| {
 5895                            editor.inline_blame_popover.take();
 5896                            cx.notify();
 5897                        })
 5898                        .ok();
 5899                });
 5900                state.hide_task = Some(hide_task);
 5901            }
 5902        }
 5903    }
 5904
 5905    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5906        if self.pending_rename.is_some() {
 5907            return None;
 5908        }
 5909
 5910        let provider = self.semantics_provider.clone()?;
 5911        let buffer = self.buffer.read(cx);
 5912        let newest_selection = self.selections.newest_anchor().clone();
 5913        let cursor_position = newest_selection.head();
 5914        let (cursor_buffer, cursor_buffer_position) =
 5915            buffer.text_anchor_for_position(cursor_position, cx)?;
 5916        let (tail_buffer, tail_buffer_position) =
 5917            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5918        if cursor_buffer != tail_buffer {
 5919            return None;
 5920        }
 5921
 5922        let snapshot = cursor_buffer.read(cx).snapshot();
 5923        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5924        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5925        if start_word_range != end_word_range {
 5926            self.document_highlights_task.take();
 5927            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5928            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5929            return None;
 5930        }
 5931
 5932        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5933        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5934            cx.background_executor()
 5935                .timer(Duration::from_millis(debounce))
 5936                .await;
 5937
 5938            let highlights = if let Some(highlights) = cx
 5939                .update(|cx| {
 5940                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5941                })
 5942                .ok()
 5943                .flatten()
 5944            {
 5945                highlights.await.log_err()
 5946            } else {
 5947                None
 5948            };
 5949
 5950            if let Some(highlights) = highlights {
 5951                this.update(cx, |this, cx| {
 5952                    if this.pending_rename.is_some() {
 5953                        return;
 5954                    }
 5955
 5956                    let buffer_id = cursor_position.buffer_id;
 5957                    let buffer = this.buffer.read(cx);
 5958                    if !buffer
 5959                        .text_anchor_for_position(cursor_position, cx)
 5960                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5961                    {
 5962                        return;
 5963                    }
 5964
 5965                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5966                    let mut write_ranges = Vec::new();
 5967                    let mut read_ranges = Vec::new();
 5968                    for highlight in highlights {
 5969                        for (excerpt_id, excerpt_range) in
 5970                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5971                        {
 5972                            let start = highlight
 5973                                .range
 5974                                .start
 5975                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5976                            let end = highlight
 5977                                .range
 5978                                .end
 5979                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5980                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5981                                continue;
 5982                            }
 5983
 5984                            let range = Anchor {
 5985                                buffer_id,
 5986                                excerpt_id,
 5987                                text_anchor: start,
 5988                                diff_base_anchor: None,
 5989                            }..Anchor {
 5990                                buffer_id,
 5991                                excerpt_id,
 5992                                text_anchor: end,
 5993                                diff_base_anchor: None,
 5994                            };
 5995                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5996                                write_ranges.push(range);
 5997                            } else {
 5998                                read_ranges.push(range);
 5999                            }
 6000                        }
 6001                    }
 6002
 6003                    this.highlight_background::<DocumentHighlightRead>(
 6004                        &read_ranges,
 6005                        |theme| theme.editor_document_highlight_read_background,
 6006                        cx,
 6007                    );
 6008                    this.highlight_background::<DocumentHighlightWrite>(
 6009                        &write_ranges,
 6010                        |theme| theme.editor_document_highlight_write_background,
 6011                        cx,
 6012                    );
 6013                    cx.notify();
 6014                })
 6015                .log_err();
 6016            }
 6017        }));
 6018        None
 6019    }
 6020
 6021    fn prepare_highlight_query_from_selection(
 6022        &mut self,
 6023        cx: &mut Context<Editor>,
 6024    ) -> Option<(String, Range<Anchor>)> {
 6025        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6026            return None;
 6027        }
 6028        if !EditorSettings::get_global(cx).selection_highlight {
 6029            return None;
 6030        }
 6031        if self.selections.count() != 1 || self.selections.line_mode {
 6032            return None;
 6033        }
 6034        let selection = self.selections.newest::<Point>(cx);
 6035        if selection.is_empty() || selection.start.row != selection.end.row {
 6036            return None;
 6037        }
 6038        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6039        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6040        let query = multi_buffer_snapshot
 6041            .text_for_range(selection_anchor_range.clone())
 6042            .collect::<String>();
 6043        if query.trim().is_empty() {
 6044            return None;
 6045        }
 6046        Some((query, selection_anchor_range))
 6047    }
 6048
 6049    fn update_selection_occurrence_highlights(
 6050        &mut self,
 6051        query_text: String,
 6052        query_range: Range<Anchor>,
 6053        multi_buffer_range_to_query: Range<Point>,
 6054        use_debounce: bool,
 6055        window: &mut Window,
 6056        cx: &mut Context<Editor>,
 6057    ) -> Task<()> {
 6058        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6059        cx.spawn_in(window, async move |editor, cx| {
 6060            if use_debounce {
 6061                cx.background_executor()
 6062                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6063                    .await;
 6064            }
 6065            let match_task = cx.background_spawn(async move {
 6066                let buffer_ranges = multi_buffer_snapshot
 6067                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6068                    .into_iter()
 6069                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6070                let mut match_ranges = Vec::new();
 6071                let Ok(regex) = project::search::SearchQuery::text(
 6072                    query_text.clone(),
 6073                    false,
 6074                    false,
 6075                    false,
 6076                    Default::default(),
 6077                    Default::default(),
 6078                    false,
 6079                    None,
 6080                ) else {
 6081                    return Vec::default();
 6082                };
 6083                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6084                    match_ranges.extend(
 6085                        regex
 6086                            .search(&buffer_snapshot, Some(search_range.clone()))
 6087                            .await
 6088                            .into_iter()
 6089                            .filter_map(|match_range| {
 6090                                let match_start = buffer_snapshot
 6091                                    .anchor_after(search_range.start + match_range.start);
 6092                                let match_end = buffer_snapshot
 6093                                    .anchor_before(search_range.start + match_range.end);
 6094                                let match_anchor_range = Anchor::range_in_buffer(
 6095                                    excerpt_id,
 6096                                    buffer_snapshot.remote_id(),
 6097                                    match_start..match_end,
 6098                                );
 6099                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6100                            }),
 6101                    );
 6102                }
 6103                match_ranges
 6104            });
 6105            let match_ranges = match_task.await;
 6106            editor
 6107                .update_in(cx, |editor, _, cx| {
 6108                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6109                    if !match_ranges.is_empty() {
 6110                        editor.highlight_background::<SelectedTextHighlight>(
 6111                            &match_ranges,
 6112                            |theme| theme.editor_document_highlight_bracket_background,
 6113                            cx,
 6114                        )
 6115                    }
 6116                })
 6117                .log_err();
 6118        })
 6119    }
 6120
 6121    fn refresh_selected_text_highlights(
 6122        &mut self,
 6123        on_buffer_edit: bool,
 6124        window: &mut Window,
 6125        cx: &mut Context<Editor>,
 6126    ) {
 6127        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6128        else {
 6129            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6130            self.quick_selection_highlight_task.take();
 6131            self.debounced_selection_highlight_task.take();
 6132            return;
 6133        };
 6134        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6135        if on_buffer_edit
 6136            || self
 6137                .quick_selection_highlight_task
 6138                .as_ref()
 6139                .map_or(true, |(prev_anchor_range, _)| {
 6140                    prev_anchor_range != &query_range
 6141                })
 6142        {
 6143            let multi_buffer_visible_start = self
 6144                .scroll_manager
 6145                .anchor()
 6146                .anchor
 6147                .to_point(&multi_buffer_snapshot);
 6148            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6149                multi_buffer_visible_start
 6150                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6151                Bias::Left,
 6152            );
 6153            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6154            self.quick_selection_highlight_task = Some((
 6155                query_range.clone(),
 6156                self.update_selection_occurrence_highlights(
 6157                    query_text.clone(),
 6158                    query_range.clone(),
 6159                    multi_buffer_visible_range,
 6160                    false,
 6161                    window,
 6162                    cx,
 6163                ),
 6164            ));
 6165        }
 6166        if on_buffer_edit
 6167            || self
 6168                .debounced_selection_highlight_task
 6169                .as_ref()
 6170                .map_or(true, |(prev_anchor_range, _)| {
 6171                    prev_anchor_range != &query_range
 6172                })
 6173        {
 6174            let multi_buffer_start = multi_buffer_snapshot
 6175                .anchor_before(0)
 6176                .to_point(&multi_buffer_snapshot);
 6177            let multi_buffer_end = multi_buffer_snapshot
 6178                .anchor_after(multi_buffer_snapshot.len())
 6179                .to_point(&multi_buffer_snapshot);
 6180            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6181            self.debounced_selection_highlight_task = Some((
 6182                query_range.clone(),
 6183                self.update_selection_occurrence_highlights(
 6184                    query_text,
 6185                    query_range,
 6186                    multi_buffer_full_range,
 6187                    true,
 6188                    window,
 6189                    cx,
 6190                ),
 6191            ));
 6192        }
 6193    }
 6194
 6195    pub fn refresh_inline_completion(
 6196        &mut self,
 6197        debounce: bool,
 6198        user_requested: bool,
 6199        window: &mut Window,
 6200        cx: &mut Context<Self>,
 6201    ) -> Option<()> {
 6202        let provider = self.edit_prediction_provider()?;
 6203        let cursor = self.selections.newest_anchor().head();
 6204        let (buffer, cursor_buffer_position) =
 6205            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6206
 6207        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6208            self.discard_inline_completion(false, cx);
 6209            return None;
 6210        }
 6211
 6212        if !user_requested
 6213            && (!self.should_show_edit_predictions()
 6214                || !self.is_focused(window)
 6215                || buffer.read(cx).is_empty())
 6216        {
 6217            self.discard_inline_completion(false, cx);
 6218            return None;
 6219        }
 6220
 6221        self.update_visible_inline_completion(window, cx);
 6222        provider.refresh(
 6223            self.project.clone(),
 6224            buffer,
 6225            cursor_buffer_position,
 6226            debounce,
 6227            cx,
 6228        );
 6229        Some(())
 6230    }
 6231
 6232    fn show_edit_predictions_in_menu(&self) -> bool {
 6233        match self.edit_prediction_settings {
 6234            EditPredictionSettings::Disabled => false,
 6235            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6236        }
 6237    }
 6238
 6239    pub fn edit_predictions_enabled(&self) -> bool {
 6240        match self.edit_prediction_settings {
 6241            EditPredictionSettings::Disabled => false,
 6242            EditPredictionSettings::Enabled { .. } => true,
 6243        }
 6244    }
 6245
 6246    fn edit_prediction_requires_modifier(&self) -> bool {
 6247        match self.edit_prediction_settings {
 6248            EditPredictionSettings::Disabled => false,
 6249            EditPredictionSettings::Enabled {
 6250                preview_requires_modifier,
 6251                ..
 6252            } => preview_requires_modifier,
 6253        }
 6254    }
 6255
 6256    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6257        if self.edit_prediction_provider.is_none() {
 6258            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6259        } else {
 6260            let selection = self.selections.newest_anchor();
 6261            let cursor = selection.head();
 6262
 6263            if let Some((buffer, cursor_buffer_position)) =
 6264                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6265            {
 6266                self.edit_prediction_settings =
 6267                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6268            }
 6269        }
 6270    }
 6271
 6272    fn edit_prediction_settings_at_position(
 6273        &self,
 6274        buffer: &Entity<Buffer>,
 6275        buffer_position: language::Anchor,
 6276        cx: &App,
 6277    ) -> EditPredictionSettings {
 6278        if !self.mode.is_full()
 6279            || !self.show_inline_completions_override.unwrap_or(true)
 6280            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6281        {
 6282            return EditPredictionSettings::Disabled;
 6283        }
 6284
 6285        let buffer = buffer.read(cx);
 6286
 6287        let file = buffer.file();
 6288
 6289        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6290            return EditPredictionSettings::Disabled;
 6291        };
 6292
 6293        let by_provider = matches!(
 6294            self.menu_inline_completions_policy,
 6295            MenuInlineCompletionsPolicy::ByProvider
 6296        );
 6297
 6298        let show_in_menu = by_provider
 6299            && self
 6300                .edit_prediction_provider
 6301                .as_ref()
 6302                .map_or(false, |provider| {
 6303                    provider.provider.show_completions_in_menu()
 6304                });
 6305
 6306        let preview_requires_modifier =
 6307            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6308
 6309        EditPredictionSettings::Enabled {
 6310            show_in_menu,
 6311            preview_requires_modifier,
 6312        }
 6313    }
 6314
 6315    fn should_show_edit_predictions(&self) -> bool {
 6316        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6317    }
 6318
 6319    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6320        matches!(
 6321            self.edit_prediction_preview,
 6322            EditPredictionPreview::Active { .. }
 6323        )
 6324    }
 6325
 6326    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6327        let cursor = self.selections.newest_anchor().head();
 6328        if let Some((buffer, cursor_position)) =
 6329            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6330        {
 6331            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6332        } else {
 6333            false
 6334        }
 6335    }
 6336
 6337    pub fn supports_minimap(&self, cx: &App) -> bool {
 6338        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6339    }
 6340
 6341    fn edit_predictions_enabled_in_buffer(
 6342        &self,
 6343        buffer: &Entity<Buffer>,
 6344        buffer_position: language::Anchor,
 6345        cx: &App,
 6346    ) -> bool {
 6347        maybe!({
 6348            if self.read_only(cx) {
 6349                return Some(false);
 6350            }
 6351            let provider = self.edit_prediction_provider()?;
 6352            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6353                return Some(false);
 6354            }
 6355            let buffer = buffer.read(cx);
 6356            let Some(file) = buffer.file() else {
 6357                return Some(true);
 6358            };
 6359            let settings = all_language_settings(Some(file), cx);
 6360            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6361        })
 6362        .unwrap_or(false)
 6363    }
 6364
 6365    fn cycle_inline_completion(
 6366        &mut self,
 6367        direction: Direction,
 6368        window: &mut Window,
 6369        cx: &mut Context<Self>,
 6370    ) -> Option<()> {
 6371        let provider = self.edit_prediction_provider()?;
 6372        let cursor = self.selections.newest_anchor().head();
 6373        let (buffer, cursor_buffer_position) =
 6374            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6375        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6376            return None;
 6377        }
 6378
 6379        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6380        self.update_visible_inline_completion(window, cx);
 6381
 6382        Some(())
 6383    }
 6384
 6385    pub fn show_inline_completion(
 6386        &mut self,
 6387        _: &ShowEditPrediction,
 6388        window: &mut Window,
 6389        cx: &mut Context<Self>,
 6390    ) {
 6391        if !self.has_active_inline_completion() {
 6392            self.refresh_inline_completion(false, true, window, cx);
 6393            return;
 6394        }
 6395
 6396        self.update_visible_inline_completion(window, cx);
 6397    }
 6398
 6399    pub fn display_cursor_names(
 6400        &mut self,
 6401        _: &DisplayCursorNames,
 6402        window: &mut Window,
 6403        cx: &mut Context<Self>,
 6404    ) {
 6405        self.show_cursor_names(window, cx);
 6406    }
 6407
 6408    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6409        self.show_cursor_names = true;
 6410        cx.notify();
 6411        cx.spawn_in(window, async move |this, cx| {
 6412            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6413            this.update(cx, |this, cx| {
 6414                this.show_cursor_names = false;
 6415                cx.notify()
 6416            })
 6417            .ok()
 6418        })
 6419        .detach();
 6420    }
 6421
 6422    pub fn next_edit_prediction(
 6423        &mut self,
 6424        _: &NextEditPrediction,
 6425        window: &mut Window,
 6426        cx: &mut Context<Self>,
 6427    ) {
 6428        if self.has_active_inline_completion() {
 6429            self.cycle_inline_completion(Direction::Next, window, cx);
 6430        } else {
 6431            let is_copilot_disabled = self
 6432                .refresh_inline_completion(false, true, window, cx)
 6433                .is_none();
 6434            if is_copilot_disabled {
 6435                cx.propagate();
 6436            }
 6437        }
 6438    }
 6439
 6440    pub fn previous_edit_prediction(
 6441        &mut self,
 6442        _: &PreviousEditPrediction,
 6443        window: &mut Window,
 6444        cx: &mut Context<Self>,
 6445    ) {
 6446        if self.has_active_inline_completion() {
 6447            self.cycle_inline_completion(Direction::Prev, window, cx);
 6448        } else {
 6449            let is_copilot_disabled = self
 6450                .refresh_inline_completion(false, true, window, cx)
 6451                .is_none();
 6452            if is_copilot_disabled {
 6453                cx.propagate();
 6454            }
 6455        }
 6456    }
 6457
 6458    pub fn accept_edit_prediction(
 6459        &mut self,
 6460        _: &AcceptEditPrediction,
 6461        window: &mut Window,
 6462        cx: &mut Context<Self>,
 6463    ) {
 6464        if self.show_edit_predictions_in_menu() {
 6465            self.hide_context_menu(window, cx);
 6466        }
 6467
 6468        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6469            return;
 6470        };
 6471
 6472        self.report_inline_completion_event(
 6473            active_inline_completion.completion_id.clone(),
 6474            true,
 6475            cx,
 6476        );
 6477
 6478        match &active_inline_completion.completion {
 6479            InlineCompletion::Move { target, .. } => {
 6480                let target = *target;
 6481
 6482                if let Some(position_map) = &self.last_position_map {
 6483                    if position_map
 6484                        .visible_row_range
 6485                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6486                        || !self.edit_prediction_requires_modifier()
 6487                    {
 6488                        self.unfold_ranges(&[target..target], true, false, cx);
 6489                        // Note that this is also done in vim's handler of the Tab action.
 6490                        self.change_selections(
 6491                            Some(Autoscroll::newest()),
 6492                            window,
 6493                            cx,
 6494                            |selections| {
 6495                                selections.select_anchor_ranges([target..target]);
 6496                            },
 6497                        );
 6498                        self.clear_row_highlights::<EditPredictionPreview>();
 6499
 6500                        self.edit_prediction_preview
 6501                            .set_previous_scroll_position(None);
 6502                    } else {
 6503                        self.edit_prediction_preview
 6504                            .set_previous_scroll_position(Some(
 6505                                position_map.snapshot.scroll_anchor,
 6506                            ));
 6507
 6508                        self.highlight_rows::<EditPredictionPreview>(
 6509                            target..target,
 6510                            cx.theme().colors().editor_highlighted_line_background,
 6511                            RowHighlightOptions {
 6512                                autoscroll: true,
 6513                                ..Default::default()
 6514                            },
 6515                            cx,
 6516                        );
 6517                        self.request_autoscroll(Autoscroll::fit(), cx);
 6518                    }
 6519                }
 6520            }
 6521            InlineCompletion::Edit { edits, .. } => {
 6522                if let Some(provider) = self.edit_prediction_provider() {
 6523                    provider.accept(cx);
 6524                }
 6525
 6526                let snapshot = self.buffer.read(cx).snapshot(cx);
 6527                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6528
 6529                self.buffer.update(cx, |buffer, cx| {
 6530                    buffer.edit(edits.iter().cloned(), None, cx)
 6531                });
 6532
 6533                self.change_selections(None, window, cx, |s| {
 6534                    s.select_anchor_ranges([last_edit_end..last_edit_end])
 6535                });
 6536
 6537                self.update_visible_inline_completion(window, cx);
 6538                if self.active_inline_completion.is_none() {
 6539                    self.refresh_inline_completion(true, true, window, cx);
 6540                }
 6541
 6542                cx.notify();
 6543            }
 6544        }
 6545
 6546        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6547    }
 6548
 6549    pub fn accept_partial_inline_completion(
 6550        &mut self,
 6551        _: &AcceptPartialEditPrediction,
 6552        window: &mut Window,
 6553        cx: &mut Context<Self>,
 6554    ) {
 6555        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6556            return;
 6557        };
 6558        if self.selections.count() != 1 {
 6559            return;
 6560        }
 6561
 6562        self.report_inline_completion_event(
 6563            active_inline_completion.completion_id.clone(),
 6564            true,
 6565            cx,
 6566        );
 6567
 6568        match &active_inline_completion.completion {
 6569            InlineCompletion::Move { target, .. } => {
 6570                let target = *target;
 6571                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6572                    selections.select_anchor_ranges([target..target]);
 6573                });
 6574            }
 6575            InlineCompletion::Edit { edits, .. } => {
 6576                // Find an insertion that starts at the cursor position.
 6577                let snapshot = self.buffer.read(cx).snapshot(cx);
 6578                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6579                let insertion = edits.iter().find_map(|(range, text)| {
 6580                    let range = range.to_offset(&snapshot);
 6581                    if range.is_empty() && range.start == cursor_offset {
 6582                        Some(text)
 6583                    } else {
 6584                        None
 6585                    }
 6586                });
 6587
 6588                if let Some(text) = insertion {
 6589                    let mut partial_completion = text
 6590                        .chars()
 6591                        .by_ref()
 6592                        .take_while(|c| c.is_alphabetic())
 6593                        .collect::<String>();
 6594                    if partial_completion.is_empty() {
 6595                        partial_completion = text
 6596                            .chars()
 6597                            .by_ref()
 6598                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6599                            .collect::<String>();
 6600                    }
 6601
 6602                    cx.emit(EditorEvent::InputHandled {
 6603                        utf16_range_to_replace: None,
 6604                        text: partial_completion.clone().into(),
 6605                    });
 6606
 6607                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6608
 6609                    self.refresh_inline_completion(true, true, window, cx);
 6610                    cx.notify();
 6611                } else {
 6612                    self.accept_edit_prediction(&Default::default(), window, cx);
 6613                }
 6614            }
 6615        }
 6616    }
 6617
 6618    fn discard_inline_completion(
 6619        &mut self,
 6620        should_report_inline_completion_event: bool,
 6621        cx: &mut Context<Self>,
 6622    ) -> bool {
 6623        if should_report_inline_completion_event {
 6624            let completion_id = self
 6625                .active_inline_completion
 6626                .as_ref()
 6627                .and_then(|active_completion| active_completion.completion_id.clone());
 6628
 6629            self.report_inline_completion_event(completion_id, false, cx);
 6630        }
 6631
 6632        if let Some(provider) = self.edit_prediction_provider() {
 6633            provider.discard(cx);
 6634        }
 6635
 6636        self.take_active_inline_completion(cx)
 6637    }
 6638
 6639    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6640        let Some(provider) = self.edit_prediction_provider() else {
 6641            return;
 6642        };
 6643
 6644        let Some((_, buffer, _)) = self
 6645            .buffer
 6646            .read(cx)
 6647            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6648        else {
 6649            return;
 6650        };
 6651
 6652        let extension = buffer
 6653            .read(cx)
 6654            .file()
 6655            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6656
 6657        let event_type = match accepted {
 6658            true => "Edit Prediction Accepted",
 6659            false => "Edit Prediction Discarded",
 6660        };
 6661        telemetry::event!(
 6662            event_type,
 6663            provider = provider.name(),
 6664            prediction_id = id,
 6665            suggestion_accepted = accepted,
 6666            file_extension = extension,
 6667        );
 6668    }
 6669
 6670    pub fn has_active_inline_completion(&self) -> bool {
 6671        self.active_inline_completion.is_some()
 6672    }
 6673
 6674    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6675        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6676            return false;
 6677        };
 6678
 6679        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6680        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6681        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6682        true
 6683    }
 6684
 6685    /// Returns true when we're displaying the edit prediction popover below the cursor
 6686    /// like we are not previewing and the LSP autocomplete menu is visible
 6687    /// or we are in `when_holding_modifier` mode.
 6688    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6689        if self.edit_prediction_preview_is_active()
 6690            || !self.show_edit_predictions_in_menu()
 6691            || !self.edit_predictions_enabled()
 6692        {
 6693            return false;
 6694        }
 6695
 6696        if self.has_visible_completions_menu() {
 6697            return true;
 6698        }
 6699
 6700        has_completion && self.edit_prediction_requires_modifier()
 6701    }
 6702
 6703    fn handle_modifiers_changed(
 6704        &mut self,
 6705        modifiers: Modifiers,
 6706        position_map: &PositionMap,
 6707        window: &mut Window,
 6708        cx: &mut Context<Self>,
 6709    ) {
 6710        if self.show_edit_predictions_in_menu() {
 6711            self.update_edit_prediction_preview(&modifiers, window, cx);
 6712        }
 6713
 6714        self.update_selection_mode(&modifiers, position_map, window, cx);
 6715
 6716        let mouse_position = window.mouse_position();
 6717        if !position_map.text_hitbox.is_hovered(window) {
 6718            return;
 6719        }
 6720
 6721        self.update_hovered_link(
 6722            position_map.point_for_position(mouse_position),
 6723            &position_map.snapshot,
 6724            modifiers,
 6725            window,
 6726            cx,
 6727        )
 6728    }
 6729
 6730    fn update_selection_mode(
 6731        &mut self,
 6732        modifiers: &Modifiers,
 6733        position_map: &PositionMap,
 6734        window: &mut Window,
 6735        cx: &mut Context<Self>,
 6736    ) {
 6737        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6738            return;
 6739        }
 6740
 6741        let mouse_position = window.mouse_position();
 6742        let point_for_position = position_map.point_for_position(mouse_position);
 6743        let position = point_for_position.previous_valid;
 6744
 6745        self.select(
 6746            SelectPhase::BeginColumnar {
 6747                position,
 6748                reset: false,
 6749                goal_column: point_for_position.exact_unclipped.column(),
 6750            },
 6751            window,
 6752            cx,
 6753        );
 6754    }
 6755
 6756    fn update_edit_prediction_preview(
 6757        &mut self,
 6758        modifiers: &Modifiers,
 6759        window: &mut Window,
 6760        cx: &mut Context<Self>,
 6761    ) {
 6762        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6763        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6764            return;
 6765        };
 6766
 6767        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6768            if matches!(
 6769                self.edit_prediction_preview,
 6770                EditPredictionPreview::Inactive { .. }
 6771            ) {
 6772                self.edit_prediction_preview = EditPredictionPreview::Active {
 6773                    previous_scroll_position: None,
 6774                    since: Instant::now(),
 6775                };
 6776
 6777                self.update_visible_inline_completion(window, cx);
 6778                cx.notify();
 6779            }
 6780        } else if let EditPredictionPreview::Active {
 6781            previous_scroll_position,
 6782            since,
 6783        } = self.edit_prediction_preview
 6784        {
 6785            if let (Some(previous_scroll_position), Some(position_map)) =
 6786                (previous_scroll_position, self.last_position_map.as_ref())
 6787            {
 6788                self.set_scroll_position(
 6789                    previous_scroll_position
 6790                        .scroll_position(&position_map.snapshot.display_snapshot),
 6791                    window,
 6792                    cx,
 6793                );
 6794            }
 6795
 6796            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6797                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6798            };
 6799            self.clear_row_highlights::<EditPredictionPreview>();
 6800            self.update_visible_inline_completion(window, cx);
 6801            cx.notify();
 6802        }
 6803    }
 6804
 6805    fn update_visible_inline_completion(
 6806        &mut self,
 6807        _window: &mut Window,
 6808        cx: &mut Context<Self>,
 6809    ) -> Option<()> {
 6810        let selection = self.selections.newest_anchor();
 6811        let cursor = selection.head();
 6812        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6813        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6814        let excerpt_id = cursor.excerpt_id;
 6815
 6816        let show_in_menu = self.show_edit_predictions_in_menu();
 6817        let completions_menu_has_precedence = !show_in_menu
 6818            && (self.context_menu.borrow().is_some()
 6819                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6820
 6821        if completions_menu_has_precedence
 6822            || !offset_selection.is_empty()
 6823            || self
 6824                .active_inline_completion
 6825                .as_ref()
 6826                .map_or(false, |completion| {
 6827                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6828                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6829                    !invalidation_range.contains(&offset_selection.head())
 6830                })
 6831        {
 6832            self.discard_inline_completion(false, cx);
 6833            return None;
 6834        }
 6835
 6836        self.take_active_inline_completion(cx);
 6837        let Some(provider) = self.edit_prediction_provider() else {
 6838            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6839            return None;
 6840        };
 6841
 6842        let (buffer, cursor_buffer_position) =
 6843            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6844
 6845        self.edit_prediction_settings =
 6846            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6847
 6848        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6849
 6850        if self.edit_prediction_indent_conflict {
 6851            let cursor_point = cursor.to_point(&multibuffer);
 6852
 6853            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6854
 6855            if let Some((_, indent)) = indents.iter().next() {
 6856                if indent.len == cursor_point.column {
 6857                    self.edit_prediction_indent_conflict = false;
 6858                }
 6859            }
 6860        }
 6861
 6862        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6863        let edits = inline_completion
 6864            .edits
 6865            .into_iter()
 6866            .flat_map(|(range, new_text)| {
 6867                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6868                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6869                Some((start..end, new_text))
 6870            })
 6871            .collect::<Vec<_>>();
 6872        if edits.is_empty() {
 6873            return None;
 6874        }
 6875
 6876        let first_edit_start = edits.first().unwrap().0.start;
 6877        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6878        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6879
 6880        let last_edit_end = edits.last().unwrap().0.end;
 6881        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6882        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6883
 6884        let cursor_row = cursor.to_point(&multibuffer).row;
 6885
 6886        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6887
 6888        let mut inlay_ids = Vec::new();
 6889        let invalidation_row_range;
 6890        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6891            Some(cursor_row..edit_end_row)
 6892        } else if cursor_row > edit_end_row {
 6893            Some(edit_start_row..cursor_row)
 6894        } else {
 6895            None
 6896        };
 6897        let is_move =
 6898            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6899        let completion = if is_move {
 6900            invalidation_row_range =
 6901                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6902            let target = first_edit_start;
 6903            InlineCompletion::Move { target, snapshot }
 6904        } else {
 6905            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6906                && !self.inline_completions_hidden_for_vim_mode;
 6907
 6908            if show_completions_in_buffer {
 6909                if edits
 6910                    .iter()
 6911                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6912                {
 6913                    let mut inlays = Vec::new();
 6914                    for (range, new_text) in &edits {
 6915                        let inlay = Inlay::inline_completion(
 6916                            post_inc(&mut self.next_inlay_id),
 6917                            range.start,
 6918                            new_text.as_str(),
 6919                        );
 6920                        inlay_ids.push(inlay.id);
 6921                        inlays.push(inlay);
 6922                    }
 6923
 6924                    self.splice_inlays(&[], inlays, cx);
 6925                } else {
 6926                    let background_color = cx.theme().status().deleted_background;
 6927                    self.highlight_text::<InlineCompletionHighlight>(
 6928                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6929                        HighlightStyle {
 6930                            background_color: Some(background_color),
 6931                            ..Default::default()
 6932                        },
 6933                        cx,
 6934                    );
 6935                }
 6936            }
 6937
 6938            invalidation_row_range = edit_start_row..edit_end_row;
 6939
 6940            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6941                if provider.show_tab_accept_marker() {
 6942                    EditDisplayMode::TabAccept
 6943                } else {
 6944                    EditDisplayMode::Inline
 6945                }
 6946            } else {
 6947                EditDisplayMode::DiffPopover
 6948            };
 6949
 6950            InlineCompletion::Edit {
 6951                edits,
 6952                edit_preview: inline_completion.edit_preview,
 6953                display_mode,
 6954                snapshot,
 6955            }
 6956        };
 6957
 6958        let invalidation_range = multibuffer
 6959            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6960            ..multibuffer.anchor_after(Point::new(
 6961                invalidation_row_range.end,
 6962                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6963            ));
 6964
 6965        self.stale_inline_completion_in_menu = None;
 6966        self.active_inline_completion = Some(InlineCompletionState {
 6967            inlay_ids,
 6968            completion,
 6969            completion_id: inline_completion.id,
 6970            invalidation_range,
 6971        });
 6972
 6973        cx.notify();
 6974
 6975        Some(())
 6976    }
 6977
 6978    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6979        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6980    }
 6981
 6982    fn clear_tasks(&mut self) {
 6983        self.tasks.clear()
 6984    }
 6985
 6986    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 6987        if self.tasks.insert(key, value).is_some() {
 6988            // This case should hopefully be rare, but just in case...
 6989            log::error!(
 6990                "multiple different run targets found on a single line, only the last target will be rendered"
 6991            )
 6992        }
 6993    }
 6994
 6995    /// Get all display points of breakpoints that will be rendered within editor
 6996    ///
 6997    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 6998    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 6999    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7000    fn active_breakpoints(
 7001        &self,
 7002        range: Range<DisplayRow>,
 7003        window: &mut Window,
 7004        cx: &mut Context<Self>,
 7005    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7006        let mut breakpoint_display_points = HashMap::default();
 7007
 7008        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7009            return breakpoint_display_points;
 7010        };
 7011
 7012        let snapshot = self.snapshot(window, cx);
 7013
 7014        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7015        let Some(project) = self.project.as_ref() else {
 7016            return breakpoint_display_points;
 7017        };
 7018
 7019        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7020            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7021
 7022        for (buffer_snapshot, range, excerpt_id) in
 7023            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7024        {
 7025            let Some(buffer) = project.read_with(cx, |this, cx| {
 7026                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7027            }) else {
 7028                continue;
 7029            };
 7030            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7031                &buffer,
 7032                Some(
 7033                    buffer_snapshot.anchor_before(range.start)
 7034                        ..buffer_snapshot.anchor_after(range.end),
 7035                ),
 7036                buffer_snapshot,
 7037                cx,
 7038            );
 7039            for (breakpoint, state) in breakpoints {
 7040                let multi_buffer_anchor =
 7041                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7042                let position = multi_buffer_anchor
 7043                    .to_point(&multi_buffer_snapshot)
 7044                    .to_display_point(&snapshot);
 7045
 7046                breakpoint_display_points.insert(
 7047                    position.row(),
 7048                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7049                );
 7050            }
 7051        }
 7052
 7053        breakpoint_display_points
 7054    }
 7055
 7056    fn breakpoint_context_menu(
 7057        &self,
 7058        anchor: Anchor,
 7059        window: &mut Window,
 7060        cx: &mut Context<Self>,
 7061    ) -> Entity<ui::ContextMenu> {
 7062        let weak_editor = cx.weak_entity();
 7063        let focus_handle = self.focus_handle(cx);
 7064
 7065        let row = self
 7066            .buffer
 7067            .read(cx)
 7068            .snapshot(cx)
 7069            .summary_for_anchor::<Point>(&anchor)
 7070            .row;
 7071
 7072        let breakpoint = self
 7073            .breakpoint_at_row(row, window, cx)
 7074            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7075
 7076        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7077            "Edit Log Breakpoint"
 7078        } else {
 7079            "Set Log Breakpoint"
 7080        };
 7081
 7082        let condition_breakpoint_msg = if breakpoint
 7083            .as_ref()
 7084            .is_some_and(|bp| bp.1.condition.is_some())
 7085        {
 7086            "Edit Condition Breakpoint"
 7087        } else {
 7088            "Set Condition Breakpoint"
 7089        };
 7090
 7091        let hit_condition_breakpoint_msg = if breakpoint
 7092            .as_ref()
 7093            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7094        {
 7095            "Edit Hit Condition Breakpoint"
 7096        } else {
 7097            "Set Hit Condition Breakpoint"
 7098        };
 7099
 7100        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7101            "Unset Breakpoint"
 7102        } else {
 7103            "Set Breakpoint"
 7104        };
 7105
 7106        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7107            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7108
 7109        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7110            BreakpointState::Enabled => Some("Disable"),
 7111            BreakpointState::Disabled => Some("Enable"),
 7112        });
 7113
 7114        let (anchor, breakpoint) =
 7115            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7116
 7117        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7118            menu.on_blur_subscription(Subscription::new(|| {}))
 7119                .context(focus_handle)
 7120                .when(run_to_cursor, |this| {
 7121                    let weak_editor = weak_editor.clone();
 7122                    this.entry("Run to cursor", None, move |window, cx| {
 7123                        weak_editor
 7124                            .update(cx, |editor, cx| {
 7125                                editor.change_selections(None, window, cx, |s| {
 7126                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7127                                });
 7128                            })
 7129                            .ok();
 7130
 7131                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7132                    })
 7133                    .separator()
 7134                })
 7135                .when_some(toggle_state_msg, |this, msg| {
 7136                    this.entry(msg, None, {
 7137                        let weak_editor = weak_editor.clone();
 7138                        let breakpoint = breakpoint.clone();
 7139                        move |_window, cx| {
 7140                            weak_editor
 7141                                .update(cx, |this, cx| {
 7142                                    this.edit_breakpoint_at_anchor(
 7143                                        anchor,
 7144                                        breakpoint.as_ref().clone(),
 7145                                        BreakpointEditAction::InvertState,
 7146                                        cx,
 7147                                    );
 7148                                })
 7149                                .log_err();
 7150                        }
 7151                    })
 7152                })
 7153                .entry(set_breakpoint_msg, None, {
 7154                    let weak_editor = weak_editor.clone();
 7155                    let breakpoint = breakpoint.clone();
 7156                    move |_window, cx| {
 7157                        weak_editor
 7158                            .update(cx, |this, cx| {
 7159                                this.edit_breakpoint_at_anchor(
 7160                                    anchor,
 7161                                    breakpoint.as_ref().clone(),
 7162                                    BreakpointEditAction::Toggle,
 7163                                    cx,
 7164                                );
 7165                            })
 7166                            .log_err();
 7167                    }
 7168                })
 7169                .entry(log_breakpoint_msg, None, {
 7170                    let breakpoint = breakpoint.clone();
 7171                    let weak_editor = weak_editor.clone();
 7172                    move |window, cx| {
 7173                        weak_editor
 7174                            .update(cx, |this, cx| {
 7175                                this.add_edit_breakpoint_block(
 7176                                    anchor,
 7177                                    breakpoint.as_ref(),
 7178                                    BreakpointPromptEditAction::Log,
 7179                                    window,
 7180                                    cx,
 7181                                );
 7182                            })
 7183                            .log_err();
 7184                    }
 7185                })
 7186                .entry(condition_breakpoint_msg, None, {
 7187                    let breakpoint = breakpoint.clone();
 7188                    let weak_editor = weak_editor.clone();
 7189                    move |window, cx| {
 7190                        weak_editor
 7191                            .update(cx, |this, cx| {
 7192                                this.add_edit_breakpoint_block(
 7193                                    anchor,
 7194                                    breakpoint.as_ref(),
 7195                                    BreakpointPromptEditAction::Condition,
 7196                                    window,
 7197                                    cx,
 7198                                );
 7199                            })
 7200                            .log_err();
 7201                    }
 7202                })
 7203                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7204                    weak_editor
 7205                        .update(cx, |this, cx| {
 7206                            this.add_edit_breakpoint_block(
 7207                                anchor,
 7208                                breakpoint.as_ref(),
 7209                                BreakpointPromptEditAction::HitCondition,
 7210                                window,
 7211                                cx,
 7212                            );
 7213                        })
 7214                        .log_err();
 7215                })
 7216        })
 7217    }
 7218
 7219    fn render_breakpoint(
 7220        &self,
 7221        position: Anchor,
 7222        row: DisplayRow,
 7223        breakpoint: &Breakpoint,
 7224        state: Option<BreakpointSessionState>,
 7225        cx: &mut Context<Self>,
 7226    ) -> IconButton {
 7227        let is_rejected = state.is_some_and(|s| !s.verified);
 7228        // Is it a breakpoint that shows up when hovering over gutter?
 7229        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7230            (false, false),
 7231            |PhantomBreakpointIndicator {
 7232                 is_active,
 7233                 display_row,
 7234                 collides_with_existing_breakpoint,
 7235             }| {
 7236                (
 7237                    is_active && display_row == row,
 7238                    collides_with_existing_breakpoint,
 7239                )
 7240            },
 7241        );
 7242
 7243        let (color, icon) = {
 7244            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7245                (false, false) => ui::IconName::DebugBreakpoint,
 7246                (true, false) => ui::IconName::DebugLogBreakpoint,
 7247                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7248                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7249            };
 7250
 7251            let color = if is_phantom {
 7252                Color::Hint
 7253            } else if is_rejected {
 7254                Color::Disabled
 7255            } else {
 7256                Color::Debugger
 7257            };
 7258
 7259            (color, icon)
 7260        };
 7261
 7262        let breakpoint = Arc::from(breakpoint.clone());
 7263
 7264        let alt_as_text = gpui::Keystroke {
 7265            modifiers: Modifiers::secondary_key(),
 7266            ..Default::default()
 7267        };
 7268        let primary_action_text = if breakpoint.is_disabled() {
 7269            "Enable breakpoint"
 7270        } else if is_phantom && !collides_with_existing {
 7271            "Set breakpoint"
 7272        } else {
 7273            "Unset breakpoint"
 7274        };
 7275        let focus_handle = self.focus_handle.clone();
 7276
 7277        let meta = if is_rejected {
 7278            SharedString::from("No executable code is associated with this line.")
 7279        } else if collides_with_existing && !breakpoint.is_disabled() {
 7280            SharedString::from(format!(
 7281                "{alt_as_text}-click to disable,\nright-click for more options."
 7282            ))
 7283        } else {
 7284            SharedString::from("Right-click for more options.")
 7285        };
 7286        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7287            .icon_size(IconSize::XSmall)
 7288            .size(ui::ButtonSize::None)
 7289            .when(is_rejected, |this| {
 7290                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7291            })
 7292            .icon_color(color)
 7293            .style(ButtonStyle::Transparent)
 7294            .on_click(cx.listener({
 7295                let breakpoint = breakpoint.clone();
 7296
 7297                move |editor, event: &ClickEvent, window, cx| {
 7298                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7299                        BreakpointEditAction::InvertState
 7300                    } else {
 7301                        BreakpointEditAction::Toggle
 7302                    };
 7303
 7304                    window.focus(&editor.focus_handle(cx));
 7305                    editor.edit_breakpoint_at_anchor(
 7306                        position,
 7307                        breakpoint.as_ref().clone(),
 7308                        edit_action,
 7309                        cx,
 7310                    );
 7311                }
 7312            }))
 7313            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7314                editor.set_breakpoint_context_menu(
 7315                    row,
 7316                    Some(position),
 7317                    event.down.position,
 7318                    window,
 7319                    cx,
 7320                );
 7321            }))
 7322            .tooltip(move |window, cx| {
 7323                Tooltip::with_meta_in(
 7324                    primary_action_text,
 7325                    Some(&ToggleBreakpoint),
 7326                    meta.clone(),
 7327                    &focus_handle,
 7328                    window,
 7329                    cx,
 7330                )
 7331            })
 7332    }
 7333
 7334    fn build_tasks_context(
 7335        project: &Entity<Project>,
 7336        buffer: &Entity<Buffer>,
 7337        buffer_row: u32,
 7338        tasks: &Arc<RunnableTasks>,
 7339        cx: &mut Context<Self>,
 7340    ) -> Task<Option<task::TaskContext>> {
 7341        let position = Point::new(buffer_row, tasks.column);
 7342        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7343        let location = Location {
 7344            buffer: buffer.clone(),
 7345            range: range_start..range_start,
 7346        };
 7347        // Fill in the environmental variables from the tree-sitter captures
 7348        let mut captured_task_variables = TaskVariables::default();
 7349        for (capture_name, value) in tasks.extra_variables.clone() {
 7350            captured_task_variables.insert(
 7351                task::VariableName::Custom(capture_name.into()),
 7352                value.clone(),
 7353            );
 7354        }
 7355        project.update(cx, |project, cx| {
 7356            project.task_store().update(cx, |task_store, cx| {
 7357                task_store.task_context_for_location(captured_task_variables, location, cx)
 7358            })
 7359        })
 7360    }
 7361
 7362    pub fn spawn_nearest_task(
 7363        &mut self,
 7364        action: &SpawnNearestTask,
 7365        window: &mut Window,
 7366        cx: &mut Context<Self>,
 7367    ) {
 7368        let Some((workspace, _)) = self.workspace.clone() else {
 7369            return;
 7370        };
 7371        let Some(project) = self.project.clone() else {
 7372            return;
 7373        };
 7374
 7375        // Try to find a closest, enclosing node using tree-sitter that has a
 7376        // task
 7377        let Some((buffer, buffer_row, tasks)) = self
 7378            .find_enclosing_node_task(cx)
 7379            // Or find the task that's closest in row-distance.
 7380            .or_else(|| self.find_closest_task(cx))
 7381        else {
 7382            return;
 7383        };
 7384
 7385        let reveal_strategy = action.reveal;
 7386        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7387        cx.spawn_in(window, async move |_, cx| {
 7388            let context = task_context.await?;
 7389            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7390
 7391            let resolved = &mut resolved_task.resolved;
 7392            resolved.reveal = reveal_strategy;
 7393
 7394            workspace
 7395                .update_in(cx, |workspace, window, cx| {
 7396                    workspace.schedule_resolved_task(
 7397                        task_source_kind,
 7398                        resolved_task,
 7399                        false,
 7400                        window,
 7401                        cx,
 7402                    );
 7403                })
 7404                .ok()
 7405        })
 7406        .detach();
 7407    }
 7408
 7409    fn find_closest_task(
 7410        &mut self,
 7411        cx: &mut Context<Self>,
 7412    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7413        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7414
 7415        let ((buffer_id, row), tasks) = self
 7416            .tasks
 7417            .iter()
 7418            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7419
 7420        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7421        let tasks = Arc::new(tasks.to_owned());
 7422        Some((buffer, *row, tasks))
 7423    }
 7424
 7425    fn find_enclosing_node_task(
 7426        &mut self,
 7427        cx: &mut Context<Self>,
 7428    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7429        let snapshot = self.buffer.read(cx).snapshot(cx);
 7430        let offset = self.selections.newest::<usize>(cx).head();
 7431        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7432        let buffer_id = excerpt.buffer().remote_id();
 7433
 7434        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7435        let mut cursor = layer.node().walk();
 7436
 7437        while cursor.goto_first_child_for_byte(offset).is_some() {
 7438            if cursor.node().end_byte() == offset {
 7439                cursor.goto_next_sibling();
 7440            }
 7441        }
 7442
 7443        // Ascend to the smallest ancestor that contains the range and has a task.
 7444        loop {
 7445            let node = cursor.node();
 7446            let node_range = node.byte_range();
 7447            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7448
 7449            // Check if this node contains our offset
 7450            if node_range.start <= offset && node_range.end >= offset {
 7451                // If it contains offset, check for task
 7452                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7453                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7454                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7455                }
 7456            }
 7457
 7458            if !cursor.goto_parent() {
 7459                break;
 7460            }
 7461        }
 7462        None
 7463    }
 7464
 7465    fn render_run_indicator(
 7466        &self,
 7467        _style: &EditorStyle,
 7468        is_active: bool,
 7469        row: DisplayRow,
 7470        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7471        cx: &mut Context<Self>,
 7472    ) -> IconButton {
 7473        let color = Color::Muted;
 7474        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7475
 7476        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7477            .shape(ui::IconButtonShape::Square)
 7478            .icon_size(IconSize::XSmall)
 7479            .icon_color(color)
 7480            .toggle_state(is_active)
 7481            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7482                let quick_launch = e.down.button == MouseButton::Left;
 7483                window.focus(&editor.focus_handle(cx));
 7484                editor.toggle_code_actions(
 7485                    &ToggleCodeActions {
 7486                        deployed_from_indicator: Some(row),
 7487                        quick_launch,
 7488                    },
 7489                    window,
 7490                    cx,
 7491                );
 7492            }))
 7493            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7494                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7495            }))
 7496    }
 7497
 7498    pub fn context_menu_visible(&self) -> bool {
 7499        !self.edit_prediction_preview_is_active()
 7500            && self
 7501                .context_menu
 7502                .borrow()
 7503                .as_ref()
 7504                .map_or(false, |menu| menu.visible())
 7505    }
 7506
 7507    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7508        self.context_menu
 7509            .borrow()
 7510            .as_ref()
 7511            .map(|menu| menu.origin())
 7512    }
 7513
 7514    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7515        self.context_menu_options = Some(options);
 7516    }
 7517
 7518    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7519    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7520
 7521    fn render_edit_prediction_popover(
 7522        &mut self,
 7523        text_bounds: &Bounds<Pixels>,
 7524        content_origin: gpui::Point<Pixels>,
 7525        right_margin: Pixels,
 7526        editor_snapshot: &EditorSnapshot,
 7527        visible_row_range: Range<DisplayRow>,
 7528        scroll_top: f32,
 7529        scroll_bottom: f32,
 7530        line_layouts: &[LineWithInvisibles],
 7531        line_height: Pixels,
 7532        scroll_pixel_position: gpui::Point<Pixels>,
 7533        newest_selection_head: Option<DisplayPoint>,
 7534        editor_width: Pixels,
 7535        style: &EditorStyle,
 7536        window: &mut Window,
 7537        cx: &mut App,
 7538    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7539        if self.mode().is_minimap() {
 7540            return None;
 7541        }
 7542        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7543
 7544        if self.edit_prediction_visible_in_cursor_popover(true) {
 7545            return None;
 7546        }
 7547
 7548        match &active_inline_completion.completion {
 7549            InlineCompletion::Move { target, .. } => {
 7550                let target_display_point = target.to_display_point(editor_snapshot);
 7551
 7552                if self.edit_prediction_requires_modifier() {
 7553                    if !self.edit_prediction_preview_is_active() {
 7554                        return None;
 7555                    }
 7556
 7557                    self.render_edit_prediction_modifier_jump_popover(
 7558                        text_bounds,
 7559                        content_origin,
 7560                        visible_row_range,
 7561                        line_layouts,
 7562                        line_height,
 7563                        scroll_pixel_position,
 7564                        newest_selection_head,
 7565                        target_display_point,
 7566                        window,
 7567                        cx,
 7568                    )
 7569                } else {
 7570                    self.render_edit_prediction_eager_jump_popover(
 7571                        text_bounds,
 7572                        content_origin,
 7573                        editor_snapshot,
 7574                        visible_row_range,
 7575                        scroll_top,
 7576                        scroll_bottom,
 7577                        line_height,
 7578                        scroll_pixel_position,
 7579                        target_display_point,
 7580                        editor_width,
 7581                        window,
 7582                        cx,
 7583                    )
 7584                }
 7585            }
 7586            InlineCompletion::Edit {
 7587                display_mode: EditDisplayMode::Inline,
 7588                ..
 7589            } => None,
 7590            InlineCompletion::Edit {
 7591                display_mode: EditDisplayMode::TabAccept,
 7592                edits,
 7593                ..
 7594            } => {
 7595                let range = &edits.first()?.0;
 7596                let target_display_point = range.end.to_display_point(editor_snapshot);
 7597
 7598                self.render_edit_prediction_end_of_line_popover(
 7599                    "Accept",
 7600                    editor_snapshot,
 7601                    visible_row_range,
 7602                    target_display_point,
 7603                    line_height,
 7604                    scroll_pixel_position,
 7605                    content_origin,
 7606                    editor_width,
 7607                    window,
 7608                    cx,
 7609                )
 7610            }
 7611            InlineCompletion::Edit {
 7612                edits,
 7613                edit_preview,
 7614                display_mode: EditDisplayMode::DiffPopover,
 7615                snapshot,
 7616            } => self.render_edit_prediction_diff_popover(
 7617                text_bounds,
 7618                content_origin,
 7619                right_margin,
 7620                editor_snapshot,
 7621                visible_row_range,
 7622                line_layouts,
 7623                line_height,
 7624                scroll_pixel_position,
 7625                newest_selection_head,
 7626                editor_width,
 7627                style,
 7628                edits,
 7629                edit_preview,
 7630                snapshot,
 7631                window,
 7632                cx,
 7633            ),
 7634        }
 7635    }
 7636
 7637    fn render_edit_prediction_modifier_jump_popover(
 7638        &mut self,
 7639        text_bounds: &Bounds<Pixels>,
 7640        content_origin: gpui::Point<Pixels>,
 7641        visible_row_range: Range<DisplayRow>,
 7642        line_layouts: &[LineWithInvisibles],
 7643        line_height: Pixels,
 7644        scroll_pixel_position: gpui::Point<Pixels>,
 7645        newest_selection_head: Option<DisplayPoint>,
 7646        target_display_point: DisplayPoint,
 7647        window: &mut Window,
 7648        cx: &mut App,
 7649    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7650        let scrolled_content_origin =
 7651            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7652
 7653        const SCROLL_PADDING_Y: Pixels = px(12.);
 7654
 7655        if target_display_point.row() < visible_row_range.start {
 7656            return self.render_edit_prediction_scroll_popover(
 7657                |_| SCROLL_PADDING_Y,
 7658                IconName::ArrowUp,
 7659                visible_row_range,
 7660                line_layouts,
 7661                newest_selection_head,
 7662                scrolled_content_origin,
 7663                window,
 7664                cx,
 7665            );
 7666        } else if target_display_point.row() >= visible_row_range.end {
 7667            return self.render_edit_prediction_scroll_popover(
 7668                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7669                IconName::ArrowDown,
 7670                visible_row_range,
 7671                line_layouts,
 7672                newest_selection_head,
 7673                scrolled_content_origin,
 7674                window,
 7675                cx,
 7676            );
 7677        }
 7678
 7679        const POLE_WIDTH: Pixels = px(2.);
 7680
 7681        let line_layout =
 7682            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7683        let target_column = target_display_point.column() as usize;
 7684
 7685        let target_x = line_layout.x_for_index(target_column);
 7686        let target_y =
 7687            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7688
 7689        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7690
 7691        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7692        border_color.l += 0.001;
 7693
 7694        let mut element = v_flex()
 7695            .items_end()
 7696            .when(flag_on_right, |el| el.items_start())
 7697            .child(if flag_on_right {
 7698                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7699                    .rounded_bl(px(0.))
 7700                    .rounded_tl(px(0.))
 7701                    .border_l_2()
 7702                    .border_color(border_color)
 7703            } else {
 7704                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7705                    .rounded_br(px(0.))
 7706                    .rounded_tr(px(0.))
 7707                    .border_r_2()
 7708                    .border_color(border_color)
 7709            })
 7710            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7711            .into_any();
 7712
 7713        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7714
 7715        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7716            - point(
 7717                if flag_on_right {
 7718                    POLE_WIDTH
 7719                } else {
 7720                    size.width - POLE_WIDTH
 7721                },
 7722                size.height - line_height,
 7723            );
 7724
 7725        origin.x = origin.x.max(content_origin.x);
 7726
 7727        element.prepaint_at(origin, window, cx);
 7728
 7729        Some((element, origin))
 7730    }
 7731
 7732    fn render_edit_prediction_scroll_popover(
 7733        &mut self,
 7734        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7735        scroll_icon: IconName,
 7736        visible_row_range: Range<DisplayRow>,
 7737        line_layouts: &[LineWithInvisibles],
 7738        newest_selection_head: Option<DisplayPoint>,
 7739        scrolled_content_origin: gpui::Point<Pixels>,
 7740        window: &mut Window,
 7741        cx: &mut App,
 7742    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7743        let mut element = self
 7744            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7745            .into_any();
 7746
 7747        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7748
 7749        let cursor = newest_selection_head?;
 7750        let cursor_row_layout =
 7751            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7752        let cursor_column = cursor.column() as usize;
 7753
 7754        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7755
 7756        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7757
 7758        element.prepaint_at(origin, window, cx);
 7759        Some((element, origin))
 7760    }
 7761
 7762    fn render_edit_prediction_eager_jump_popover(
 7763        &mut self,
 7764        text_bounds: &Bounds<Pixels>,
 7765        content_origin: gpui::Point<Pixels>,
 7766        editor_snapshot: &EditorSnapshot,
 7767        visible_row_range: Range<DisplayRow>,
 7768        scroll_top: f32,
 7769        scroll_bottom: f32,
 7770        line_height: Pixels,
 7771        scroll_pixel_position: gpui::Point<Pixels>,
 7772        target_display_point: DisplayPoint,
 7773        editor_width: Pixels,
 7774        window: &mut Window,
 7775        cx: &mut App,
 7776    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7777        if target_display_point.row().as_f32() < scroll_top {
 7778            let mut element = self
 7779                .render_edit_prediction_line_popover(
 7780                    "Jump to Edit",
 7781                    Some(IconName::ArrowUp),
 7782                    window,
 7783                    cx,
 7784                )?
 7785                .into_any();
 7786
 7787            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7788            let offset = point(
 7789                (text_bounds.size.width - size.width) / 2.,
 7790                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7791            );
 7792
 7793            let origin = text_bounds.origin + offset;
 7794            element.prepaint_at(origin, window, cx);
 7795            Some((element, origin))
 7796        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7797            let mut element = self
 7798                .render_edit_prediction_line_popover(
 7799                    "Jump to Edit",
 7800                    Some(IconName::ArrowDown),
 7801                    window,
 7802                    cx,
 7803                )?
 7804                .into_any();
 7805
 7806            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7807            let offset = point(
 7808                (text_bounds.size.width - size.width) / 2.,
 7809                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7810            );
 7811
 7812            let origin = text_bounds.origin + offset;
 7813            element.prepaint_at(origin, window, cx);
 7814            Some((element, origin))
 7815        } else {
 7816            self.render_edit_prediction_end_of_line_popover(
 7817                "Jump to Edit",
 7818                editor_snapshot,
 7819                visible_row_range,
 7820                target_display_point,
 7821                line_height,
 7822                scroll_pixel_position,
 7823                content_origin,
 7824                editor_width,
 7825                window,
 7826                cx,
 7827            )
 7828        }
 7829    }
 7830
 7831    fn render_edit_prediction_end_of_line_popover(
 7832        self: &mut Editor,
 7833        label: &'static str,
 7834        editor_snapshot: &EditorSnapshot,
 7835        visible_row_range: Range<DisplayRow>,
 7836        target_display_point: DisplayPoint,
 7837        line_height: Pixels,
 7838        scroll_pixel_position: gpui::Point<Pixels>,
 7839        content_origin: gpui::Point<Pixels>,
 7840        editor_width: Pixels,
 7841        window: &mut Window,
 7842        cx: &mut App,
 7843    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7844        let target_line_end = DisplayPoint::new(
 7845            target_display_point.row(),
 7846            editor_snapshot.line_len(target_display_point.row()),
 7847        );
 7848
 7849        let mut element = self
 7850            .render_edit_prediction_line_popover(label, None, window, cx)?
 7851            .into_any();
 7852
 7853        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7854
 7855        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7856
 7857        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7858        let mut origin = start_point
 7859            + line_origin
 7860            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7861        origin.x = origin.x.max(content_origin.x);
 7862
 7863        let max_x = content_origin.x + editor_width - size.width;
 7864
 7865        if origin.x > max_x {
 7866            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7867
 7868            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7869                origin.y += offset;
 7870                IconName::ArrowUp
 7871            } else {
 7872                origin.y -= offset;
 7873                IconName::ArrowDown
 7874            };
 7875
 7876            element = self
 7877                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7878                .into_any();
 7879
 7880            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7881
 7882            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7883        }
 7884
 7885        element.prepaint_at(origin, window, cx);
 7886        Some((element, origin))
 7887    }
 7888
 7889    fn render_edit_prediction_diff_popover(
 7890        self: &Editor,
 7891        text_bounds: &Bounds<Pixels>,
 7892        content_origin: gpui::Point<Pixels>,
 7893        right_margin: Pixels,
 7894        editor_snapshot: &EditorSnapshot,
 7895        visible_row_range: Range<DisplayRow>,
 7896        line_layouts: &[LineWithInvisibles],
 7897        line_height: Pixels,
 7898        scroll_pixel_position: gpui::Point<Pixels>,
 7899        newest_selection_head: Option<DisplayPoint>,
 7900        editor_width: Pixels,
 7901        style: &EditorStyle,
 7902        edits: &Vec<(Range<Anchor>, String)>,
 7903        edit_preview: &Option<language::EditPreview>,
 7904        snapshot: &language::BufferSnapshot,
 7905        window: &mut Window,
 7906        cx: &mut App,
 7907    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7908        let edit_start = edits
 7909            .first()
 7910            .unwrap()
 7911            .0
 7912            .start
 7913            .to_display_point(editor_snapshot);
 7914        let edit_end = edits
 7915            .last()
 7916            .unwrap()
 7917            .0
 7918            .end
 7919            .to_display_point(editor_snapshot);
 7920
 7921        let is_visible = visible_row_range.contains(&edit_start.row())
 7922            || visible_row_range.contains(&edit_end.row());
 7923        if !is_visible {
 7924            return None;
 7925        }
 7926
 7927        let highlighted_edits =
 7928            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7929
 7930        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7931        let line_count = highlighted_edits.text.lines().count();
 7932
 7933        const BORDER_WIDTH: Pixels = px(1.);
 7934
 7935        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7936        let has_keybind = keybind.is_some();
 7937
 7938        let mut element = h_flex()
 7939            .items_start()
 7940            .child(
 7941                h_flex()
 7942                    .bg(cx.theme().colors().editor_background)
 7943                    .border(BORDER_WIDTH)
 7944                    .shadow_sm()
 7945                    .border_color(cx.theme().colors().border)
 7946                    .rounded_l_lg()
 7947                    .when(line_count > 1, |el| el.rounded_br_lg())
 7948                    .pr_1()
 7949                    .child(styled_text),
 7950            )
 7951            .child(
 7952                h_flex()
 7953                    .h(line_height + BORDER_WIDTH * 2.)
 7954                    .px_1p5()
 7955                    .gap_1()
 7956                    // Workaround: For some reason, there's a gap if we don't do this
 7957                    .ml(-BORDER_WIDTH)
 7958                    .shadow(smallvec![gpui::BoxShadow {
 7959                        color: gpui::black().opacity(0.05),
 7960                        offset: point(px(1.), px(1.)),
 7961                        blur_radius: px(2.),
 7962                        spread_radius: px(0.),
 7963                    }])
 7964                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7965                    .border(BORDER_WIDTH)
 7966                    .border_color(cx.theme().colors().border)
 7967                    .rounded_r_lg()
 7968                    .id("edit_prediction_diff_popover_keybind")
 7969                    .when(!has_keybind, |el| {
 7970                        let status_colors = cx.theme().status();
 7971
 7972                        el.bg(status_colors.error_background)
 7973                            .border_color(status_colors.error.opacity(0.6))
 7974                            .child(Icon::new(IconName::Info).color(Color::Error))
 7975                            .cursor_default()
 7976                            .hoverable_tooltip(move |_window, cx| {
 7977                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7978                            })
 7979                    })
 7980                    .children(keybind),
 7981            )
 7982            .into_any();
 7983
 7984        let longest_row =
 7985            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 7986        let longest_line_width = if visible_row_range.contains(&longest_row) {
 7987            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 7988        } else {
 7989            layout_line(
 7990                longest_row,
 7991                editor_snapshot,
 7992                style,
 7993                editor_width,
 7994                |_| false,
 7995                window,
 7996                cx,
 7997            )
 7998            .width
 7999        };
 8000
 8001        let viewport_bounds =
 8002            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8003                right: -right_margin,
 8004                ..Default::default()
 8005            });
 8006
 8007        let x_after_longest =
 8008            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8009                - scroll_pixel_position.x;
 8010
 8011        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8012
 8013        // Fully visible if it can be displayed within the window (allow overlapping other
 8014        // panes). However, this is only allowed if the popover starts within text_bounds.
 8015        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8016            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8017
 8018        let mut origin = if can_position_to_the_right {
 8019            point(
 8020                x_after_longest,
 8021                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8022                    - scroll_pixel_position.y,
 8023            )
 8024        } else {
 8025            let cursor_row = newest_selection_head.map(|head| head.row());
 8026            let above_edit = edit_start
 8027                .row()
 8028                .0
 8029                .checked_sub(line_count as u32)
 8030                .map(DisplayRow);
 8031            let below_edit = Some(edit_end.row() + 1);
 8032            let above_cursor =
 8033                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8034            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8035
 8036            // Place the edit popover adjacent to the edit if there is a location
 8037            // available that is onscreen and does not obscure the cursor. Otherwise,
 8038            // place it adjacent to the cursor.
 8039            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8040                .into_iter()
 8041                .flatten()
 8042                .find(|&start_row| {
 8043                    let end_row = start_row + line_count as u32;
 8044                    visible_row_range.contains(&start_row)
 8045                        && visible_row_range.contains(&end_row)
 8046                        && cursor_row.map_or(true, |cursor_row| {
 8047                            !((start_row..end_row).contains(&cursor_row))
 8048                        })
 8049                })?;
 8050
 8051            content_origin
 8052                + point(
 8053                    -scroll_pixel_position.x,
 8054                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8055                )
 8056        };
 8057
 8058        origin.x -= BORDER_WIDTH;
 8059
 8060        window.defer_draw(element, origin, 1);
 8061
 8062        // Do not return an element, since it will already be drawn due to defer_draw.
 8063        None
 8064    }
 8065
 8066    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8067        px(30.)
 8068    }
 8069
 8070    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8071        if self.read_only(cx) {
 8072            cx.theme().players().read_only()
 8073        } else {
 8074            self.style.as_ref().unwrap().local_player
 8075        }
 8076    }
 8077
 8078    fn render_edit_prediction_accept_keybind(
 8079        &self,
 8080        window: &mut Window,
 8081        cx: &App,
 8082    ) -> Option<AnyElement> {
 8083        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8084        let accept_keystroke = accept_binding.keystroke()?;
 8085
 8086        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8087
 8088        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8089            Color::Accent
 8090        } else {
 8091            Color::Muted
 8092        };
 8093
 8094        h_flex()
 8095            .px_0p5()
 8096            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8097            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8098            .text_size(TextSize::XSmall.rems(cx))
 8099            .child(h_flex().children(ui::render_modifiers(
 8100                &accept_keystroke.modifiers,
 8101                PlatformStyle::platform(),
 8102                Some(modifiers_color),
 8103                Some(IconSize::XSmall.rems().into()),
 8104                true,
 8105            )))
 8106            .when(is_platform_style_mac, |parent| {
 8107                parent.child(accept_keystroke.key.clone())
 8108            })
 8109            .when(!is_platform_style_mac, |parent| {
 8110                parent.child(
 8111                    Key::new(
 8112                        util::capitalize(&accept_keystroke.key),
 8113                        Some(Color::Default),
 8114                    )
 8115                    .size(Some(IconSize::XSmall.rems().into())),
 8116                )
 8117            })
 8118            .into_any()
 8119            .into()
 8120    }
 8121
 8122    fn render_edit_prediction_line_popover(
 8123        &self,
 8124        label: impl Into<SharedString>,
 8125        icon: Option<IconName>,
 8126        window: &mut Window,
 8127        cx: &App,
 8128    ) -> Option<Stateful<Div>> {
 8129        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8130
 8131        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8132        let has_keybind = keybind.is_some();
 8133
 8134        let result = h_flex()
 8135            .id("ep-line-popover")
 8136            .py_0p5()
 8137            .pl_1()
 8138            .pr(padding_right)
 8139            .gap_1()
 8140            .rounded_md()
 8141            .border_1()
 8142            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8143            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8144            .shadow_sm()
 8145            .when(!has_keybind, |el| {
 8146                let status_colors = cx.theme().status();
 8147
 8148                el.bg(status_colors.error_background)
 8149                    .border_color(status_colors.error.opacity(0.6))
 8150                    .pl_2()
 8151                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8152                    .cursor_default()
 8153                    .hoverable_tooltip(move |_window, cx| {
 8154                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8155                    })
 8156            })
 8157            .children(keybind)
 8158            .child(
 8159                Label::new(label)
 8160                    .size(LabelSize::Small)
 8161                    .when(!has_keybind, |el| {
 8162                        el.color(cx.theme().status().error.into()).strikethrough()
 8163                    }),
 8164            )
 8165            .when(!has_keybind, |el| {
 8166                el.child(
 8167                    h_flex().ml_1().child(
 8168                        Icon::new(IconName::Info)
 8169                            .size(IconSize::Small)
 8170                            .color(cx.theme().status().error.into()),
 8171                    ),
 8172                )
 8173            })
 8174            .when_some(icon, |element, icon| {
 8175                element.child(
 8176                    div()
 8177                        .mt(px(1.5))
 8178                        .child(Icon::new(icon).size(IconSize::Small)),
 8179                )
 8180            });
 8181
 8182        Some(result)
 8183    }
 8184
 8185    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8186        let accent_color = cx.theme().colors().text_accent;
 8187        let editor_bg_color = cx.theme().colors().editor_background;
 8188        editor_bg_color.blend(accent_color.opacity(0.1))
 8189    }
 8190
 8191    fn edit_prediction_callout_popover_border_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.6))
 8195    }
 8196
 8197    fn render_edit_prediction_cursor_popover(
 8198        &self,
 8199        min_width: Pixels,
 8200        max_width: Pixels,
 8201        cursor_point: Point,
 8202        style: &EditorStyle,
 8203        accept_keystroke: Option<&gpui::Keystroke>,
 8204        _window: &Window,
 8205        cx: &mut Context<Editor>,
 8206    ) -> Option<AnyElement> {
 8207        let provider = self.edit_prediction_provider.as_ref()?;
 8208
 8209        if provider.provider.needs_terms_acceptance(cx) {
 8210            return Some(
 8211                h_flex()
 8212                    .min_w(min_width)
 8213                    .flex_1()
 8214                    .px_2()
 8215                    .py_1()
 8216                    .gap_3()
 8217                    .elevation_2(cx)
 8218                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8219                    .id("accept-terms")
 8220                    .cursor_pointer()
 8221                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8222                    .on_click(cx.listener(|this, _event, window, cx| {
 8223                        cx.stop_propagation();
 8224                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8225                        window.dispatch_action(
 8226                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8227                            cx,
 8228                        );
 8229                    }))
 8230                    .child(
 8231                        h_flex()
 8232                            .flex_1()
 8233                            .gap_2()
 8234                            .child(Icon::new(IconName::ZedPredict))
 8235                            .child(Label::new("Accept Terms of Service"))
 8236                            .child(div().w_full())
 8237                            .child(
 8238                                Icon::new(IconName::ArrowUpRight)
 8239                                    .color(Color::Muted)
 8240                                    .size(IconSize::Small),
 8241                            )
 8242                            .into_any_element(),
 8243                    )
 8244                    .into_any(),
 8245            );
 8246        }
 8247
 8248        let is_refreshing = provider.provider.is_refreshing(cx);
 8249
 8250        fn pending_completion_container() -> Div {
 8251            h_flex()
 8252                .h_full()
 8253                .flex_1()
 8254                .gap_2()
 8255                .child(Icon::new(IconName::ZedPredict))
 8256        }
 8257
 8258        let completion = match &self.active_inline_completion {
 8259            Some(prediction) => {
 8260                if !self.has_visible_completions_menu() {
 8261                    const RADIUS: Pixels = px(6.);
 8262                    const BORDER_WIDTH: Pixels = px(1.);
 8263
 8264                    return Some(
 8265                        h_flex()
 8266                            .elevation_2(cx)
 8267                            .border(BORDER_WIDTH)
 8268                            .border_color(cx.theme().colors().border)
 8269                            .when(accept_keystroke.is_none(), |el| {
 8270                                el.border_color(cx.theme().status().error)
 8271                            })
 8272                            .rounded(RADIUS)
 8273                            .rounded_tl(px(0.))
 8274                            .overflow_hidden()
 8275                            .child(div().px_1p5().child(match &prediction.completion {
 8276                                InlineCompletion::Move { target, snapshot } => {
 8277                                    use text::ToPoint as _;
 8278                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8279                                    {
 8280                                        Icon::new(IconName::ZedPredictDown)
 8281                                    } else {
 8282                                        Icon::new(IconName::ZedPredictUp)
 8283                                    }
 8284                                }
 8285                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8286                            }))
 8287                            .child(
 8288                                h_flex()
 8289                                    .gap_1()
 8290                                    .py_1()
 8291                                    .px_2()
 8292                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8293                                    .border_l_1()
 8294                                    .border_color(cx.theme().colors().border)
 8295                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8296                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8297                                        el.child(
 8298                                            Label::new("Hold")
 8299                                                .size(LabelSize::Small)
 8300                                                .when(accept_keystroke.is_none(), |el| {
 8301                                                    el.strikethrough()
 8302                                                })
 8303                                                .line_height_style(LineHeightStyle::UiLabel),
 8304                                        )
 8305                                    })
 8306                                    .id("edit_prediction_cursor_popover_keybind")
 8307                                    .when(accept_keystroke.is_none(), |el| {
 8308                                        let status_colors = cx.theme().status();
 8309
 8310                                        el.bg(status_colors.error_background)
 8311                                            .border_color(status_colors.error.opacity(0.6))
 8312                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8313                                            .cursor_default()
 8314                                            .hoverable_tooltip(move |_window, cx| {
 8315                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8316                                                    .into()
 8317                                            })
 8318                                    })
 8319                                    .when_some(
 8320                                        accept_keystroke.as_ref(),
 8321                                        |el, accept_keystroke| {
 8322                                            el.child(h_flex().children(ui::render_modifiers(
 8323                                                &accept_keystroke.modifiers,
 8324                                                PlatformStyle::platform(),
 8325                                                Some(Color::Default),
 8326                                                Some(IconSize::XSmall.rems().into()),
 8327                                                false,
 8328                                            )))
 8329                                        },
 8330                                    ),
 8331                            )
 8332                            .into_any(),
 8333                    );
 8334                }
 8335
 8336                self.render_edit_prediction_cursor_popover_preview(
 8337                    prediction,
 8338                    cursor_point,
 8339                    style,
 8340                    cx,
 8341                )?
 8342            }
 8343
 8344            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8345                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8346                    stale_completion,
 8347                    cursor_point,
 8348                    style,
 8349                    cx,
 8350                )?,
 8351
 8352                None => {
 8353                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8354                }
 8355            },
 8356
 8357            None => pending_completion_container().child(Label::new("No Prediction")),
 8358        };
 8359
 8360        let completion = if is_refreshing {
 8361            completion
 8362                .with_animation(
 8363                    "loading-completion",
 8364                    Animation::new(Duration::from_secs(2))
 8365                        .repeat()
 8366                        .with_easing(pulsating_between(0.4, 0.8)),
 8367                    |label, delta| label.opacity(delta),
 8368                )
 8369                .into_any_element()
 8370        } else {
 8371            completion.into_any_element()
 8372        };
 8373
 8374        let has_completion = self.active_inline_completion.is_some();
 8375
 8376        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8377        Some(
 8378            h_flex()
 8379                .min_w(min_width)
 8380                .max_w(max_width)
 8381                .flex_1()
 8382                .elevation_2(cx)
 8383                .border_color(cx.theme().colors().border)
 8384                .child(
 8385                    div()
 8386                        .flex_1()
 8387                        .py_1()
 8388                        .px_2()
 8389                        .overflow_hidden()
 8390                        .child(completion),
 8391                )
 8392                .when_some(accept_keystroke, |el, accept_keystroke| {
 8393                    if !accept_keystroke.modifiers.modified() {
 8394                        return el;
 8395                    }
 8396
 8397                    el.child(
 8398                        h_flex()
 8399                            .h_full()
 8400                            .border_l_1()
 8401                            .rounded_r_lg()
 8402                            .border_color(cx.theme().colors().border)
 8403                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8404                            .gap_1()
 8405                            .py_1()
 8406                            .px_2()
 8407                            .child(
 8408                                h_flex()
 8409                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8410                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8411                                    .child(h_flex().children(ui::render_modifiers(
 8412                                        &accept_keystroke.modifiers,
 8413                                        PlatformStyle::platform(),
 8414                                        Some(if !has_completion {
 8415                                            Color::Muted
 8416                                        } else {
 8417                                            Color::Default
 8418                                        }),
 8419                                        None,
 8420                                        false,
 8421                                    ))),
 8422                            )
 8423                            .child(Label::new("Preview").into_any_element())
 8424                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8425                    )
 8426                })
 8427                .into_any(),
 8428        )
 8429    }
 8430
 8431    fn render_edit_prediction_cursor_popover_preview(
 8432        &self,
 8433        completion: &InlineCompletionState,
 8434        cursor_point: Point,
 8435        style: &EditorStyle,
 8436        cx: &mut Context<Editor>,
 8437    ) -> Option<Div> {
 8438        use text::ToPoint as _;
 8439
 8440        fn render_relative_row_jump(
 8441            prefix: impl Into<String>,
 8442            current_row: u32,
 8443            target_row: u32,
 8444        ) -> Div {
 8445            let (row_diff, arrow) = if target_row < current_row {
 8446                (current_row - target_row, IconName::ArrowUp)
 8447            } else {
 8448                (target_row - current_row, IconName::ArrowDown)
 8449            };
 8450
 8451            h_flex()
 8452                .child(
 8453                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8454                        .color(Color::Muted)
 8455                        .size(LabelSize::Small),
 8456                )
 8457                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8458        }
 8459
 8460        match &completion.completion {
 8461            InlineCompletion::Move {
 8462                target, snapshot, ..
 8463            } => Some(
 8464                h_flex()
 8465                    .px_2()
 8466                    .gap_2()
 8467                    .flex_1()
 8468                    .child(
 8469                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8470                            Icon::new(IconName::ZedPredictDown)
 8471                        } else {
 8472                            Icon::new(IconName::ZedPredictUp)
 8473                        },
 8474                    )
 8475                    .child(Label::new("Jump to Edit")),
 8476            ),
 8477
 8478            InlineCompletion::Edit {
 8479                edits,
 8480                edit_preview,
 8481                snapshot,
 8482                display_mode: _,
 8483            } => {
 8484                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8485
 8486                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8487                    &snapshot,
 8488                    &edits,
 8489                    edit_preview.as_ref()?,
 8490                    true,
 8491                    cx,
 8492                )
 8493                .first_line_preview();
 8494
 8495                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8496                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8497
 8498                let preview = h_flex()
 8499                    .gap_1()
 8500                    .min_w_16()
 8501                    .child(styled_text)
 8502                    .when(has_more_lines, |parent| parent.child(""));
 8503
 8504                let left = if first_edit_row != cursor_point.row {
 8505                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8506                        .into_any_element()
 8507                } else {
 8508                    Icon::new(IconName::ZedPredict).into_any_element()
 8509                };
 8510
 8511                Some(
 8512                    h_flex()
 8513                        .h_full()
 8514                        .flex_1()
 8515                        .gap_2()
 8516                        .pr_1()
 8517                        .overflow_x_hidden()
 8518                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8519                        .child(left)
 8520                        .child(preview),
 8521                )
 8522            }
 8523        }
 8524    }
 8525
 8526    fn render_context_menu(
 8527        &self,
 8528        style: &EditorStyle,
 8529        max_height_in_lines: u32,
 8530        window: &mut Window,
 8531        cx: &mut Context<Editor>,
 8532    ) -> Option<AnyElement> {
 8533        let menu = self.context_menu.borrow();
 8534        let menu = menu.as_ref()?;
 8535        if !menu.visible() {
 8536            return None;
 8537        };
 8538        Some(menu.render(style, max_height_in_lines, window, cx))
 8539    }
 8540
 8541    fn render_context_menu_aside(
 8542        &mut self,
 8543        max_size: Size<Pixels>,
 8544        window: &mut Window,
 8545        cx: &mut Context<Editor>,
 8546    ) -> Option<AnyElement> {
 8547        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8548            if menu.visible() {
 8549                menu.render_aside(self, max_size, window, cx)
 8550            } else {
 8551                None
 8552            }
 8553        })
 8554    }
 8555
 8556    fn hide_context_menu(
 8557        &mut self,
 8558        window: &mut Window,
 8559        cx: &mut Context<Self>,
 8560    ) -> Option<CodeContextMenu> {
 8561        cx.notify();
 8562        self.completion_tasks.clear();
 8563        let context_menu = self.context_menu.borrow_mut().take();
 8564        self.stale_inline_completion_in_menu.take();
 8565        self.update_visible_inline_completion(window, cx);
 8566        context_menu
 8567    }
 8568
 8569    fn show_snippet_choices(
 8570        &mut self,
 8571        choices: &Vec<String>,
 8572        selection: Range<Anchor>,
 8573        cx: &mut Context<Self>,
 8574    ) {
 8575        if selection.start.buffer_id.is_none() {
 8576            return;
 8577        }
 8578        let buffer_id = selection.start.buffer_id.unwrap();
 8579        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8580        let id = post_inc(&mut self.next_completion_id);
 8581        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8582
 8583        if let Some(buffer) = buffer {
 8584            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8585                CompletionsMenu::new_snippet_choices(
 8586                    id,
 8587                    true,
 8588                    choices,
 8589                    selection,
 8590                    buffer,
 8591                    snippet_sort_order,
 8592                ),
 8593            ));
 8594        }
 8595    }
 8596
 8597    pub fn insert_snippet(
 8598        &mut self,
 8599        insertion_ranges: &[Range<usize>],
 8600        snippet: Snippet,
 8601        window: &mut Window,
 8602        cx: &mut Context<Self>,
 8603    ) -> Result<()> {
 8604        struct Tabstop<T> {
 8605            is_end_tabstop: bool,
 8606            ranges: Vec<Range<T>>,
 8607            choices: Option<Vec<String>>,
 8608        }
 8609
 8610        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8611            let snippet_text: Arc<str> = snippet.text.clone().into();
 8612            let edits = insertion_ranges
 8613                .iter()
 8614                .cloned()
 8615                .map(|range| (range, snippet_text.clone()));
 8616            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8617
 8618            let snapshot = &*buffer.read(cx);
 8619            let snippet = &snippet;
 8620            snippet
 8621                .tabstops
 8622                .iter()
 8623                .map(|tabstop| {
 8624                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8625                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8626                    });
 8627                    let mut tabstop_ranges = tabstop
 8628                        .ranges
 8629                        .iter()
 8630                        .flat_map(|tabstop_range| {
 8631                            let mut delta = 0_isize;
 8632                            insertion_ranges.iter().map(move |insertion_range| {
 8633                                let insertion_start = insertion_range.start as isize + delta;
 8634                                delta +=
 8635                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8636
 8637                                let start = ((insertion_start + tabstop_range.start) as usize)
 8638                                    .min(snapshot.len());
 8639                                let end = ((insertion_start + tabstop_range.end) as usize)
 8640                                    .min(snapshot.len());
 8641                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8642                            })
 8643                        })
 8644                        .collect::<Vec<_>>();
 8645                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8646
 8647                    Tabstop {
 8648                        is_end_tabstop,
 8649                        ranges: tabstop_ranges,
 8650                        choices: tabstop.choices.clone(),
 8651                    }
 8652                })
 8653                .collect::<Vec<_>>()
 8654        });
 8655        if let Some(tabstop) = tabstops.first() {
 8656            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8657                s.select_ranges(tabstop.ranges.iter().cloned());
 8658            });
 8659
 8660            if let Some(choices) = &tabstop.choices {
 8661                if let Some(selection) = tabstop.ranges.first() {
 8662                    self.show_snippet_choices(choices, selection.clone(), cx)
 8663                }
 8664            }
 8665
 8666            // If we're already at the last tabstop and it's at the end of the snippet,
 8667            // we're done, we don't need to keep the state around.
 8668            if !tabstop.is_end_tabstop {
 8669                let choices = tabstops
 8670                    .iter()
 8671                    .map(|tabstop| tabstop.choices.clone())
 8672                    .collect();
 8673
 8674                let ranges = tabstops
 8675                    .into_iter()
 8676                    .map(|tabstop| tabstop.ranges)
 8677                    .collect::<Vec<_>>();
 8678
 8679                self.snippet_stack.push(SnippetState {
 8680                    active_index: 0,
 8681                    ranges,
 8682                    choices,
 8683                });
 8684            }
 8685
 8686            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8687            if self.autoclose_regions.is_empty() {
 8688                let snapshot = self.buffer.read(cx).snapshot(cx);
 8689                for selection in &mut self.selections.all::<Point>(cx) {
 8690                    let selection_head = selection.head();
 8691                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8692                        continue;
 8693                    };
 8694
 8695                    let mut bracket_pair = None;
 8696                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8697                    let prev_chars = snapshot
 8698                        .reversed_chars_at(selection_head)
 8699                        .collect::<String>();
 8700                    for (pair, enabled) in scope.brackets() {
 8701                        if enabled
 8702                            && pair.close
 8703                            && prev_chars.starts_with(pair.start.as_str())
 8704                            && next_chars.starts_with(pair.end.as_str())
 8705                        {
 8706                            bracket_pair = Some(pair.clone());
 8707                            break;
 8708                        }
 8709                    }
 8710                    if let Some(pair) = bracket_pair {
 8711                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8712                        let autoclose_enabled =
 8713                            self.use_autoclose && snapshot_settings.use_autoclose;
 8714                        if autoclose_enabled {
 8715                            let start = snapshot.anchor_after(selection_head);
 8716                            let end = snapshot.anchor_after(selection_head);
 8717                            self.autoclose_regions.push(AutocloseRegion {
 8718                                selection_id: selection.id,
 8719                                range: start..end,
 8720                                pair,
 8721                            });
 8722                        }
 8723                    }
 8724                }
 8725            }
 8726        }
 8727        Ok(())
 8728    }
 8729
 8730    pub fn move_to_next_snippet_tabstop(
 8731        &mut self,
 8732        window: &mut Window,
 8733        cx: &mut Context<Self>,
 8734    ) -> bool {
 8735        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8736    }
 8737
 8738    pub fn move_to_prev_snippet_tabstop(
 8739        &mut self,
 8740        window: &mut Window,
 8741        cx: &mut Context<Self>,
 8742    ) -> bool {
 8743        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8744    }
 8745
 8746    pub fn move_to_snippet_tabstop(
 8747        &mut self,
 8748        bias: Bias,
 8749        window: &mut Window,
 8750        cx: &mut Context<Self>,
 8751    ) -> bool {
 8752        if let Some(mut snippet) = self.snippet_stack.pop() {
 8753            match bias {
 8754                Bias::Left => {
 8755                    if snippet.active_index > 0 {
 8756                        snippet.active_index -= 1;
 8757                    } else {
 8758                        self.snippet_stack.push(snippet);
 8759                        return false;
 8760                    }
 8761                }
 8762                Bias::Right => {
 8763                    if snippet.active_index + 1 < snippet.ranges.len() {
 8764                        snippet.active_index += 1;
 8765                    } else {
 8766                        self.snippet_stack.push(snippet);
 8767                        return false;
 8768                    }
 8769                }
 8770            }
 8771            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8772                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8773                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8774                });
 8775
 8776                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8777                    if let Some(selection) = current_ranges.first() {
 8778                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8779                    }
 8780                }
 8781
 8782                // If snippet state is not at the last tabstop, push it back on the stack
 8783                if snippet.active_index + 1 < snippet.ranges.len() {
 8784                    self.snippet_stack.push(snippet);
 8785                }
 8786                return true;
 8787            }
 8788        }
 8789
 8790        false
 8791    }
 8792
 8793    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8794        self.transact(window, cx, |this, window, cx| {
 8795            this.select_all(&SelectAll, window, cx);
 8796            this.insert("", window, cx);
 8797        });
 8798    }
 8799
 8800    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8801        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8802        self.transact(window, cx, |this, window, cx| {
 8803            this.select_autoclose_pair(window, cx);
 8804            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8805            if !this.linked_edit_ranges.is_empty() {
 8806                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8807                let snapshot = this.buffer.read(cx).snapshot(cx);
 8808
 8809                for selection in selections.iter() {
 8810                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8811                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8812                    if selection_start.buffer_id != selection_end.buffer_id {
 8813                        continue;
 8814                    }
 8815                    if let Some(ranges) =
 8816                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8817                    {
 8818                        for (buffer, entries) in ranges {
 8819                            linked_ranges.entry(buffer).or_default().extend(entries);
 8820                        }
 8821                    }
 8822                }
 8823            }
 8824
 8825            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8826            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8827            for selection in &mut selections {
 8828                if selection.is_empty() {
 8829                    let old_head = selection.head();
 8830                    let mut new_head =
 8831                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8832                            .to_point(&display_map);
 8833                    if let Some((buffer, line_buffer_range)) = display_map
 8834                        .buffer_snapshot
 8835                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8836                    {
 8837                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8838                        let indent_len = match indent_size.kind {
 8839                            IndentKind::Space => {
 8840                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8841                            }
 8842                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8843                        };
 8844                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8845                            let indent_len = indent_len.get();
 8846                            new_head = cmp::min(
 8847                                new_head,
 8848                                MultiBufferPoint::new(
 8849                                    old_head.row,
 8850                                    ((old_head.column - 1) / indent_len) * indent_len,
 8851                                ),
 8852                            );
 8853                        }
 8854                    }
 8855
 8856                    selection.set_head(new_head, SelectionGoal::None);
 8857                }
 8858            }
 8859
 8860            this.signature_help_state.set_backspace_pressed(true);
 8861            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8862                s.select(selections)
 8863            });
 8864            this.insert("", window, cx);
 8865            let empty_str: Arc<str> = Arc::from("");
 8866            for (buffer, edits) in linked_ranges {
 8867                let snapshot = buffer.read(cx).snapshot();
 8868                use text::ToPoint as TP;
 8869
 8870                let edits = edits
 8871                    .into_iter()
 8872                    .map(|range| {
 8873                        let end_point = TP::to_point(&range.end, &snapshot);
 8874                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8875
 8876                        if end_point == start_point {
 8877                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8878                                .saturating_sub(1);
 8879                            start_point =
 8880                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8881                        };
 8882
 8883                        (start_point..end_point, empty_str.clone())
 8884                    })
 8885                    .sorted_by_key(|(range, _)| range.start)
 8886                    .collect::<Vec<_>>();
 8887                buffer.update(cx, |this, cx| {
 8888                    this.edit(edits, None, cx);
 8889                })
 8890            }
 8891            this.refresh_inline_completion(true, false, window, cx);
 8892            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8893        });
 8894    }
 8895
 8896    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8897        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8898        self.transact(window, cx, |this, window, cx| {
 8899            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8900                s.move_with(|map, selection| {
 8901                    if selection.is_empty() {
 8902                        let cursor = movement::right(map, selection.head());
 8903                        selection.end = cursor;
 8904                        selection.reversed = true;
 8905                        selection.goal = SelectionGoal::None;
 8906                    }
 8907                })
 8908            });
 8909            this.insert("", window, cx);
 8910            this.refresh_inline_completion(true, false, window, cx);
 8911        });
 8912    }
 8913
 8914    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8915        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8916        if self.move_to_prev_snippet_tabstop(window, cx) {
 8917            return;
 8918        }
 8919        self.outdent(&Outdent, window, cx);
 8920    }
 8921
 8922    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8923        if self.move_to_next_snippet_tabstop(window, cx) {
 8924            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8925            return;
 8926        }
 8927        if self.read_only(cx) {
 8928            return;
 8929        }
 8930        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8931        let mut selections = self.selections.all_adjusted(cx);
 8932        let buffer = self.buffer.read(cx);
 8933        let snapshot = buffer.snapshot(cx);
 8934        let rows_iter = selections.iter().map(|s| s.head().row);
 8935        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8936
 8937        let has_some_cursor_in_whitespace = selections
 8938            .iter()
 8939            .filter(|selection| selection.is_empty())
 8940            .any(|selection| {
 8941                let cursor = selection.head();
 8942                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8943                cursor.column < current_indent.len
 8944            });
 8945
 8946        let mut edits = Vec::new();
 8947        let mut prev_edited_row = 0;
 8948        let mut row_delta = 0;
 8949        for selection in &mut selections {
 8950            if selection.start.row != prev_edited_row {
 8951                row_delta = 0;
 8952            }
 8953            prev_edited_row = selection.end.row;
 8954
 8955            // If the selection is non-empty, then increase the indentation of the selected lines.
 8956            if !selection.is_empty() {
 8957                row_delta =
 8958                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8959                continue;
 8960            }
 8961
 8962            let cursor = selection.head();
 8963            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8964            if let Some(suggested_indent) =
 8965                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8966            {
 8967                // Don't do anything if already at suggested indent
 8968                // and there is any other cursor which is not
 8969                if has_some_cursor_in_whitespace
 8970                    && cursor.column == current_indent.len
 8971                    && current_indent.len == suggested_indent.len
 8972                {
 8973                    continue;
 8974                }
 8975
 8976                // Adjust line and move cursor to suggested indent
 8977                // if cursor is not at suggested indent
 8978                if cursor.column < suggested_indent.len
 8979                    && cursor.column <= current_indent.len
 8980                    && current_indent.len <= suggested_indent.len
 8981                {
 8982                    selection.start = Point::new(cursor.row, suggested_indent.len);
 8983                    selection.end = selection.start;
 8984                    if row_delta == 0 {
 8985                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 8986                            cursor.row,
 8987                            current_indent,
 8988                            suggested_indent,
 8989                        ));
 8990                        row_delta = suggested_indent.len - current_indent.len;
 8991                    }
 8992                    continue;
 8993                }
 8994
 8995                // If current indent is more than suggested indent
 8996                // only move cursor to current indent and skip indent
 8997                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 8998                    selection.start = Point::new(cursor.row, current_indent.len);
 8999                    selection.end = selection.start;
 9000                    continue;
 9001                }
 9002            }
 9003
 9004            // Otherwise, insert a hard or soft tab.
 9005            let settings = buffer.language_settings_at(cursor, cx);
 9006            let tab_size = if settings.hard_tabs {
 9007                IndentSize::tab()
 9008            } else {
 9009                let tab_size = settings.tab_size.get();
 9010                let indent_remainder = snapshot
 9011                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9012                    .flat_map(str::chars)
 9013                    .fold(row_delta % tab_size, |counter: u32, c| {
 9014                        if c == '\t' {
 9015                            0
 9016                        } else {
 9017                            (counter + 1) % tab_size
 9018                        }
 9019                    });
 9020
 9021                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9022                IndentSize::spaces(chars_to_next_tab_stop)
 9023            };
 9024            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9025            selection.end = selection.start;
 9026            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9027            row_delta += tab_size.len;
 9028        }
 9029
 9030        self.transact(window, cx, |this, window, cx| {
 9031            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9032            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9033                s.select(selections)
 9034            });
 9035            this.refresh_inline_completion(true, false, window, cx);
 9036        });
 9037    }
 9038
 9039    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9040        if self.read_only(cx) {
 9041            return;
 9042        }
 9043        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9044        let mut selections = self.selections.all::<Point>(cx);
 9045        let mut prev_edited_row = 0;
 9046        let mut row_delta = 0;
 9047        let mut edits = Vec::new();
 9048        let buffer = self.buffer.read(cx);
 9049        let snapshot = buffer.snapshot(cx);
 9050        for selection in &mut selections {
 9051            if selection.start.row != prev_edited_row {
 9052                row_delta = 0;
 9053            }
 9054            prev_edited_row = selection.end.row;
 9055
 9056            row_delta =
 9057                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9058        }
 9059
 9060        self.transact(window, cx, |this, window, cx| {
 9061            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9062            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9063                s.select(selections)
 9064            });
 9065        });
 9066    }
 9067
 9068    fn indent_selection(
 9069        buffer: &MultiBuffer,
 9070        snapshot: &MultiBufferSnapshot,
 9071        selection: &mut Selection<Point>,
 9072        edits: &mut Vec<(Range<Point>, String)>,
 9073        delta_for_start_row: u32,
 9074        cx: &App,
 9075    ) -> u32 {
 9076        let settings = buffer.language_settings_at(selection.start, cx);
 9077        let tab_size = settings.tab_size.get();
 9078        let indent_kind = if settings.hard_tabs {
 9079            IndentKind::Tab
 9080        } else {
 9081            IndentKind::Space
 9082        };
 9083        let mut start_row = selection.start.row;
 9084        let mut end_row = selection.end.row + 1;
 9085
 9086        // If a selection ends at the beginning of a line, don't indent
 9087        // that last line.
 9088        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9089            end_row -= 1;
 9090        }
 9091
 9092        // Avoid re-indenting a row that has already been indented by a
 9093        // previous selection, but still update this selection's column
 9094        // to reflect that indentation.
 9095        if delta_for_start_row > 0 {
 9096            start_row += 1;
 9097            selection.start.column += delta_for_start_row;
 9098            if selection.end.row == selection.start.row {
 9099                selection.end.column += delta_for_start_row;
 9100            }
 9101        }
 9102
 9103        let mut delta_for_end_row = 0;
 9104        let has_multiple_rows = start_row + 1 != end_row;
 9105        for row in start_row..end_row {
 9106            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9107            let indent_delta = match (current_indent.kind, indent_kind) {
 9108                (IndentKind::Space, IndentKind::Space) => {
 9109                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9110                    IndentSize::spaces(columns_to_next_tab_stop)
 9111                }
 9112                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9113                (_, IndentKind::Tab) => IndentSize::tab(),
 9114            };
 9115
 9116            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9117                0
 9118            } else {
 9119                selection.start.column
 9120            };
 9121            let row_start = Point::new(row, start);
 9122            edits.push((
 9123                row_start..row_start,
 9124                indent_delta.chars().collect::<String>(),
 9125            ));
 9126
 9127            // Update this selection's endpoints to reflect the indentation.
 9128            if row == selection.start.row {
 9129                selection.start.column += indent_delta.len;
 9130            }
 9131            if row == selection.end.row {
 9132                selection.end.column += indent_delta.len;
 9133                delta_for_end_row = indent_delta.len;
 9134            }
 9135        }
 9136
 9137        if selection.start.row == selection.end.row {
 9138            delta_for_start_row + delta_for_end_row
 9139        } else {
 9140            delta_for_end_row
 9141        }
 9142    }
 9143
 9144    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9145        if self.read_only(cx) {
 9146            return;
 9147        }
 9148        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9149        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9150        let selections = self.selections.all::<Point>(cx);
 9151        let mut deletion_ranges = Vec::new();
 9152        let mut last_outdent = None;
 9153        {
 9154            let buffer = self.buffer.read(cx);
 9155            let snapshot = buffer.snapshot(cx);
 9156            for selection in &selections {
 9157                let settings = buffer.language_settings_at(selection.start, cx);
 9158                let tab_size = settings.tab_size.get();
 9159                let mut rows = selection.spanned_rows(false, &display_map);
 9160
 9161                // Avoid re-outdenting a row that has already been outdented by a
 9162                // previous selection.
 9163                if let Some(last_row) = last_outdent {
 9164                    if last_row == rows.start {
 9165                        rows.start = rows.start.next_row();
 9166                    }
 9167                }
 9168                let has_multiple_rows = rows.len() > 1;
 9169                for row in rows.iter_rows() {
 9170                    let indent_size = snapshot.indent_size_for_line(row);
 9171                    if indent_size.len > 0 {
 9172                        let deletion_len = match indent_size.kind {
 9173                            IndentKind::Space => {
 9174                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9175                                if columns_to_prev_tab_stop == 0 {
 9176                                    tab_size
 9177                                } else {
 9178                                    columns_to_prev_tab_stop
 9179                                }
 9180                            }
 9181                            IndentKind::Tab => 1,
 9182                        };
 9183                        let start = if has_multiple_rows
 9184                            || deletion_len > selection.start.column
 9185                            || indent_size.len < selection.start.column
 9186                        {
 9187                            0
 9188                        } else {
 9189                            selection.start.column - deletion_len
 9190                        };
 9191                        deletion_ranges.push(
 9192                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9193                        );
 9194                        last_outdent = Some(row);
 9195                    }
 9196                }
 9197            }
 9198        }
 9199
 9200        self.transact(window, cx, |this, window, cx| {
 9201            this.buffer.update(cx, |buffer, cx| {
 9202                let empty_str: Arc<str> = Arc::default();
 9203                buffer.edit(
 9204                    deletion_ranges
 9205                        .into_iter()
 9206                        .map(|range| (range, empty_str.clone())),
 9207                    None,
 9208                    cx,
 9209                );
 9210            });
 9211            let selections = this.selections.all::<usize>(cx);
 9212            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9213                s.select(selections)
 9214            });
 9215        });
 9216    }
 9217
 9218    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9219        if self.read_only(cx) {
 9220            return;
 9221        }
 9222        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9223        let selections = self
 9224            .selections
 9225            .all::<usize>(cx)
 9226            .into_iter()
 9227            .map(|s| s.range());
 9228
 9229        self.transact(window, cx, |this, window, cx| {
 9230            this.buffer.update(cx, |buffer, cx| {
 9231                buffer.autoindent_ranges(selections, cx);
 9232            });
 9233            let selections = this.selections.all::<usize>(cx);
 9234            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9235                s.select(selections)
 9236            });
 9237        });
 9238    }
 9239
 9240    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9241        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9242        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9243        let selections = self.selections.all::<Point>(cx);
 9244
 9245        let mut new_cursors = Vec::new();
 9246        let mut edit_ranges = Vec::new();
 9247        let mut selections = selections.iter().peekable();
 9248        while let Some(selection) = selections.next() {
 9249            let mut rows = selection.spanned_rows(false, &display_map);
 9250            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9251
 9252            // Accumulate contiguous regions of rows that we want to delete.
 9253            while let Some(next_selection) = selections.peek() {
 9254                let next_rows = next_selection.spanned_rows(false, &display_map);
 9255                if next_rows.start <= rows.end {
 9256                    rows.end = next_rows.end;
 9257                    selections.next().unwrap();
 9258                } else {
 9259                    break;
 9260                }
 9261            }
 9262
 9263            let buffer = &display_map.buffer_snapshot;
 9264            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9265            let edit_end;
 9266            let cursor_buffer_row;
 9267            if buffer.max_point().row >= rows.end.0 {
 9268                // If there's a line after the range, delete the \n from the end of the row range
 9269                // and position the cursor on the next line.
 9270                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9271                cursor_buffer_row = rows.end;
 9272            } else {
 9273                // If there isn't a line after the range, delete the \n from the line before the
 9274                // start of the row range and position the cursor there.
 9275                edit_start = edit_start.saturating_sub(1);
 9276                edit_end = buffer.len();
 9277                cursor_buffer_row = rows.start.previous_row();
 9278            }
 9279
 9280            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9281            *cursor.column_mut() =
 9282                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9283
 9284            new_cursors.push((
 9285                selection.id,
 9286                buffer.anchor_after(cursor.to_point(&display_map)),
 9287            ));
 9288            edit_ranges.push(edit_start..edit_end);
 9289        }
 9290
 9291        self.transact(window, cx, |this, window, cx| {
 9292            let buffer = this.buffer.update(cx, |buffer, cx| {
 9293                let empty_str: Arc<str> = Arc::default();
 9294                buffer.edit(
 9295                    edit_ranges
 9296                        .into_iter()
 9297                        .map(|range| (range, empty_str.clone())),
 9298                    None,
 9299                    cx,
 9300                );
 9301                buffer.snapshot(cx)
 9302            });
 9303            let new_selections = new_cursors
 9304                .into_iter()
 9305                .map(|(id, cursor)| {
 9306                    let cursor = cursor.to_point(&buffer);
 9307                    Selection {
 9308                        id,
 9309                        start: cursor,
 9310                        end: cursor,
 9311                        reversed: false,
 9312                        goal: SelectionGoal::None,
 9313                    }
 9314                })
 9315                .collect();
 9316
 9317            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9318                s.select(new_selections);
 9319            });
 9320        });
 9321    }
 9322
 9323    pub fn join_lines_impl(
 9324        &mut self,
 9325        insert_whitespace: bool,
 9326        window: &mut Window,
 9327        cx: &mut Context<Self>,
 9328    ) {
 9329        if self.read_only(cx) {
 9330            return;
 9331        }
 9332        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9333        for selection in self.selections.all::<Point>(cx) {
 9334            let start = MultiBufferRow(selection.start.row);
 9335            // Treat single line selections as if they include the next line. Otherwise this action
 9336            // would do nothing for single line selections individual cursors.
 9337            let end = if selection.start.row == selection.end.row {
 9338                MultiBufferRow(selection.start.row + 1)
 9339            } else {
 9340                MultiBufferRow(selection.end.row)
 9341            };
 9342
 9343            if let Some(last_row_range) = row_ranges.last_mut() {
 9344                if start <= last_row_range.end {
 9345                    last_row_range.end = end;
 9346                    continue;
 9347                }
 9348            }
 9349            row_ranges.push(start..end);
 9350        }
 9351
 9352        let snapshot = self.buffer.read(cx).snapshot(cx);
 9353        let mut cursor_positions = Vec::new();
 9354        for row_range in &row_ranges {
 9355            let anchor = snapshot.anchor_before(Point::new(
 9356                row_range.end.previous_row().0,
 9357                snapshot.line_len(row_range.end.previous_row()),
 9358            ));
 9359            cursor_positions.push(anchor..anchor);
 9360        }
 9361
 9362        self.transact(window, cx, |this, window, cx| {
 9363            for row_range in row_ranges.into_iter().rev() {
 9364                for row in row_range.iter_rows().rev() {
 9365                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9366                    let next_line_row = row.next_row();
 9367                    let indent = snapshot.indent_size_for_line(next_line_row);
 9368                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9369
 9370                    let replace =
 9371                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9372                            " "
 9373                        } else {
 9374                            ""
 9375                        };
 9376
 9377                    this.buffer.update(cx, |buffer, cx| {
 9378                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9379                    });
 9380                }
 9381            }
 9382
 9383            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9384                s.select_anchor_ranges(cursor_positions)
 9385            });
 9386        });
 9387    }
 9388
 9389    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9390        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9391        self.join_lines_impl(true, window, cx);
 9392    }
 9393
 9394    pub fn sort_lines_case_sensitive(
 9395        &mut self,
 9396        _: &SortLinesCaseSensitive,
 9397        window: &mut Window,
 9398        cx: &mut Context<Self>,
 9399    ) {
 9400        self.manipulate_lines(window, cx, |lines| lines.sort())
 9401    }
 9402
 9403    pub fn sort_lines_case_insensitive(
 9404        &mut self,
 9405        _: &SortLinesCaseInsensitive,
 9406        window: &mut Window,
 9407        cx: &mut Context<Self>,
 9408    ) {
 9409        self.manipulate_lines(window, cx, |lines| {
 9410            lines.sort_by_key(|line| line.to_lowercase())
 9411        })
 9412    }
 9413
 9414    pub fn unique_lines_case_insensitive(
 9415        &mut self,
 9416        _: &UniqueLinesCaseInsensitive,
 9417        window: &mut Window,
 9418        cx: &mut Context<Self>,
 9419    ) {
 9420        self.manipulate_lines(window, cx, |lines| {
 9421            let mut seen = HashSet::default();
 9422            lines.retain(|line| seen.insert(line.to_lowercase()));
 9423        })
 9424    }
 9425
 9426    pub fn unique_lines_case_sensitive(
 9427        &mut self,
 9428        _: &UniqueLinesCaseSensitive,
 9429        window: &mut Window,
 9430        cx: &mut Context<Self>,
 9431    ) {
 9432        self.manipulate_lines(window, cx, |lines| {
 9433            let mut seen = HashSet::default();
 9434            lines.retain(|line| seen.insert(*line));
 9435        })
 9436    }
 9437
 9438    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9439        let Some(project) = self.project.clone() else {
 9440            return;
 9441        };
 9442        self.reload(project, window, cx)
 9443            .detach_and_notify_err(window, cx);
 9444    }
 9445
 9446    pub fn restore_file(
 9447        &mut self,
 9448        _: &::git::RestoreFile,
 9449        window: &mut Window,
 9450        cx: &mut Context<Self>,
 9451    ) {
 9452        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9453        let mut buffer_ids = HashSet::default();
 9454        let snapshot = self.buffer().read(cx).snapshot(cx);
 9455        for selection in self.selections.all::<usize>(cx) {
 9456            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9457        }
 9458
 9459        let buffer = self.buffer().read(cx);
 9460        let ranges = buffer_ids
 9461            .into_iter()
 9462            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9463            .collect::<Vec<_>>();
 9464
 9465        self.restore_hunks_in_ranges(ranges, window, cx);
 9466    }
 9467
 9468    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9469        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9470        let selections = self
 9471            .selections
 9472            .all(cx)
 9473            .into_iter()
 9474            .map(|s| s.range())
 9475            .collect();
 9476        self.restore_hunks_in_ranges(selections, window, cx);
 9477    }
 9478
 9479    pub fn restore_hunks_in_ranges(
 9480        &mut self,
 9481        ranges: Vec<Range<Point>>,
 9482        window: &mut Window,
 9483        cx: &mut Context<Editor>,
 9484    ) {
 9485        let mut revert_changes = HashMap::default();
 9486        let chunk_by = self
 9487            .snapshot(window, cx)
 9488            .hunks_for_ranges(ranges)
 9489            .into_iter()
 9490            .chunk_by(|hunk| hunk.buffer_id);
 9491        for (buffer_id, hunks) in &chunk_by {
 9492            let hunks = hunks.collect::<Vec<_>>();
 9493            for hunk in &hunks {
 9494                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9495            }
 9496            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9497        }
 9498        drop(chunk_by);
 9499        if !revert_changes.is_empty() {
 9500            self.transact(window, cx, |editor, window, cx| {
 9501                editor.restore(revert_changes, window, cx);
 9502            });
 9503        }
 9504    }
 9505
 9506    pub fn open_active_item_in_terminal(
 9507        &mut self,
 9508        _: &OpenInTerminal,
 9509        window: &mut Window,
 9510        cx: &mut Context<Self>,
 9511    ) {
 9512        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9513            let project_path = buffer.read(cx).project_path(cx)?;
 9514            let project = self.project.as_ref()?.read(cx);
 9515            let entry = project.entry_for_path(&project_path, cx)?;
 9516            let parent = match &entry.canonical_path {
 9517                Some(canonical_path) => canonical_path.to_path_buf(),
 9518                None => project.absolute_path(&project_path, cx)?,
 9519            }
 9520            .parent()?
 9521            .to_path_buf();
 9522            Some(parent)
 9523        }) {
 9524            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9525        }
 9526    }
 9527
 9528    fn set_breakpoint_context_menu(
 9529        &mut self,
 9530        display_row: DisplayRow,
 9531        position: Option<Anchor>,
 9532        clicked_point: gpui::Point<Pixels>,
 9533        window: &mut Window,
 9534        cx: &mut Context<Self>,
 9535    ) {
 9536        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9537            return;
 9538        }
 9539        let source = self
 9540            .buffer
 9541            .read(cx)
 9542            .snapshot(cx)
 9543            .anchor_before(Point::new(display_row.0, 0u32));
 9544
 9545        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9546
 9547        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9548            self,
 9549            source,
 9550            clicked_point,
 9551            context_menu,
 9552            window,
 9553            cx,
 9554        );
 9555    }
 9556
 9557    fn add_edit_breakpoint_block(
 9558        &mut self,
 9559        anchor: Anchor,
 9560        breakpoint: &Breakpoint,
 9561        edit_action: BreakpointPromptEditAction,
 9562        window: &mut Window,
 9563        cx: &mut Context<Self>,
 9564    ) {
 9565        let weak_editor = cx.weak_entity();
 9566        let bp_prompt = cx.new(|cx| {
 9567            BreakpointPromptEditor::new(
 9568                weak_editor,
 9569                anchor,
 9570                breakpoint.clone(),
 9571                edit_action,
 9572                window,
 9573                cx,
 9574            )
 9575        });
 9576
 9577        let height = bp_prompt.update(cx, |this, cx| {
 9578            this.prompt
 9579                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9580        });
 9581        let cloned_prompt = bp_prompt.clone();
 9582        let blocks = vec![BlockProperties {
 9583            style: BlockStyle::Sticky,
 9584            placement: BlockPlacement::Above(anchor),
 9585            height: Some(height),
 9586            render: Arc::new(move |cx| {
 9587                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9588                cloned_prompt.clone().into_any_element()
 9589            }),
 9590            priority: 0,
 9591            render_in_minimap: true,
 9592        }];
 9593
 9594        let focus_handle = bp_prompt.focus_handle(cx);
 9595        window.focus(&focus_handle);
 9596
 9597        let block_ids = self.insert_blocks(blocks, None, cx);
 9598        bp_prompt.update(cx, |prompt, _| {
 9599            prompt.add_block_ids(block_ids);
 9600        });
 9601    }
 9602
 9603    pub(crate) fn breakpoint_at_row(
 9604        &self,
 9605        row: u32,
 9606        window: &mut Window,
 9607        cx: &mut Context<Self>,
 9608    ) -> Option<(Anchor, Breakpoint)> {
 9609        let snapshot = self.snapshot(window, cx);
 9610        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9611
 9612        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9613    }
 9614
 9615    pub(crate) fn breakpoint_at_anchor(
 9616        &self,
 9617        breakpoint_position: Anchor,
 9618        snapshot: &EditorSnapshot,
 9619        cx: &mut Context<Self>,
 9620    ) -> Option<(Anchor, Breakpoint)> {
 9621        let project = self.project.clone()?;
 9622
 9623        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9624            snapshot
 9625                .buffer_snapshot
 9626                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9627        })?;
 9628
 9629        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9630        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9631        let buffer_snapshot = buffer.read(cx).snapshot();
 9632
 9633        let row = buffer_snapshot
 9634            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9635            .row;
 9636
 9637        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9638        let anchor_end = snapshot
 9639            .buffer_snapshot
 9640            .anchor_after(Point::new(row, line_len));
 9641
 9642        let bp = self
 9643            .breakpoint_store
 9644            .as_ref()?
 9645            .read_with(cx, |breakpoint_store, cx| {
 9646                breakpoint_store
 9647                    .breakpoints(
 9648                        &buffer,
 9649                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9650                        &buffer_snapshot,
 9651                        cx,
 9652                    )
 9653                    .next()
 9654                    .and_then(|(bp, _)| {
 9655                        let breakpoint_row = buffer_snapshot
 9656                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9657                            .row;
 9658
 9659                        if breakpoint_row == row {
 9660                            snapshot
 9661                                .buffer_snapshot
 9662                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9663                                .map(|position| (position, bp.bp.clone()))
 9664                        } else {
 9665                            None
 9666                        }
 9667                    })
 9668            });
 9669        bp
 9670    }
 9671
 9672    pub fn edit_log_breakpoint(
 9673        &mut self,
 9674        _: &EditLogBreakpoint,
 9675        window: &mut Window,
 9676        cx: &mut Context<Self>,
 9677    ) {
 9678        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9679            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9680                message: None,
 9681                state: BreakpointState::Enabled,
 9682                condition: None,
 9683                hit_condition: None,
 9684            });
 9685
 9686            self.add_edit_breakpoint_block(
 9687                anchor,
 9688                &breakpoint,
 9689                BreakpointPromptEditAction::Log,
 9690                window,
 9691                cx,
 9692            );
 9693        }
 9694    }
 9695
 9696    fn breakpoints_at_cursors(
 9697        &self,
 9698        window: &mut Window,
 9699        cx: &mut Context<Self>,
 9700    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9701        let snapshot = self.snapshot(window, cx);
 9702        let cursors = self
 9703            .selections
 9704            .disjoint_anchors()
 9705            .into_iter()
 9706            .map(|selection| {
 9707                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9708
 9709                let breakpoint_position = self
 9710                    .breakpoint_at_row(cursor_position.row, window, cx)
 9711                    .map(|bp| bp.0)
 9712                    .unwrap_or_else(|| {
 9713                        snapshot
 9714                            .display_snapshot
 9715                            .buffer_snapshot
 9716                            .anchor_after(Point::new(cursor_position.row, 0))
 9717                    });
 9718
 9719                let breakpoint = self
 9720                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9721                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9722
 9723                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9724            })
 9725            // 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.
 9726            .collect::<HashMap<Anchor, _>>();
 9727
 9728        cursors.into_iter().collect()
 9729    }
 9730
 9731    pub fn enable_breakpoint(
 9732        &mut self,
 9733        _: &crate::actions::EnableBreakpoint,
 9734        window: &mut Window,
 9735        cx: &mut Context<Self>,
 9736    ) {
 9737        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9738            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9739                continue;
 9740            };
 9741            self.edit_breakpoint_at_anchor(
 9742                anchor,
 9743                breakpoint,
 9744                BreakpointEditAction::InvertState,
 9745                cx,
 9746            );
 9747        }
 9748    }
 9749
 9750    pub fn disable_breakpoint(
 9751        &mut self,
 9752        _: &crate::actions::DisableBreakpoint,
 9753        window: &mut Window,
 9754        cx: &mut Context<Self>,
 9755    ) {
 9756        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9757            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9758                continue;
 9759            };
 9760            self.edit_breakpoint_at_anchor(
 9761                anchor,
 9762                breakpoint,
 9763                BreakpointEditAction::InvertState,
 9764                cx,
 9765            );
 9766        }
 9767    }
 9768
 9769    pub fn toggle_breakpoint(
 9770        &mut self,
 9771        _: &crate::actions::ToggleBreakpoint,
 9772        window: &mut Window,
 9773        cx: &mut Context<Self>,
 9774    ) {
 9775        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9776            if let Some(breakpoint) = breakpoint {
 9777                self.edit_breakpoint_at_anchor(
 9778                    anchor,
 9779                    breakpoint,
 9780                    BreakpointEditAction::Toggle,
 9781                    cx,
 9782                );
 9783            } else {
 9784                self.edit_breakpoint_at_anchor(
 9785                    anchor,
 9786                    Breakpoint::new_standard(),
 9787                    BreakpointEditAction::Toggle,
 9788                    cx,
 9789                );
 9790            }
 9791        }
 9792    }
 9793
 9794    pub fn edit_breakpoint_at_anchor(
 9795        &mut self,
 9796        breakpoint_position: Anchor,
 9797        breakpoint: Breakpoint,
 9798        edit_action: BreakpointEditAction,
 9799        cx: &mut Context<Self>,
 9800    ) {
 9801        let Some(breakpoint_store) = &self.breakpoint_store else {
 9802            return;
 9803        };
 9804
 9805        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9806            if breakpoint_position == Anchor::min() {
 9807                self.buffer()
 9808                    .read(cx)
 9809                    .excerpt_buffer_ids()
 9810                    .into_iter()
 9811                    .next()
 9812            } else {
 9813                None
 9814            }
 9815        }) else {
 9816            return;
 9817        };
 9818
 9819        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9820            return;
 9821        };
 9822
 9823        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9824            breakpoint_store.toggle_breakpoint(
 9825                buffer,
 9826                BreakpointWithPosition {
 9827                    position: breakpoint_position.text_anchor,
 9828                    bp: breakpoint,
 9829                },
 9830                edit_action,
 9831                cx,
 9832            );
 9833        });
 9834
 9835        cx.notify();
 9836    }
 9837
 9838    #[cfg(any(test, feature = "test-support"))]
 9839    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9840        self.breakpoint_store.clone()
 9841    }
 9842
 9843    pub fn prepare_restore_change(
 9844        &self,
 9845        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9846        hunk: &MultiBufferDiffHunk,
 9847        cx: &mut App,
 9848    ) -> Option<()> {
 9849        if hunk.is_created_file() {
 9850            return None;
 9851        }
 9852        let buffer = self.buffer.read(cx);
 9853        let diff = buffer.diff_for(hunk.buffer_id)?;
 9854        let buffer = buffer.buffer(hunk.buffer_id)?;
 9855        let buffer = buffer.read(cx);
 9856        let original_text = diff
 9857            .read(cx)
 9858            .base_text()
 9859            .as_rope()
 9860            .slice(hunk.diff_base_byte_range.clone());
 9861        let buffer_snapshot = buffer.snapshot();
 9862        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9863        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9864            probe
 9865                .0
 9866                .start
 9867                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9868                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9869        }) {
 9870            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9871            Some(())
 9872        } else {
 9873            None
 9874        }
 9875    }
 9876
 9877    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9878        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9879    }
 9880
 9881    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9882        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9883    }
 9884
 9885    fn manipulate_lines<Fn>(
 9886        &mut self,
 9887        window: &mut Window,
 9888        cx: &mut Context<Self>,
 9889        mut callback: Fn,
 9890    ) where
 9891        Fn: FnMut(&mut Vec<&str>),
 9892    {
 9893        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9894
 9895        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9896        let buffer = self.buffer.read(cx).snapshot(cx);
 9897
 9898        let mut edits = Vec::new();
 9899
 9900        let selections = self.selections.all::<Point>(cx);
 9901        let mut selections = selections.iter().peekable();
 9902        let mut contiguous_row_selections = Vec::new();
 9903        let mut new_selections = Vec::new();
 9904        let mut added_lines = 0;
 9905        let mut removed_lines = 0;
 9906
 9907        while let Some(selection) = selections.next() {
 9908            let (start_row, end_row) = consume_contiguous_rows(
 9909                &mut contiguous_row_selections,
 9910                selection,
 9911                &display_map,
 9912                &mut selections,
 9913            );
 9914
 9915            let start_point = Point::new(start_row.0, 0);
 9916            let end_point = Point::new(
 9917                end_row.previous_row().0,
 9918                buffer.line_len(end_row.previous_row()),
 9919            );
 9920            let text = buffer
 9921                .text_for_range(start_point..end_point)
 9922                .collect::<String>();
 9923
 9924            let mut lines = text.split('\n').collect_vec();
 9925
 9926            let lines_before = lines.len();
 9927            callback(&mut lines);
 9928            let lines_after = lines.len();
 9929
 9930            edits.push((start_point..end_point, lines.join("\n")));
 9931
 9932            // Selections must change based on added and removed line count
 9933            let start_row =
 9934                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9935            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9936            new_selections.push(Selection {
 9937                id: selection.id,
 9938                start: start_row,
 9939                end: end_row,
 9940                goal: SelectionGoal::None,
 9941                reversed: selection.reversed,
 9942            });
 9943
 9944            if lines_after > lines_before {
 9945                added_lines += lines_after - lines_before;
 9946            } else if lines_before > lines_after {
 9947                removed_lines += lines_before - lines_after;
 9948            }
 9949        }
 9950
 9951        self.transact(window, cx, |this, window, cx| {
 9952            let buffer = this.buffer.update(cx, |buffer, cx| {
 9953                buffer.edit(edits, None, cx);
 9954                buffer.snapshot(cx)
 9955            });
 9956
 9957            // Recalculate offsets on newly edited buffer
 9958            let new_selections = new_selections
 9959                .iter()
 9960                .map(|s| {
 9961                    let start_point = Point::new(s.start.0, 0);
 9962                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9963                    Selection {
 9964                        id: s.id,
 9965                        start: buffer.point_to_offset(start_point),
 9966                        end: buffer.point_to_offset(end_point),
 9967                        goal: s.goal,
 9968                        reversed: s.reversed,
 9969                    }
 9970                })
 9971                .collect();
 9972
 9973            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9974                s.select(new_selections);
 9975            });
 9976
 9977            this.request_autoscroll(Autoscroll::fit(), cx);
 9978        });
 9979    }
 9980
 9981    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9982        self.manipulate_text(window, cx, |text| {
 9983            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
 9984            if has_upper_case_characters {
 9985                text.to_lowercase()
 9986            } else {
 9987                text.to_uppercase()
 9988            }
 9989        })
 9990    }
 9991
 9992    pub fn convert_to_upper_case(
 9993        &mut self,
 9994        _: &ConvertToUpperCase,
 9995        window: &mut Window,
 9996        cx: &mut Context<Self>,
 9997    ) {
 9998        self.manipulate_text(window, cx, |text| text.to_uppercase())
 9999    }
10000
10001    pub fn convert_to_lower_case(
10002        &mut self,
10003        _: &ConvertToLowerCase,
10004        window: &mut Window,
10005        cx: &mut Context<Self>,
10006    ) {
10007        self.manipulate_text(window, cx, |text| text.to_lowercase())
10008    }
10009
10010    pub fn convert_to_title_case(
10011        &mut self,
10012        _: &ConvertToTitleCase,
10013        window: &mut Window,
10014        cx: &mut Context<Self>,
10015    ) {
10016        self.manipulate_text(window, cx, |text| {
10017            text.split('\n')
10018                .map(|line| line.to_case(Case::Title))
10019                .join("\n")
10020        })
10021    }
10022
10023    pub fn convert_to_snake_case(
10024        &mut self,
10025        _: &ConvertToSnakeCase,
10026        window: &mut Window,
10027        cx: &mut Context<Self>,
10028    ) {
10029        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10030    }
10031
10032    pub fn convert_to_kebab_case(
10033        &mut self,
10034        _: &ConvertToKebabCase,
10035        window: &mut Window,
10036        cx: &mut Context<Self>,
10037    ) {
10038        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10039    }
10040
10041    pub fn convert_to_upper_camel_case(
10042        &mut self,
10043        _: &ConvertToUpperCamelCase,
10044        window: &mut Window,
10045        cx: &mut Context<Self>,
10046    ) {
10047        self.manipulate_text(window, cx, |text| {
10048            text.split('\n')
10049                .map(|line| line.to_case(Case::UpperCamel))
10050                .join("\n")
10051        })
10052    }
10053
10054    pub fn convert_to_lower_camel_case(
10055        &mut self,
10056        _: &ConvertToLowerCamelCase,
10057        window: &mut Window,
10058        cx: &mut Context<Self>,
10059    ) {
10060        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10061    }
10062
10063    pub fn convert_to_opposite_case(
10064        &mut self,
10065        _: &ConvertToOppositeCase,
10066        window: &mut Window,
10067        cx: &mut Context<Self>,
10068    ) {
10069        self.manipulate_text(window, cx, |text| {
10070            text.chars()
10071                .fold(String::with_capacity(text.len()), |mut t, c| {
10072                    if c.is_uppercase() {
10073                        t.extend(c.to_lowercase());
10074                    } else {
10075                        t.extend(c.to_uppercase());
10076                    }
10077                    t
10078                })
10079        })
10080    }
10081
10082    pub fn convert_to_rot13(
10083        &mut self,
10084        _: &ConvertToRot13,
10085        window: &mut Window,
10086        cx: &mut Context<Self>,
10087    ) {
10088        self.manipulate_text(window, cx, |text| {
10089            text.chars()
10090                .map(|c| match c {
10091                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10092                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10093                    _ => c,
10094                })
10095                .collect()
10096        })
10097    }
10098
10099    pub fn convert_to_rot47(
10100        &mut self,
10101        _: &ConvertToRot47,
10102        window: &mut Window,
10103        cx: &mut Context<Self>,
10104    ) {
10105        self.manipulate_text(window, cx, |text| {
10106            text.chars()
10107                .map(|c| {
10108                    let code_point = c as u32;
10109                    if code_point >= 33 && code_point <= 126 {
10110                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10111                    }
10112                    c
10113                })
10114                .collect()
10115        })
10116    }
10117
10118    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10119    where
10120        Fn: FnMut(&str) -> String,
10121    {
10122        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10123        let buffer = self.buffer.read(cx).snapshot(cx);
10124
10125        let mut new_selections = Vec::new();
10126        let mut edits = Vec::new();
10127        let mut selection_adjustment = 0i32;
10128
10129        for selection in self.selections.all::<usize>(cx) {
10130            let selection_is_empty = selection.is_empty();
10131
10132            let (start, end) = if selection_is_empty {
10133                let word_range = movement::surrounding_word(
10134                    &display_map,
10135                    selection.start.to_display_point(&display_map),
10136                );
10137                let start = word_range.start.to_offset(&display_map, Bias::Left);
10138                let end = word_range.end.to_offset(&display_map, Bias::Left);
10139                (start, end)
10140            } else {
10141                (selection.start, selection.end)
10142            };
10143
10144            let text = buffer.text_for_range(start..end).collect::<String>();
10145            let old_length = text.len() as i32;
10146            let text = callback(&text);
10147
10148            new_selections.push(Selection {
10149                start: (start as i32 - selection_adjustment) as usize,
10150                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10151                goal: SelectionGoal::None,
10152                ..selection
10153            });
10154
10155            selection_adjustment += old_length - text.len() as i32;
10156
10157            edits.push((start..end, text));
10158        }
10159
10160        self.transact(window, cx, |this, window, cx| {
10161            this.buffer.update(cx, |buffer, cx| {
10162                buffer.edit(edits, None, cx);
10163            });
10164
10165            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10166                s.select(new_selections);
10167            });
10168
10169            this.request_autoscroll(Autoscroll::fit(), cx);
10170        });
10171    }
10172
10173    pub fn duplicate(
10174        &mut self,
10175        upwards: bool,
10176        whole_lines: bool,
10177        window: &mut Window,
10178        cx: &mut Context<Self>,
10179    ) {
10180        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10181
10182        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10183        let buffer = &display_map.buffer_snapshot;
10184        let selections = self.selections.all::<Point>(cx);
10185
10186        let mut edits = Vec::new();
10187        let mut selections_iter = selections.iter().peekable();
10188        while let Some(selection) = selections_iter.next() {
10189            let mut rows = selection.spanned_rows(false, &display_map);
10190            // duplicate line-wise
10191            if whole_lines || selection.start == selection.end {
10192                // Avoid duplicating the same lines twice.
10193                while let Some(next_selection) = selections_iter.peek() {
10194                    let next_rows = next_selection.spanned_rows(false, &display_map);
10195                    if next_rows.start < rows.end {
10196                        rows.end = next_rows.end;
10197                        selections_iter.next().unwrap();
10198                    } else {
10199                        break;
10200                    }
10201                }
10202
10203                // Copy the text from the selected row region and splice it either at the start
10204                // or end of the region.
10205                let start = Point::new(rows.start.0, 0);
10206                let end = Point::new(
10207                    rows.end.previous_row().0,
10208                    buffer.line_len(rows.end.previous_row()),
10209                );
10210                let text = buffer
10211                    .text_for_range(start..end)
10212                    .chain(Some("\n"))
10213                    .collect::<String>();
10214                let insert_location = if upwards {
10215                    Point::new(rows.end.0, 0)
10216                } else {
10217                    start
10218                };
10219                edits.push((insert_location..insert_location, text));
10220            } else {
10221                // duplicate character-wise
10222                let start = selection.start;
10223                let end = selection.end;
10224                let text = buffer.text_for_range(start..end).collect::<String>();
10225                edits.push((selection.end..selection.end, text));
10226            }
10227        }
10228
10229        self.transact(window, cx, |this, _, cx| {
10230            this.buffer.update(cx, |buffer, cx| {
10231                buffer.edit(edits, None, cx);
10232            });
10233
10234            this.request_autoscroll(Autoscroll::fit(), cx);
10235        });
10236    }
10237
10238    pub fn duplicate_line_up(
10239        &mut self,
10240        _: &DuplicateLineUp,
10241        window: &mut Window,
10242        cx: &mut Context<Self>,
10243    ) {
10244        self.duplicate(true, true, window, cx);
10245    }
10246
10247    pub fn duplicate_line_down(
10248        &mut self,
10249        _: &DuplicateLineDown,
10250        window: &mut Window,
10251        cx: &mut Context<Self>,
10252    ) {
10253        self.duplicate(false, true, window, cx);
10254    }
10255
10256    pub fn duplicate_selection(
10257        &mut self,
10258        _: &DuplicateSelection,
10259        window: &mut Window,
10260        cx: &mut Context<Self>,
10261    ) {
10262        self.duplicate(false, false, window, cx);
10263    }
10264
10265    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10266        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10267
10268        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10269        let buffer = self.buffer.read(cx).snapshot(cx);
10270
10271        let mut edits = Vec::new();
10272        let mut unfold_ranges = Vec::new();
10273        let mut refold_creases = Vec::new();
10274
10275        let selections = self.selections.all::<Point>(cx);
10276        let mut selections = selections.iter().peekable();
10277        let mut contiguous_row_selections = Vec::new();
10278        let mut new_selections = Vec::new();
10279
10280        while let Some(selection) = selections.next() {
10281            // Find all the selections that span a contiguous row range
10282            let (start_row, end_row) = consume_contiguous_rows(
10283                &mut contiguous_row_selections,
10284                selection,
10285                &display_map,
10286                &mut selections,
10287            );
10288
10289            // Move the text spanned by the row range to be before the line preceding the row range
10290            if start_row.0 > 0 {
10291                let range_to_move = Point::new(
10292                    start_row.previous_row().0,
10293                    buffer.line_len(start_row.previous_row()),
10294                )
10295                    ..Point::new(
10296                        end_row.previous_row().0,
10297                        buffer.line_len(end_row.previous_row()),
10298                    );
10299                let insertion_point = display_map
10300                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10301                    .0;
10302
10303                // Don't move lines across excerpts
10304                if buffer
10305                    .excerpt_containing(insertion_point..range_to_move.end)
10306                    .is_some()
10307                {
10308                    let text = buffer
10309                        .text_for_range(range_to_move.clone())
10310                        .flat_map(|s| s.chars())
10311                        .skip(1)
10312                        .chain(['\n'])
10313                        .collect::<String>();
10314
10315                    edits.push((
10316                        buffer.anchor_after(range_to_move.start)
10317                            ..buffer.anchor_before(range_to_move.end),
10318                        String::new(),
10319                    ));
10320                    let insertion_anchor = buffer.anchor_after(insertion_point);
10321                    edits.push((insertion_anchor..insertion_anchor, text));
10322
10323                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10324
10325                    // Move selections up
10326                    new_selections.extend(contiguous_row_selections.drain(..).map(
10327                        |mut selection| {
10328                            selection.start.row -= row_delta;
10329                            selection.end.row -= row_delta;
10330                            selection
10331                        },
10332                    ));
10333
10334                    // Move folds up
10335                    unfold_ranges.push(range_to_move.clone());
10336                    for fold in display_map.folds_in_range(
10337                        buffer.anchor_before(range_to_move.start)
10338                            ..buffer.anchor_after(range_to_move.end),
10339                    ) {
10340                        let mut start = fold.range.start.to_point(&buffer);
10341                        let mut end = fold.range.end.to_point(&buffer);
10342                        start.row -= row_delta;
10343                        end.row -= row_delta;
10344                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10345                    }
10346                }
10347            }
10348
10349            // If we didn't move line(s), preserve the existing selections
10350            new_selections.append(&mut contiguous_row_selections);
10351        }
10352
10353        self.transact(window, cx, |this, window, cx| {
10354            this.unfold_ranges(&unfold_ranges, true, true, cx);
10355            this.buffer.update(cx, |buffer, cx| {
10356                for (range, text) in edits {
10357                    buffer.edit([(range, text)], None, cx);
10358                }
10359            });
10360            this.fold_creases(refold_creases, true, window, cx);
10361            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10362                s.select(new_selections);
10363            })
10364        });
10365    }
10366
10367    pub fn move_line_down(
10368        &mut self,
10369        _: &MoveLineDown,
10370        window: &mut Window,
10371        cx: &mut Context<Self>,
10372    ) {
10373        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10374
10375        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10376        let buffer = self.buffer.read(cx).snapshot(cx);
10377
10378        let mut edits = Vec::new();
10379        let mut unfold_ranges = Vec::new();
10380        let mut refold_creases = Vec::new();
10381
10382        let selections = self.selections.all::<Point>(cx);
10383        let mut selections = selections.iter().peekable();
10384        let mut contiguous_row_selections = Vec::new();
10385        let mut new_selections = Vec::new();
10386
10387        while let Some(selection) = selections.next() {
10388            // Find all the selections that span a contiguous row range
10389            let (start_row, end_row) = consume_contiguous_rows(
10390                &mut contiguous_row_selections,
10391                selection,
10392                &display_map,
10393                &mut selections,
10394            );
10395
10396            // Move the text spanned by the row range to be after the last line of the row range
10397            if end_row.0 <= buffer.max_point().row {
10398                let range_to_move =
10399                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10400                let insertion_point = display_map
10401                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10402                    .0;
10403
10404                // Don't move lines across excerpt boundaries
10405                if buffer
10406                    .excerpt_containing(range_to_move.start..insertion_point)
10407                    .is_some()
10408                {
10409                    let mut text = String::from("\n");
10410                    text.extend(buffer.text_for_range(range_to_move.clone()));
10411                    text.pop(); // Drop trailing newline
10412                    edits.push((
10413                        buffer.anchor_after(range_to_move.start)
10414                            ..buffer.anchor_before(range_to_move.end),
10415                        String::new(),
10416                    ));
10417                    let insertion_anchor = buffer.anchor_after(insertion_point);
10418                    edits.push((insertion_anchor..insertion_anchor, text));
10419
10420                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10421
10422                    // Move selections down
10423                    new_selections.extend(contiguous_row_selections.drain(..).map(
10424                        |mut selection| {
10425                            selection.start.row += row_delta;
10426                            selection.end.row += row_delta;
10427                            selection
10428                        },
10429                    ));
10430
10431                    // Move folds down
10432                    unfold_ranges.push(range_to_move.clone());
10433                    for fold in display_map.folds_in_range(
10434                        buffer.anchor_before(range_to_move.start)
10435                            ..buffer.anchor_after(range_to_move.end),
10436                    ) {
10437                        let mut start = fold.range.start.to_point(&buffer);
10438                        let mut end = fold.range.end.to_point(&buffer);
10439                        start.row += row_delta;
10440                        end.row += row_delta;
10441                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10442                    }
10443                }
10444            }
10445
10446            // If we didn't move line(s), preserve the existing selections
10447            new_selections.append(&mut contiguous_row_selections);
10448        }
10449
10450        self.transact(window, cx, |this, window, cx| {
10451            this.unfold_ranges(&unfold_ranges, true, true, cx);
10452            this.buffer.update(cx, |buffer, cx| {
10453                for (range, text) in edits {
10454                    buffer.edit([(range, text)], None, cx);
10455                }
10456            });
10457            this.fold_creases(refold_creases, true, window, cx);
10458            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10459                s.select(new_selections)
10460            });
10461        });
10462    }
10463
10464    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10465        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10466        let text_layout_details = &self.text_layout_details(window);
10467        self.transact(window, cx, |this, window, cx| {
10468            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10469                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10470                s.move_with(|display_map, selection| {
10471                    if !selection.is_empty() {
10472                        return;
10473                    }
10474
10475                    let mut head = selection.head();
10476                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10477                    if head.column() == display_map.line_len(head.row()) {
10478                        transpose_offset = display_map
10479                            .buffer_snapshot
10480                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10481                    }
10482
10483                    if transpose_offset == 0 {
10484                        return;
10485                    }
10486
10487                    *head.column_mut() += 1;
10488                    head = display_map.clip_point(head, Bias::Right);
10489                    let goal = SelectionGoal::HorizontalPosition(
10490                        display_map
10491                            .x_for_display_point(head, text_layout_details)
10492                            .into(),
10493                    );
10494                    selection.collapse_to(head, goal);
10495
10496                    let transpose_start = display_map
10497                        .buffer_snapshot
10498                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10499                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10500                        let transpose_end = display_map
10501                            .buffer_snapshot
10502                            .clip_offset(transpose_offset + 1, Bias::Right);
10503                        if let Some(ch) =
10504                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10505                        {
10506                            edits.push((transpose_start..transpose_offset, String::new()));
10507                            edits.push((transpose_end..transpose_end, ch.to_string()));
10508                        }
10509                    }
10510                });
10511                edits
10512            });
10513            this.buffer
10514                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10515            let selections = this.selections.all::<usize>(cx);
10516            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10517                s.select(selections);
10518            });
10519        });
10520    }
10521
10522    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10523        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10524        self.rewrap_impl(RewrapOptions::default(), cx)
10525    }
10526
10527    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10528        let buffer = self.buffer.read(cx).snapshot(cx);
10529        let selections = self.selections.all::<Point>(cx);
10530        let mut selections = selections.iter().peekable();
10531
10532        let mut edits = Vec::new();
10533        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10534
10535        while let Some(selection) = selections.next() {
10536            let mut start_row = selection.start.row;
10537            let mut end_row = selection.end.row;
10538
10539            // Skip selections that overlap with a range that has already been rewrapped.
10540            let selection_range = start_row..end_row;
10541            if rewrapped_row_ranges
10542                .iter()
10543                .any(|range| range.overlaps(&selection_range))
10544            {
10545                continue;
10546            }
10547
10548            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10549
10550            // Since not all lines in the selection may be at the same indent
10551            // level, choose the indent size that is the most common between all
10552            // of the lines.
10553            //
10554            // If there is a tie, we use the deepest indent.
10555            let (indent_size, indent_end) = {
10556                let mut indent_size_occurrences = HashMap::default();
10557                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10558
10559                for row in start_row..=end_row {
10560                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10561                    rows_by_indent_size.entry(indent).or_default().push(row);
10562                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10563                }
10564
10565                let indent_size = indent_size_occurrences
10566                    .into_iter()
10567                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10568                    .map(|(indent, _)| indent)
10569                    .unwrap_or_default();
10570                let row = rows_by_indent_size[&indent_size][0];
10571                let indent_end = Point::new(row, indent_size.len);
10572
10573                (indent_size, indent_end)
10574            };
10575
10576            let mut line_prefix = indent_size.chars().collect::<String>();
10577
10578            let mut inside_comment = false;
10579            if let Some(comment_prefix) =
10580                buffer
10581                    .language_scope_at(selection.head())
10582                    .and_then(|language| {
10583                        language
10584                            .line_comment_prefixes()
10585                            .iter()
10586                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10587                            .cloned()
10588                    })
10589            {
10590                line_prefix.push_str(&comment_prefix);
10591                inside_comment = true;
10592            }
10593
10594            let language_settings = buffer.language_settings_at(selection.head(), cx);
10595            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10596                RewrapBehavior::InComments => inside_comment,
10597                RewrapBehavior::InSelections => !selection.is_empty(),
10598                RewrapBehavior::Anywhere => true,
10599            };
10600
10601            let should_rewrap = options.override_language_settings
10602                || allow_rewrap_based_on_language
10603                || self.hard_wrap.is_some();
10604            if !should_rewrap {
10605                continue;
10606            }
10607
10608            if selection.is_empty() {
10609                'expand_upwards: while start_row > 0 {
10610                    let prev_row = start_row - 1;
10611                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10612                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10613                    {
10614                        start_row = prev_row;
10615                    } else {
10616                        break 'expand_upwards;
10617                    }
10618                }
10619
10620                'expand_downwards: while end_row < buffer.max_point().row {
10621                    let next_row = end_row + 1;
10622                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10623                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10624                    {
10625                        end_row = next_row;
10626                    } else {
10627                        break 'expand_downwards;
10628                    }
10629                }
10630            }
10631
10632            let start = Point::new(start_row, 0);
10633            let start_offset = start.to_offset(&buffer);
10634            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10635            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10636            let Some(lines_without_prefixes) = selection_text
10637                .lines()
10638                .map(|line| {
10639                    line.strip_prefix(&line_prefix)
10640                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10641                        .with_context(|| {
10642                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10643                        })
10644                })
10645                .collect::<Result<Vec<_>, _>>()
10646                .log_err()
10647            else {
10648                continue;
10649            };
10650
10651            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10652                buffer
10653                    .language_settings_at(Point::new(start_row, 0), cx)
10654                    .preferred_line_length as usize
10655            });
10656            let wrapped_text = wrap_with_prefix(
10657                line_prefix,
10658                lines_without_prefixes.join("\n"),
10659                wrap_column,
10660                tab_size,
10661                options.preserve_existing_whitespace,
10662            );
10663
10664            // TODO: should always use char-based diff while still supporting cursor behavior that
10665            // matches vim.
10666            let mut diff_options = DiffOptions::default();
10667            if options.override_language_settings {
10668                diff_options.max_word_diff_len = 0;
10669                diff_options.max_word_diff_line_count = 0;
10670            } else {
10671                diff_options.max_word_diff_len = usize::MAX;
10672                diff_options.max_word_diff_line_count = usize::MAX;
10673            }
10674
10675            for (old_range, new_text) in
10676                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10677            {
10678                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10679                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10680                edits.push((edit_start..edit_end, new_text));
10681            }
10682
10683            rewrapped_row_ranges.push(start_row..=end_row);
10684        }
10685
10686        self.buffer
10687            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10688    }
10689
10690    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10691        let mut text = String::new();
10692        let buffer = self.buffer.read(cx).snapshot(cx);
10693        let mut selections = self.selections.all::<Point>(cx);
10694        let mut clipboard_selections = Vec::with_capacity(selections.len());
10695        {
10696            let max_point = buffer.max_point();
10697            let mut is_first = true;
10698            for selection in &mut selections {
10699                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10700                if is_entire_line {
10701                    selection.start = Point::new(selection.start.row, 0);
10702                    if !selection.is_empty() && selection.end.column == 0 {
10703                        selection.end = cmp::min(max_point, selection.end);
10704                    } else {
10705                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10706                    }
10707                    selection.goal = SelectionGoal::None;
10708                }
10709                if is_first {
10710                    is_first = false;
10711                } else {
10712                    text += "\n";
10713                }
10714                let mut len = 0;
10715                for chunk in buffer.text_for_range(selection.start..selection.end) {
10716                    text.push_str(chunk);
10717                    len += chunk.len();
10718                }
10719                clipboard_selections.push(ClipboardSelection {
10720                    len,
10721                    is_entire_line,
10722                    first_line_indent: buffer
10723                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10724                        .len,
10725                });
10726            }
10727        }
10728
10729        self.transact(window, cx, |this, window, cx| {
10730            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10731                s.select(selections);
10732            });
10733            this.insert("", window, cx);
10734        });
10735        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10736    }
10737
10738    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10739        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10740        let item = self.cut_common(window, cx);
10741        cx.write_to_clipboard(item);
10742    }
10743
10744    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10745        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10746        self.change_selections(None, window, cx, |s| {
10747            s.move_with(|snapshot, sel| {
10748                if sel.is_empty() {
10749                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10750                }
10751            });
10752        });
10753        let item = self.cut_common(window, cx);
10754        cx.set_global(KillRing(item))
10755    }
10756
10757    pub fn kill_ring_yank(
10758        &mut self,
10759        _: &KillRingYank,
10760        window: &mut Window,
10761        cx: &mut Context<Self>,
10762    ) {
10763        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10764        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10765            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10766                (kill_ring.text().to_string(), kill_ring.metadata_json())
10767            } else {
10768                return;
10769            }
10770        } else {
10771            return;
10772        };
10773        self.do_paste(&text, metadata, false, window, cx);
10774    }
10775
10776    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10777        self.do_copy(true, cx);
10778    }
10779
10780    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10781        self.do_copy(false, cx);
10782    }
10783
10784    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10785        let selections = self.selections.all::<Point>(cx);
10786        let buffer = self.buffer.read(cx).read(cx);
10787        let mut text = String::new();
10788
10789        let mut clipboard_selections = Vec::with_capacity(selections.len());
10790        {
10791            let max_point = buffer.max_point();
10792            let mut is_first = true;
10793            for selection in &selections {
10794                let mut start = selection.start;
10795                let mut end = selection.end;
10796                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10797                if is_entire_line {
10798                    start = Point::new(start.row, 0);
10799                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10800                }
10801
10802                let mut trimmed_selections = Vec::new();
10803                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10804                    let row = MultiBufferRow(start.row);
10805                    let first_indent = buffer.indent_size_for_line(row);
10806                    if first_indent.len == 0 || start.column > first_indent.len {
10807                        trimmed_selections.push(start..end);
10808                    } else {
10809                        trimmed_selections.push(
10810                            Point::new(row.0, first_indent.len)
10811                                ..Point::new(row.0, buffer.line_len(row)),
10812                        );
10813                        for row in start.row + 1..=end.row {
10814                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10815                            if row == end.row {
10816                                line_len = end.column;
10817                            }
10818                            if line_len == 0 {
10819                                trimmed_selections
10820                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10821                                continue;
10822                            }
10823                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10824                            if row_indent_size.len >= first_indent.len {
10825                                trimmed_selections.push(
10826                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10827                                );
10828                            } else {
10829                                trimmed_selections.clear();
10830                                trimmed_selections.push(start..end);
10831                                break;
10832                            }
10833                        }
10834                    }
10835                } else {
10836                    trimmed_selections.push(start..end);
10837                }
10838
10839                for trimmed_range in trimmed_selections {
10840                    if is_first {
10841                        is_first = false;
10842                    } else {
10843                        text += "\n";
10844                    }
10845                    let mut len = 0;
10846                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10847                        text.push_str(chunk);
10848                        len += chunk.len();
10849                    }
10850                    clipboard_selections.push(ClipboardSelection {
10851                        len,
10852                        is_entire_line,
10853                        first_line_indent: buffer
10854                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10855                            .len,
10856                    });
10857                }
10858            }
10859        }
10860
10861        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10862            text,
10863            clipboard_selections,
10864        ));
10865    }
10866
10867    pub fn do_paste(
10868        &mut self,
10869        text: &String,
10870        clipboard_selections: Option<Vec<ClipboardSelection>>,
10871        handle_entire_lines: bool,
10872        window: &mut Window,
10873        cx: &mut Context<Self>,
10874    ) {
10875        if self.read_only(cx) {
10876            return;
10877        }
10878
10879        let clipboard_text = Cow::Borrowed(text);
10880
10881        self.transact(window, cx, |this, window, cx| {
10882            if let Some(mut clipboard_selections) = clipboard_selections {
10883                let old_selections = this.selections.all::<usize>(cx);
10884                let all_selections_were_entire_line =
10885                    clipboard_selections.iter().all(|s| s.is_entire_line);
10886                let first_selection_indent_column =
10887                    clipboard_selections.first().map(|s| s.first_line_indent);
10888                if clipboard_selections.len() != old_selections.len() {
10889                    clipboard_selections.drain(..);
10890                }
10891                let cursor_offset = this.selections.last::<usize>(cx).head();
10892                let mut auto_indent_on_paste = true;
10893
10894                this.buffer.update(cx, |buffer, cx| {
10895                    let snapshot = buffer.read(cx);
10896                    auto_indent_on_paste = snapshot
10897                        .language_settings_at(cursor_offset, cx)
10898                        .auto_indent_on_paste;
10899
10900                    let mut start_offset = 0;
10901                    let mut edits = Vec::new();
10902                    let mut original_indent_columns = Vec::new();
10903                    for (ix, selection) in old_selections.iter().enumerate() {
10904                        let to_insert;
10905                        let entire_line;
10906                        let original_indent_column;
10907                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10908                            let end_offset = start_offset + clipboard_selection.len;
10909                            to_insert = &clipboard_text[start_offset..end_offset];
10910                            entire_line = clipboard_selection.is_entire_line;
10911                            start_offset = end_offset + 1;
10912                            original_indent_column = Some(clipboard_selection.first_line_indent);
10913                        } else {
10914                            to_insert = clipboard_text.as_str();
10915                            entire_line = all_selections_were_entire_line;
10916                            original_indent_column = first_selection_indent_column
10917                        }
10918
10919                        // If the corresponding selection was empty when this slice of the
10920                        // clipboard text was written, then the entire line containing the
10921                        // selection was copied. If this selection is also currently empty,
10922                        // then paste the line before the current line of the buffer.
10923                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10924                            let column = selection.start.to_point(&snapshot).column as usize;
10925                            let line_start = selection.start - column;
10926                            line_start..line_start
10927                        } else {
10928                            selection.range()
10929                        };
10930
10931                        edits.push((range, to_insert));
10932                        original_indent_columns.push(original_indent_column);
10933                    }
10934                    drop(snapshot);
10935
10936                    buffer.edit(
10937                        edits,
10938                        if auto_indent_on_paste {
10939                            Some(AutoindentMode::Block {
10940                                original_indent_columns,
10941                            })
10942                        } else {
10943                            None
10944                        },
10945                        cx,
10946                    );
10947                });
10948
10949                let selections = this.selections.all::<usize>(cx);
10950                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10951                    s.select(selections)
10952                });
10953            } else {
10954                this.insert(&clipboard_text, window, cx);
10955            }
10956        });
10957    }
10958
10959    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10960        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10961        if let Some(item) = cx.read_from_clipboard() {
10962            let entries = item.entries();
10963
10964            match entries.first() {
10965                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10966                // of all the pasted entries.
10967                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10968                    .do_paste(
10969                        clipboard_string.text(),
10970                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10971                        true,
10972                        window,
10973                        cx,
10974                    ),
10975                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10976            }
10977        }
10978    }
10979
10980    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10981        if self.read_only(cx) {
10982            return;
10983        }
10984
10985        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10986
10987        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
10988            if let Some((selections, _)) =
10989                self.selection_history.transaction(transaction_id).cloned()
10990            {
10991                self.change_selections(None, window, cx, |s| {
10992                    s.select_anchors(selections.to_vec());
10993                });
10994            } else {
10995                log::error!(
10996                    "No entry in selection_history found for undo. \
10997                     This may correspond to a bug where undo does not update the selection. \
10998                     If this is occurring, please add details to \
10999                     https://github.com/zed-industries/zed/issues/22692"
11000                );
11001            }
11002            self.request_autoscroll(Autoscroll::fit(), cx);
11003            self.unmark_text(window, cx);
11004            self.refresh_inline_completion(true, false, window, cx);
11005            cx.emit(EditorEvent::Edited { transaction_id });
11006            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11007        }
11008    }
11009
11010    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11011        if self.read_only(cx) {
11012            return;
11013        }
11014
11015        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11016
11017        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11018            if let Some((_, Some(selections))) =
11019                self.selection_history.transaction(transaction_id).cloned()
11020            {
11021                self.change_selections(None, window, cx, |s| {
11022                    s.select_anchors(selections.to_vec());
11023                });
11024            } else {
11025                log::error!(
11026                    "No entry in selection_history found for redo. \
11027                     This may correspond to a bug where undo does not update the selection. \
11028                     If this is occurring, please add details to \
11029                     https://github.com/zed-industries/zed/issues/22692"
11030                );
11031            }
11032            self.request_autoscroll(Autoscroll::fit(), cx);
11033            self.unmark_text(window, cx);
11034            self.refresh_inline_completion(true, false, window, cx);
11035            cx.emit(EditorEvent::Edited { transaction_id });
11036        }
11037    }
11038
11039    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11040        self.buffer
11041            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11042    }
11043
11044    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11045        self.buffer
11046            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11047    }
11048
11049    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11050        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11051        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11052            s.move_with(|map, selection| {
11053                let cursor = if selection.is_empty() {
11054                    movement::left(map, selection.start)
11055                } else {
11056                    selection.start
11057                };
11058                selection.collapse_to(cursor, SelectionGoal::None);
11059            });
11060        })
11061    }
11062
11063    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11064        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11065        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11066            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11067        })
11068    }
11069
11070    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11071        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11072        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11073            s.move_with(|map, selection| {
11074                let cursor = if selection.is_empty() {
11075                    movement::right(map, selection.end)
11076                } else {
11077                    selection.end
11078                };
11079                selection.collapse_to(cursor, SelectionGoal::None)
11080            });
11081        })
11082    }
11083
11084    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11085        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11086        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11087            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11088        })
11089    }
11090
11091    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11092        if self.take_rename(true, window, cx).is_some() {
11093            return;
11094        }
11095
11096        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11097            cx.propagate();
11098            return;
11099        }
11100
11101        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11102
11103        let text_layout_details = &self.text_layout_details(window);
11104        let selection_count = self.selections.count();
11105        let first_selection = self.selections.first_anchor();
11106
11107        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11108            s.move_with(|map, selection| {
11109                if !selection.is_empty() {
11110                    selection.goal = SelectionGoal::None;
11111                }
11112                let (cursor, goal) = movement::up(
11113                    map,
11114                    selection.start,
11115                    selection.goal,
11116                    false,
11117                    text_layout_details,
11118                );
11119                selection.collapse_to(cursor, goal);
11120            });
11121        });
11122
11123        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11124        {
11125            cx.propagate();
11126        }
11127    }
11128
11129    pub fn move_up_by_lines(
11130        &mut self,
11131        action: &MoveUpByLines,
11132        window: &mut Window,
11133        cx: &mut Context<Self>,
11134    ) {
11135        if self.take_rename(true, window, cx).is_some() {
11136            return;
11137        }
11138
11139        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11140            cx.propagate();
11141            return;
11142        }
11143
11144        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11145
11146        let text_layout_details = &self.text_layout_details(window);
11147
11148        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11149            s.move_with(|map, selection| {
11150                if !selection.is_empty() {
11151                    selection.goal = SelectionGoal::None;
11152                }
11153                let (cursor, goal) = movement::up_by_rows(
11154                    map,
11155                    selection.start,
11156                    action.lines,
11157                    selection.goal,
11158                    false,
11159                    text_layout_details,
11160                );
11161                selection.collapse_to(cursor, goal);
11162            });
11163        })
11164    }
11165
11166    pub fn move_down_by_lines(
11167        &mut self,
11168        action: &MoveDownByLines,
11169        window: &mut Window,
11170        cx: &mut Context<Self>,
11171    ) {
11172        if self.take_rename(true, window, cx).is_some() {
11173            return;
11174        }
11175
11176        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11177            cx.propagate();
11178            return;
11179        }
11180
11181        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11182
11183        let text_layout_details = &self.text_layout_details(window);
11184
11185        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11186            s.move_with(|map, selection| {
11187                if !selection.is_empty() {
11188                    selection.goal = SelectionGoal::None;
11189                }
11190                let (cursor, goal) = movement::down_by_rows(
11191                    map,
11192                    selection.start,
11193                    action.lines,
11194                    selection.goal,
11195                    false,
11196                    text_layout_details,
11197                );
11198                selection.collapse_to(cursor, goal);
11199            });
11200        })
11201    }
11202
11203    pub fn select_down_by_lines(
11204        &mut self,
11205        action: &SelectDownByLines,
11206        window: &mut Window,
11207        cx: &mut Context<Self>,
11208    ) {
11209        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11210        let text_layout_details = &self.text_layout_details(window);
11211        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11212            s.move_heads_with(|map, head, goal| {
11213                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11214            })
11215        })
11216    }
11217
11218    pub fn select_up_by_lines(
11219        &mut self,
11220        action: &SelectUpByLines,
11221        window: &mut Window,
11222        cx: &mut Context<Self>,
11223    ) {
11224        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11225        let text_layout_details = &self.text_layout_details(window);
11226        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11227            s.move_heads_with(|map, head, goal| {
11228                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11229            })
11230        })
11231    }
11232
11233    pub fn select_page_up(
11234        &mut self,
11235        _: &SelectPageUp,
11236        window: &mut Window,
11237        cx: &mut Context<Self>,
11238    ) {
11239        let Some(row_count) = self.visible_row_count() else {
11240            return;
11241        };
11242
11243        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11244
11245        let text_layout_details = &self.text_layout_details(window);
11246
11247        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11248            s.move_heads_with(|map, head, goal| {
11249                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11250            })
11251        })
11252    }
11253
11254    pub fn move_page_up(
11255        &mut self,
11256        action: &MovePageUp,
11257        window: &mut Window,
11258        cx: &mut Context<Self>,
11259    ) {
11260        if self.take_rename(true, window, cx).is_some() {
11261            return;
11262        }
11263
11264        if self
11265            .context_menu
11266            .borrow_mut()
11267            .as_mut()
11268            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11269            .unwrap_or(false)
11270        {
11271            return;
11272        }
11273
11274        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11275            cx.propagate();
11276            return;
11277        }
11278
11279        let Some(row_count) = self.visible_row_count() else {
11280            return;
11281        };
11282
11283        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11284
11285        let autoscroll = if action.center_cursor {
11286            Autoscroll::center()
11287        } else {
11288            Autoscroll::fit()
11289        };
11290
11291        let text_layout_details = &self.text_layout_details(window);
11292
11293        self.change_selections(Some(autoscroll), window, cx, |s| {
11294            s.move_with(|map, selection| {
11295                if !selection.is_empty() {
11296                    selection.goal = SelectionGoal::None;
11297                }
11298                let (cursor, goal) = movement::up_by_rows(
11299                    map,
11300                    selection.end,
11301                    row_count,
11302                    selection.goal,
11303                    false,
11304                    text_layout_details,
11305                );
11306                selection.collapse_to(cursor, goal);
11307            });
11308        });
11309    }
11310
11311    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11312        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11313        let text_layout_details = &self.text_layout_details(window);
11314        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11315            s.move_heads_with(|map, head, goal| {
11316                movement::up(map, head, goal, false, text_layout_details)
11317            })
11318        })
11319    }
11320
11321    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11322        self.take_rename(true, window, cx);
11323
11324        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11325            cx.propagate();
11326            return;
11327        }
11328
11329        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11330
11331        let text_layout_details = &self.text_layout_details(window);
11332        let selection_count = self.selections.count();
11333        let first_selection = self.selections.first_anchor();
11334
11335        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11336            s.move_with(|map, selection| {
11337                if !selection.is_empty() {
11338                    selection.goal = SelectionGoal::None;
11339                }
11340                let (cursor, goal) = movement::down(
11341                    map,
11342                    selection.end,
11343                    selection.goal,
11344                    false,
11345                    text_layout_details,
11346                );
11347                selection.collapse_to(cursor, goal);
11348            });
11349        });
11350
11351        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11352        {
11353            cx.propagate();
11354        }
11355    }
11356
11357    pub fn select_page_down(
11358        &mut self,
11359        _: &SelectPageDown,
11360        window: &mut Window,
11361        cx: &mut Context<Self>,
11362    ) {
11363        let Some(row_count) = self.visible_row_count() else {
11364            return;
11365        };
11366
11367        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11368
11369        let text_layout_details = &self.text_layout_details(window);
11370
11371        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11372            s.move_heads_with(|map, head, goal| {
11373                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11374            })
11375        })
11376    }
11377
11378    pub fn move_page_down(
11379        &mut self,
11380        action: &MovePageDown,
11381        window: &mut Window,
11382        cx: &mut Context<Self>,
11383    ) {
11384        if self.take_rename(true, window, cx).is_some() {
11385            return;
11386        }
11387
11388        if self
11389            .context_menu
11390            .borrow_mut()
11391            .as_mut()
11392            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11393            .unwrap_or(false)
11394        {
11395            return;
11396        }
11397
11398        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11399            cx.propagate();
11400            return;
11401        }
11402
11403        let Some(row_count) = self.visible_row_count() else {
11404            return;
11405        };
11406
11407        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11408
11409        let autoscroll = if action.center_cursor {
11410            Autoscroll::center()
11411        } else {
11412            Autoscroll::fit()
11413        };
11414
11415        let text_layout_details = &self.text_layout_details(window);
11416        self.change_selections(Some(autoscroll), window, cx, |s| {
11417            s.move_with(|map, selection| {
11418                if !selection.is_empty() {
11419                    selection.goal = SelectionGoal::None;
11420                }
11421                let (cursor, goal) = movement::down_by_rows(
11422                    map,
11423                    selection.end,
11424                    row_count,
11425                    selection.goal,
11426                    false,
11427                    text_layout_details,
11428                );
11429                selection.collapse_to(cursor, goal);
11430            });
11431        });
11432    }
11433
11434    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11435        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11436        let text_layout_details = &self.text_layout_details(window);
11437        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11438            s.move_heads_with(|map, head, goal| {
11439                movement::down(map, head, goal, false, text_layout_details)
11440            })
11441        });
11442    }
11443
11444    pub fn context_menu_first(
11445        &mut self,
11446        _: &ContextMenuFirst,
11447        _window: &mut Window,
11448        cx: &mut Context<Self>,
11449    ) {
11450        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11451            context_menu.select_first(self.completion_provider.as_deref(), cx);
11452        }
11453    }
11454
11455    pub fn context_menu_prev(
11456        &mut self,
11457        _: &ContextMenuPrevious,
11458        _window: &mut Window,
11459        cx: &mut Context<Self>,
11460    ) {
11461        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11462            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11463        }
11464    }
11465
11466    pub fn context_menu_next(
11467        &mut self,
11468        _: &ContextMenuNext,
11469        _window: &mut Window,
11470        cx: &mut Context<Self>,
11471    ) {
11472        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11473            context_menu.select_next(self.completion_provider.as_deref(), cx);
11474        }
11475    }
11476
11477    pub fn context_menu_last(
11478        &mut self,
11479        _: &ContextMenuLast,
11480        _window: &mut Window,
11481        cx: &mut Context<Self>,
11482    ) {
11483        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11484            context_menu.select_last(self.completion_provider.as_deref(), cx);
11485        }
11486    }
11487
11488    pub fn move_to_previous_word_start(
11489        &mut self,
11490        _: &MoveToPreviousWordStart,
11491        window: &mut Window,
11492        cx: &mut Context<Self>,
11493    ) {
11494        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11495        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11496            s.move_cursors_with(|map, head, _| {
11497                (
11498                    movement::previous_word_start(map, head),
11499                    SelectionGoal::None,
11500                )
11501            });
11502        })
11503    }
11504
11505    pub fn move_to_previous_subword_start(
11506        &mut self,
11507        _: &MoveToPreviousSubwordStart,
11508        window: &mut Window,
11509        cx: &mut Context<Self>,
11510    ) {
11511        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11512        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11513            s.move_cursors_with(|map, head, _| {
11514                (
11515                    movement::previous_subword_start(map, head),
11516                    SelectionGoal::None,
11517                )
11518            });
11519        })
11520    }
11521
11522    pub fn select_to_previous_word_start(
11523        &mut self,
11524        _: &SelectToPreviousWordStart,
11525        window: &mut Window,
11526        cx: &mut Context<Self>,
11527    ) {
11528        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11529        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11530            s.move_heads_with(|map, head, _| {
11531                (
11532                    movement::previous_word_start(map, head),
11533                    SelectionGoal::None,
11534                )
11535            });
11536        })
11537    }
11538
11539    pub fn select_to_previous_subword_start(
11540        &mut self,
11541        _: &SelectToPreviousSubwordStart,
11542        window: &mut Window,
11543        cx: &mut Context<Self>,
11544    ) {
11545        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11546        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11547            s.move_heads_with(|map, head, _| {
11548                (
11549                    movement::previous_subword_start(map, head),
11550                    SelectionGoal::None,
11551                )
11552            });
11553        })
11554    }
11555
11556    pub fn delete_to_previous_word_start(
11557        &mut self,
11558        action: &DeleteToPreviousWordStart,
11559        window: &mut Window,
11560        cx: &mut Context<Self>,
11561    ) {
11562        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11563        self.transact(window, cx, |this, window, cx| {
11564            this.select_autoclose_pair(window, cx);
11565            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11566                s.move_with(|map, selection| {
11567                    if selection.is_empty() {
11568                        let cursor = if action.ignore_newlines {
11569                            movement::previous_word_start(map, selection.head())
11570                        } else {
11571                            movement::previous_word_start_or_newline(map, selection.head())
11572                        };
11573                        selection.set_head(cursor, SelectionGoal::None);
11574                    }
11575                });
11576            });
11577            this.insert("", window, cx);
11578        });
11579    }
11580
11581    pub fn delete_to_previous_subword_start(
11582        &mut self,
11583        _: &DeleteToPreviousSubwordStart,
11584        window: &mut Window,
11585        cx: &mut Context<Self>,
11586    ) {
11587        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11588        self.transact(window, cx, |this, window, cx| {
11589            this.select_autoclose_pair(window, cx);
11590            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11591                s.move_with(|map, selection| {
11592                    if selection.is_empty() {
11593                        let cursor = movement::previous_subword_start(map, selection.head());
11594                        selection.set_head(cursor, SelectionGoal::None);
11595                    }
11596                });
11597            });
11598            this.insert("", window, cx);
11599        });
11600    }
11601
11602    pub fn move_to_next_word_end(
11603        &mut self,
11604        _: &MoveToNextWordEnd,
11605        window: &mut Window,
11606        cx: &mut Context<Self>,
11607    ) {
11608        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11609        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11610            s.move_cursors_with(|map, head, _| {
11611                (movement::next_word_end(map, head), SelectionGoal::None)
11612            });
11613        })
11614    }
11615
11616    pub fn move_to_next_subword_end(
11617        &mut self,
11618        _: &MoveToNextSubwordEnd,
11619        window: &mut Window,
11620        cx: &mut Context<Self>,
11621    ) {
11622        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11623        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11624            s.move_cursors_with(|map, head, _| {
11625                (movement::next_subword_end(map, head), SelectionGoal::None)
11626            });
11627        })
11628    }
11629
11630    pub fn select_to_next_word_end(
11631        &mut self,
11632        _: &SelectToNextWordEnd,
11633        window: &mut Window,
11634        cx: &mut Context<Self>,
11635    ) {
11636        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11637        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11638            s.move_heads_with(|map, head, _| {
11639                (movement::next_word_end(map, head), SelectionGoal::None)
11640            });
11641        })
11642    }
11643
11644    pub fn select_to_next_subword_end(
11645        &mut self,
11646        _: &SelectToNextSubwordEnd,
11647        window: &mut Window,
11648        cx: &mut Context<Self>,
11649    ) {
11650        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11651        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11652            s.move_heads_with(|map, head, _| {
11653                (movement::next_subword_end(map, head), SelectionGoal::None)
11654            });
11655        })
11656    }
11657
11658    pub fn delete_to_next_word_end(
11659        &mut self,
11660        action: &DeleteToNextWordEnd,
11661        window: &mut Window,
11662        cx: &mut Context<Self>,
11663    ) {
11664        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11665        self.transact(window, cx, |this, window, cx| {
11666            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11667                s.move_with(|map, selection| {
11668                    if selection.is_empty() {
11669                        let cursor = if action.ignore_newlines {
11670                            movement::next_word_end(map, selection.head())
11671                        } else {
11672                            movement::next_word_end_or_newline(map, selection.head())
11673                        };
11674                        selection.set_head(cursor, SelectionGoal::None);
11675                    }
11676                });
11677            });
11678            this.insert("", window, cx);
11679        });
11680    }
11681
11682    pub fn delete_to_next_subword_end(
11683        &mut self,
11684        _: &DeleteToNextSubwordEnd,
11685        window: &mut Window,
11686        cx: &mut Context<Self>,
11687    ) {
11688        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11689        self.transact(window, cx, |this, window, cx| {
11690            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11691                s.move_with(|map, selection| {
11692                    if selection.is_empty() {
11693                        let cursor = movement::next_subword_end(map, selection.head());
11694                        selection.set_head(cursor, SelectionGoal::None);
11695                    }
11696                });
11697            });
11698            this.insert("", window, cx);
11699        });
11700    }
11701
11702    pub fn move_to_beginning_of_line(
11703        &mut self,
11704        action: &MoveToBeginningOfLine,
11705        window: &mut Window,
11706        cx: &mut Context<Self>,
11707    ) {
11708        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11709        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11710            s.move_cursors_with(|map, head, _| {
11711                (
11712                    movement::indented_line_beginning(
11713                        map,
11714                        head,
11715                        action.stop_at_soft_wraps,
11716                        action.stop_at_indent,
11717                    ),
11718                    SelectionGoal::None,
11719                )
11720            });
11721        })
11722    }
11723
11724    pub fn select_to_beginning_of_line(
11725        &mut self,
11726        action: &SelectToBeginningOfLine,
11727        window: &mut Window,
11728        cx: &mut Context<Self>,
11729    ) {
11730        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11731        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11732            s.move_heads_with(|map, head, _| {
11733                (
11734                    movement::indented_line_beginning(
11735                        map,
11736                        head,
11737                        action.stop_at_soft_wraps,
11738                        action.stop_at_indent,
11739                    ),
11740                    SelectionGoal::None,
11741                )
11742            });
11743        });
11744    }
11745
11746    pub fn delete_to_beginning_of_line(
11747        &mut self,
11748        action: &DeleteToBeginningOfLine,
11749        window: &mut Window,
11750        cx: &mut Context<Self>,
11751    ) {
11752        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11753        self.transact(window, cx, |this, window, cx| {
11754            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11755                s.move_with(|_, selection| {
11756                    selection.reversed = true;
11757                });
11758            });
11759
11760            this.select_to_beginning_of_line(
11761                &SelectToBeginningOfLine {
11762                    stop_at_soft_wraps: false,
11763                    stop_at_indent: action.stop_at_indent,
11764                },
11765                window,
11766                cx,
11767            );
11768            this.backspace(&Backspace, window, cx);
11769        });
11770    }
11771
11772    pub fn move_to_end_of_line(
11773        &mut self,
11774        action: &MoveToEndOfLine,
11775        window: &mut Window,
11776        cx: &mut Context<Self>,
11777    ) {
11778        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11779        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11780            s.move_cursors_with(|map, head, _| {
11781                (
11782                    movement::line_end(map, head, action.stop_at_soft_wraps),
11783                    SelectionGoal::None,
11784                )
11785            });
11786        })
11787    }
11788
11789    pub fn select_to_end_of_line(
11790        &mut self,
11791        action: &SelectToEndOfLine,
11792        window: &mut Window,
11793        cx: &mut Context<Self>,
11794    ) {
11795        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11796        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11797            s.move_heads_with(|map, head, _| {
11798                (
11799                    movement::line_end(map, head, action.stop_at_soft_wraps),
11800                    SelectionGoal::None,
11801                )
11802            });
11803        })
11804    }
11805
11806    pub fn delete_to_end_of_line(
11807        &mut self,
11808        _: &DeleteToEndOfLine,
11809        window: &mut Window,
11810        cx: &mut Context<Self>,
11811    ) {
11812        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11813        self.transact(window, cx, |this, window, cx| {
11814            this.select_to_end_of_line(
11815                &SelectToEndOfLine {
11816                    stop_at_soft_wraps: false,
11817                },
11818                window,
11819                cx,
11820            );
11821            this.delete(&Delete, window, cx);
11822        });
11823    }
11824
11825    pub fn cut_to_end_of_line(
11826        &mut self,
11827        _: &CutToEndOfLine,
11828        window: &mut Window,
11829        cx: &mut Context<Self>,
11830    ) {
11831        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11832        self.transact(window, cx, |this, window, cx| {
11833            this.select_to_end_of_line(
11834                &SelectToEndOfLine {
11835                    stop_at_soft_wraps: false,
11836                },
11837                window,
11838                cx,
11839            );
11840            this.cut(&Cut, window, cx);
11841        });
11842    }
11843
11844    pub fn move_to_start_of_paragraph(
11845        &mut self,
11846        _: &MoveToStartOfParagraph,
11847        window: &mut Window,
11848        cx: &mut Context<Self>,
11849    ) {
11850        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11851            cx.propagate();
11852            return;
11853        }
11854        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11855        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11856            s.move_with(|map, selection| {
11857                selection.collapse_to(
11858                    movement::start_of_paragraph(map, selection.head(), 1),
11859                    SelectionGoal::None,
11860                )
11861            });
11862        })
11863    }
11864
11865    pub fn move_to_end_of_paragraph(
11866        &mut self,
11867        _: &MoveToEndOfParagraph,
11868        window: &mut Window,
11869        cx: &mut Context<Self>,
11870    ) {
11871        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11872            cx.propagate();
11873            return;
11874        }
11875        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11876        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11877            s.move_with(|map, selection| {
11878                selection.collapse_to(
11879                    movement::end_of_paragraph(map, selection.head(), 1),
11880                    SelectionGoal::None,
11881                )
11882            });
11883        })
11884    }
11885
11886    pub fn select_to_start_of_paragraph(
11887        &mut self,
11888        _: &SelectToStartOfParagraph,
11889        window: &mut Window,
11890        cx: &mut Context<Self>,
11891    ) {
11892        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11893            cx.propagate();
11894            return;
11895        }
11896        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11897        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11898            s.move_heads_with(|map, head, _| {
11899                (
11900                    movement::start_of_paragraph(map, head, 1),
11901                    SelectionGoal::None,
11902                )
11903            });
11904        })
11905    }
11906
11907    pub fn select_to_end_of_paragraph(
11908        &mut self,
11909        _: &SelectToEndOfParagraph,
11910        window: &mut Window,
11911        cx: &mut Context<Self>,
11912    ) {
11913        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11914            cx.propagate();
11915            return;
11916        }
11917        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11918        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11919            s.move_heads_with(|map, head, _| {
11920                (
11921                    movement::end_of_paragraph(map, head, 1),
11922                    SelectionGoal::None,
11923                )
11924            });
11925        })
11926    }
11927
11928    pub fn move_to_start_of_excerpt(
11929        &mut self,
11930        _: &MoveToStartOfExcerpt,
11931        window: &mut Window,
11932        cx: &mut Context<Self>,
11933    ) {
11934        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11935            cx.propagate();
11936            return;
11937        }
11938        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11939        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11940            s.move_with(|map, selection| {
11941                selection.collapse_to(
11942                    movement::start_of_excerpt(
11943                        map,
11944                        selection.head(),
11945                        workspace::searchable::Direction::Prev,
11946                    ),
11947                    SelectionGoal::None,
11948                )
11949            });
11950        })
11951    }
11952
11953    pub fn move_to_start_of_next_excerpt(
11954        &mut self,
11955        _: &MoveToStartOfNextExcerpt,
11956        window: &mut Window,
11957        cx: &mut Context<Self>,
11958    ) {
11959        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11960            cx.propagate();
11961            return;
11962        }
11963
11964        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11965            s.move_with(|map, selection| {
11966                selection.collapse_to(
11967                    movement::start_of_excerpt(
11968                        map,
11969                        selection.head(),
11970                        workspace::searchable::Direction::Next,
11971                    ),
11972                    SelectionGoal::None,
11973                )
11974            });
11975        })
11976    }
11977
11978    pub fn move_to_end_of_excerpt(
11979        &mut self,
11980        _: &MoveToEndOfExcerpt,
11981        window: &mut Window,
11982        cx: &mut Context<Self>,
11983    ) {
11984        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11985            cx.propagate();
11986            return;
11987        }
11988        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11989        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11990            s.move_with(|map, selection| {
11991                selection.collapse_to(
11992                    movement::end_of_excerpt(
11993                        map,
11994                        selection.head(),
11995                        workspace::searchable::Direction::Next,
11996                    ),
11997                    SelectionGoal::None,
11998                )
11999            });
12000        })
12001    }
12002
12003    pub fn move_to_end_of_previous_excerpt(
12004        &mut self,
12005        _: &MoveToEndOfPreviousExcerpt,
12006        window: &mut Window,
12007        cx: &mut Context<Self>,
12008    ) {
12009        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12010            cx.propagate();
12011            return;
12012        }
12013        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12014        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12015            s.move_with(|map, selection| {
12016                selection.collapse_to(
12017                    movement::end_of_excerpt(
12018                        map,
12019                        selection.head(),
12020                        workspace::searchable::Direction::Prev,
12021                    ),
12022                    SelectionGoal::None,
12023                )
12024            });
12025        })
12026    }
12027
12028    pub fn select_to_start_of_excerpt(
12029        &mut self,
12030        _: &SelectToStartOfExcerpt,
12031        window: &mut Window,
12032        cx: &mut Context<Self>,
12033    ) {
12034        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12035            cx.propagate();
12036            return;
12037        }
12038        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12039        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12040            s.move_heads_with(|map, head, _| {
12041                (
12042                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12043                    SelectionGoal::None,
12044                )
12045            });
12046        })
12047    }
12048
12049    pub fn select_to_start_of_next_excerpt(
12050        &mut self,
12051        _: &SelectToStartOfNextExcerpt,
12052        window: &mut Window,
12053        cx: &mut Context<Self>,
12054    ) {
12055        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12056            cx.propagate();
12057            return;
12058        }
12059        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12060        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12061            s.move_heads_with(|map, head, _| {
12062                (
12063                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12064                    SelectionGoal::None,
12065                )
12066            });
12067        })
12068    }
12069
12070    pub fn select_to_end_of_excerpt(
12071        &mut self,
12072        _: &SelectToEndOfExcerpt,
12073        window: &mut Window,
12074        cx: &mut Context<Self>,
12075    ) {
12076        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12077            cx.propagate();
12078            return;
12079        }
12080        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12081        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12082            s.move_heads_with(|map, head, _| {
12083                (
12084                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12085                    SelectionGoal::None,
12086                )
12087            });
12088        })
12089    }
12090
12091    pub fn select_to_end_of_previous_excerpt(
12092        &mut self,
12093        _: &SelectToEndOfPreviousExcerpt,
12094        window: &mut Window,
12095        cx: &mut Context<Self>,
12096    ) {
12097        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12098            cx.propagate();
12099            return;
12100        }
12101        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12102        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12103            s.move_heads_with(|map, head, _| {
12104                (
12105                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12106                    SelectionGoal::None,
12107                )
12108            });
12109        })
12110    }
12111
12112    pub fn move_to_beginning(
12113        &mut self,
12114        _: &MoveToBeginning,
12115        window: &mut Window,
12116        cx: &mut Context<Self>,
12117    ) {
12118        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12119            cx.propagate();
12120            return;
12121        }
12122        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12123        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12124            s.select_ranges(vec![0..0]);
12125        });
12126    }
12127
12128    pub fn select_to_beginning(
12129        &mut self,
12130        _: &SelectToBeginning,
12131        window: &mut Window,
12132        cx: &mut Context<Self>,
12133    ) {
12134        let mut selection = self.selections.last::<Point>(cx);
12135        selection.set_head(Point::zero(), SelectionGoal::None);
12136        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12137        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12138            s.select(vec![selection]);
12139        });
12140    }
12141
12142    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12143        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12144            cx.propagate();
12145            return;
12146        }
12147        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12148        let cursor = self.buffer.read(cx).read(cx).len();
12149        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12150            s.select_ranges(vec![cursor..cursor])
12151        });
12152    }
12153
12154    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12155        self.nav_history = nav_history;
12156    }
12157
12158    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12159        self.nav_history.as_ref()
12160    }
12161
12162    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12163        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12164    }
12165
12166    fn push_to_nav_history(
12167        &mut self,
12168        cursor_anchor: Anchor,
12169        new_position: Option<Point>,
12170        is_deactivate: bool,
12171        cx: &mut Context<Self>,
12172    ) {
12173        if let Some(nav_history) = self.nav_history.as_mut() {
12174            let buffer = self.buffer.read(cx).read(cx);
12175            let cursor_position = cursor_anchor.to_point(&buffer);
12176            let scroll_state = self.scroll_manager.anchor();
12177            let scroll_top_row = scroll_state.top_row(&buffer);
12178            drop(buffer);
12179
12180            if let Some(new_position) = new_position {
12181                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12182                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12183                    return;
12184                }
12185            }
12186
12187            nav_history.push(
12188                Some(NavigationData {
12189                    cursor_anchor,
12190                    cursor_position,
12191                    scroll_anchor: scroll_state,
12192                    scroll_top_row,
12193                }),
12194                cx,
12195            );
12196            cx.emit(EditorEvent::PushedToNavHistory {
12197                anchor: cursor_anchor,
12198                is_deactivate,
12199            })
12200        }
12201    }
12202
12203    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12204        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12205        let buffer = self.buffer.read(cx).snapshot(cx);
12206        let mut selection = self.selections.first::<usize>(cx);
12207        selection.set_head(buffer.len(), SelectionGoal::None);
12208        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12209            s.select(vec![selection]);
12210        });
12211    }
12212
12213    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12214        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12215        let end = self.buffer.read(cx).read(cx).len();
12216        self.change_selections(None, window, cx, |s| {
12217            s.select_ranges(vec![0..end]);
12218        });
12219    }
12220
12221    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12222        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12223        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12224        let mut selections = self.selections.all::<Point>(cx);
12225        let max_point = display_map.buffer_snapshot.max_point();
12226        for selection in &mut selections {
12227            let rows = selection.spanned_rows(true, &display_map);
12228            selection.start = Point::new(rows.start.0, 0);
12229            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12230            selection.reversed = false;
12231        }
12232        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12233            s.select(selections);
12234        });
12235    }
12236
12237    pub fn split_selection_into_lines(
12238        &mut self,
12239        _: &SplitSelectionIntoLines,
12240        window: &mut Window,
12241        cx: &mut Context<Self>,
12242    ) {
12243        let selections = self
12244            .selections
12245            .all::<Point>(cx)
12246            .into_iter()
12247            .map(|selection| selection.start..selection.end)
12248            .collect::<Vec<_>>();
12249        self.unfold_ranges(&selections, true, true, cx);
12250
12251        let mut new_selection_ranges = Vec::new();
12252        {
12253            let buffer = self.buffer.read(cx).read(cx);
12254            for selection in selections {
12255                for row in selection.start.row..selection.end.row {
12256                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12257                    new_selection_ranges.push(cursor..cursor);
12258                }
12259
12260                let is_multiline_selection = selection.start.row != selection.end.row;
12261                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12262                // so this action feels more ergonomic when paired with other selection operations
12263                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12264                if !should_skip_last {
12265                    new_selection_ranges.push(selection.end..selection.end);
12266                }
12267            }
12268        }
12269        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12270            s.select_ranges(new_selection_ranges);
12271        });
12272    }
12273
12274    pub fn add_selection_above(
12275        &mut self,
12276        _: &AddSelectionAbove,
12277        window: &mut Window,
12278        cx: &mut Context<Self>,
12279    ) {
12280        self.add_selection(true, window, cx);
12281    }
12282
12283    pub fn add_selection_below(
12284        &mut self,
12285        _: &AddSelectionBelow,
12286        window: &mut Window,
12287        cx: &mut Context<Self>,
12288    ) {
12289        self.add_selection(false, window, cx);
12290    }
12291
12292    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12293        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12294
12295        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12296        let mut selections = self.selections.all::<Point>(cx);
12297        let text_layout_details = self.text_layout_details(window);
12298        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12299            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12300            let range = oldest_selection.display_range(&display_map).sorted();
12301
12302            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12303            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12304            let positions = start_x.min(end_x)..start_x.max(end_x);
12305
12306            selections.clear();
12307            let mut stack = Vec::new();
12308            for row in range.start.row().0..=range.end.row().0 {
12309                if let Some(selection) = self.selections.build_columnar_selection(
12310                    &display_map,
12311                    DisplayRow(row),
12312                    &positions,
12313                    oldest_selection.reversed,
12314                    &text_layout_details,
12315                ) {
12316                    stack.push(selection.id);
12317                    selections.push(selection);
12318                }
12319            }
12320
12321            if above {
12322                stack.reverse();
12323            }
12324
12325            AddSelectionsState { above, stack }
12326        });
12327
12328        let last_added_selection = *state.stack.last().unwrap();
12329        let mut new_selections = Vec::new();
12330        if above == state.above {
12331            let end_row = if above {
12332                DisplayRow(0)
12333            } else {
12334                display_map.max_point().row()
12335            };
12336
12337            'outer: for selection in selections {
12338                if selection.id == last_added_selection {
12339                    let range = selection.display_range(&display_map).sorted();
12340                    debug_assert_eq!(range.start.row(), range.end.row());
12341                    let mut row = range.start.row();
12342                    let positions =
12343                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12344                            px(start)..px(end)
12345                        } else {
12346                            let start_x =
12347                                display_map.x_for_display_point(range.start, &text_layout_details);
12348                            let end_x =
12349                                display_map.x_for_display_point(range.end, &text_layout_details);
12350                            start_x.min(end_x)..start_x.max(end_x)
12351                        };
12352
12353                    while row != end_row {
12354                        if above {
12355                            row.0 -= 1;
12356                        } else {
12357                            row.0 += 1;
12358                        }
12359
12360                        if let Some(new_selection) = self.selections.build_columnar_selection(
12361                            &display_map,
12362                            row,
12363                            &positions,
12364                            selection.reversed,
12365                            &text_layout_details,
12366                        ) {
12367                            state.stack.push(new_selection.id);
12368                            if above {
12369                                new_selections.push(new_selection);
12370                                new_selections.push(selection);
12371                            } else {
12372                                new_selections.push(selection);
12373                                new_selections.push(new_selection);
12374                            }
12375
12376                            continue 'outer;
12377                        }
12378                    }
12379                }
12380
12381                new_selections.push(selection);
12382            }
12383        } else {
12384            new_selections = selections;
12385            new_selections.retain(|s| s.id != last_added_selection);
12386            state.stack.pop();
12387        }
12388
12389        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12390            s.select(new_selections);
12391        });
12392        if state.stack.len() > 1 {
12393            self.add_selections_state = Some(state);
12394        }
12395    }
12396
12397    fn select_match_ranges(
12398        &mut self,
12399        range: Range<usize>,
12400        reversed: bool,
12401        replace_newest: bool,
12402        auto_scroll: Option<Autoscroll>,
12403        window: &mut Window,
12404        cx: &mut Context<Editor>,
12405    ) {
12406        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12407        self.change_selections(auto_scroll, window, cx, |s| {
12408            if replace_newest {
12409                s.delete(s.newest_anchor().id);
12410            }
12411            if reversed {
12412                s.insert_range(range.end..range.start);
12413            } else {
12414                s.insert_range(range);
12415            }
12416        });
12417    }
12418
12419    pub fn select_next_match_internal(
12420        &mut self,
12421        display_map: &DisplaySnapshot,
12422        replace_newest: bool,
12423        autoscroll: Option<Autoscroll>,
12424        window: &mut Window,
12425        cx: &mut Context<Self>,
12426    ) -> Result<()> {
12427        let buffer = &display_map.buffer_snapshot;
12428        let mut selections = self.selections.all::<usize>(cx);
12429        if let Some(mut select_next_state) = self.select_next_state.take() {
12430            let query = &select_next_state.query;
12431            if !select_next_state.done {
12432                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12433                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12434                let mut next_selected_range = None;
12435
12436                let bytes_after_last_selection =
12437                    buffer.bytes_in_range(last_selection.end..buffer.len());
12438                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12439                let query_matches = query
12440                    .stream_find_iter(bytes_after_last_selection)
12441                    .map(|result| (last_selection.end, result))
12442                    .chain(
12443                        query
12444                            .stream_find_iter(bytes_before_first_selection)
12445                            .map(|result| (0, result)),
12446                    );
12447
12448                for (start_offset, query_match) in query_matches {
12449                    let query_match = query_match.unwrap(); // can only fail due to I/O
12450                    let offset_range =
12451                        start_offset + query_match.start()..start_offset + query_match.end();
12452                    let display_range = offset_range.start.to_display_point(display_map)
12453                        ..offset_range.end.to_display_point(display_map);
12454
12455                    if !select_next_state.wordwise
12456                        || (!movement::is_inside_word(display_map, display_range.start)
12457                            && !movement::is_inside_word(display_map, display_range.end))
12458                    {
12459                        // TODO: This is n^2, because we might check all the selections
12460                        if !selections
12461                            .iter()
12462                            .any(|selection| selection.range().overlaps(&offset_range))
12463                        {
12464                            next_selected_range = Some(offset_range);
12465                            break;
12466                        }
12467                    }
12468                }
12469
12470                if let Some(next_selected_range) = next_selected_range {
12471                    self.select_match_ranges(
12472                        next_selected_range,
12473                        last_selection.reversed,
12474                        replace_newest,
12475                        autoscroll,
12476                        window,
12477                        cx,
12478                    );
12479                } else {
12480                    select_next_state.done = true;
12481                }
12482            }
12483
12484            self.select_next_state = Some(select_next_state);
12485        } else {
12486            let mut only_carets = true;
12487            let mut same_text_selected = true;
12488            let mut selected_text = None;
12489
12490            let mut selections_iter = selections.iter().peekable();
12491            while let Some(selection) = selections_iter.next() {
12492                if selection.start != selection.end {
12493                    only_carets = false;
12494                }
12495
12496                if same_text_selected {
12497                    if selected_text.is_none() {
12498                        selected_text =
12499                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12500                    }
12501
12502                    if let Some(next_selection) = selections_iter.peek() {
12503                        if next_selection.range().len() == selection.range().len() {
12504                            let next_selected_text = buffer
12505                                .text_for_range(next_selection.range())
12506                                .collect::<String>();
12507                            if Some(next_selected_text) != selected_text {
12508                                same_text_selected = false;
12509                                selected_text = None;
12510                            }
12511                        } else {
12512                            same_text_selected = false;
12513                            selected_text = None;
12514                        }
12515                    }
12516                }
12517            }
12518
12519            if only_carets {
12520                for selection in &mut selections {
12521                    let word_range = movement::surrounding_word(
12522                        display_map,
12523                        selection.start.to_display_point(display_map),
12524                    );
12525                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12526                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12527                    selection.goal = SelectionGoal::None;
12528                    selection.reversed = false;
12529                    self.select_match_ranges(
12530                        selection.start..selection.end,
12531                        selection.reversed,
12532                        replace_newest,
12533                        autoscroll,
12534                        window,
12535                        cx,
12536                    );
12537                }
12538
12539                if selections.len() == 1 {
12540                    let selection = selections
12541                        .last()
12542                        .expect("ensured that there's only one selection");
12543                    let query = buffer
12544                        .text_for_range(selection.start..selection.end)
12545                        .collect::<String>();
12546                    let is_empty = query.is_empty();
12547                    let select_state = SelectNextState {
12548                        query: AhoCorasick::new(&[query])?,
12549                        wordwise: true,
12550                        done: is_empty,
12551                    };
12552                    self.select_next_state = Some(select_state);
12553                } else {
12554                    self.select_next_state = None;
12555                }
12556            } else if let Some(selected_text) = selected_text {
12557                self.select_next_state = Some(SelectNextState {
12558                    query: AhoCorasick::new(&[selected_text])?,
12559                    wordwise: false,
12560                    done: false,
12561                });
12562                self.select_next_match_internal(
12563                    display_map,
12564                    replace_newest,
12565                    autoscroll,
12566                    window,
12567                    cx,
12568                )?;
12569            }
12570        }
12571        Ok(())
12572    }
12573
12574    pub fn select_all_matches(
12575        &mut self,
12576        _action: &SelectAllMatches,
12577        window: &mut Window,
12578        cx: &mut Context<Self>,
12579    ) -> Result<()> {
12580        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12581
12582        self.push_to_selection_history();
12583        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12584
12585        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12586        let Some(select_next_state) = self.select_next_state.as_mut() else {
12587            return Ok(());
12588        };
12589        if select_next_state.done {
12590            return Ok(());
12591        }
12592
12593        let mut new_selections = Vec::new();
12594
12595        let reversed = self.selections.oldest::<usize>(cx).reversed;
12596        let buffer = &display_map.buffer_snapshot;
12597        let query_matches = select_next_state
12598            .query
12599            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12600
12601        for query_match in query_matches.into_iter() {
12602            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12603            let offset_range = if reversed {
12604                query_match.end()..query_match.start()
12605            } else {
12606                query_match.start()..query_match.end()
12607            };
12608            let display_range = offset_range.start.to_display_point(&display_map)
12609                ..offset_range.end.to_display_point(&display_map);
12610
12611            if !select_next_state.wordwise
12612                || (!movement::is_inside_word(&display_map, display_range.start)
12613                    && !movement::is_inside_word(&display_map, display_range.end))
12614            {
12615                new_selections.push(offset_range.start..offset_range.end);
12616            }
12617        }
12618
12619        select_next_state.done = true;
12620        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12621        self.change_selections(None, window, cx, |selections| {
12622            selections.select_ranges(new_selections)
12623        });
12624
12625        Ok(())
12626    }
12627
12628    pub fn select_next(
12629        &mut self,
12630        action: &SelectNext,
12631        window: &mut Window,
12632        cx: &mut Context<Self>,
12633    ) -> Result<()> {
12634        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12635        self.push_to_selection_history();
12636        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12637        self.select_next_match_internal(
12638            &display_map,
12639            action.replace_newest,
12640            Some(Autoscroll::newest()),
12641            window,
12642            cx,
12643        )?;
12644        Ok(())
12645    }
12646
12647    pub fn select_previous(
12648        &mut self,
12649        action: &SelectPrevious,
12650        window: &mut Window,
12651        cx: &mut Context<Self>,
12652    ) -> Result<()> {
12653        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12654        self.push_to_selection_history();
12655        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12656        let buffer = &display_map.buffer_snapshot;
12657        let mut selections = self.selections.all::<usize>(cx);
12658        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12659            let query = &select_prev_state.query;
12660            if !select_prev_state.done {
12661                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12662                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12663                let mut next_selected_range = None;
12664                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12665                let bytes_before_last_selection =
12666                    buffer.reversed_bytes_in_range(0..last_selection.start);
12667                let bytes_after_first_selection =
12668                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12669                let query_matches = query
12670                    .stream_find_iter(bytes_before_last_selection)
12671                    .map(|result| (last_selection.start, result))
12672                    .chain(
12673                        query
12674                            .stream_find_iter(bytes_after_first_selection)
12675                            .map(|result| (buffer.len(), result)),
12676                    );
12677                for (end_offset, query_match) in query_matches {
12678                    let query_match = query_match.unwrap(); // can only fail due to I/O
12679                    let offset_range =
12680                        end_offset - query_match.end()..end_offset - query_match.start();
12681                    let display_range = offset_range.start.to_display_point(&display_map)
12682                        ..offset_range.end.to_display_point(&display_map);
12683
12684                    if !select_prev_state.wordwise
12685                        || (!movement::is_inside_word(&display_map, display_range.start)
12686                            && !movement::is_inside_word(&display_map, display_range.end))
12687                    {
12688                        next_selected_range = Some(offset_range);
12689                        break;
12690                    }
12691                }
12692
12693                if let Some(next_selected_range) = next_selected_range {
12694                    self.select_match_ranges(
12695                        next_selected_range,
12696                        last_selection.reversed,
12697                        action.replace_newest,
12698                        Some(Autoscroll::newest()),
12699                        window,
12700                        cx,
12701                    );
12702                } else {
12703                    select_prev_state.done = true;
12704                }
12705            }
12706
12707            self.select_prev_state = Some(select_prev_state);
12708        } else {
12709            let mut only_carets = true;
12710            let mut same_text_selected = true;
12711            let mut selected_text = None;
12712
12713            let mut selections_iter = selections.iter().peekable();
12714            while let Some(selection) = selections_iter.next() {
12715                if selection.start != selection.end {
12716                    only_carets = false;
12717                }
12718
12719                if same_text_selected {
12720                    if selected_text.is_none() {
12721                        selected_text =
12722                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12723                    }
12724
12725                    if let Some(next_selection) = selections_iter.peek() {
12726                        if next_selection.range().len() == selection.range().len() {
12727                            let next_selected_text = buffer
12728                                .text_for_range(next_selection.range())
12729                                .collect::<String>();
12730                            if Some(next_selected_text) != selected_text {
12731                                same_text_selected = false;
12732                                selected_text = None;
12733                            }
12734                        } else {
12735                            same_text_selected = false;
12736                            selected_text = None;
12737                        }
12738                    }
12739                }
12740            }
12741
12742            if only_carets {
12743                for selection in &mut selections {
12744                    let word_range = movement::surrounding_word(
12745                        &display_map,
12746                        selection.start.to_display_point(&display_map),
12747                    );
12748                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12749                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12750                    selection.goal = SelectionGoal::None;
12751                    selection.reversed = false;
12752                    self.select_match_ranges(
12753                        selection.start..selection.end,
12754                        selection.reversed,
12755                        action.replace_newest,
12756                        Some(Autoscroll::newest()),
12757                        window,
12758                        cx,
12759                    );
12760                }
12761                if selections.len() == 1 {
12762                    let selection = selections
12763                        .last()
12764                        .expect("ensured that there's only one selection");
12765                    let query = buffer
12766                        .text_for_range(selection.start..selection.end)
12767                        .collect::<String>();
12768                    let is_empty = query.is_empty();
12769                    let select_state = SelectNextState {
12770                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12771                        wordwise: true,
12772                        done: is_empty,
12773                    };
12774                    self.select_prev_state = Some(select_state);
12775                } else {
12776                    self.select_prev_state = None;
12777                }
12778            } else if let Some(selected_text) = selected_text {
12779                self.select_prev_state = Some(SelectNextState {
12780                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12781                    wordwise: false,
12782                    done: false,
12783                });
12784                self.select_previous(action, window, cx)?;
12785            }
12786        }
12787        Ok(())
12788    }
12789
12790    pub fn find_next_match(
12791        &mut self,
12792        _: &FindNextMatch,
12793        window: &mut Window,
12794        cx: &mut Context<Self>,
12795    ) -> Result<()> {
12796        let selections = self.selections.disjoint_anchors();
12797        match selections.first() {
12798            Some(first) if selections.len() >= 2 => {
12799                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12800                    s.select_ranges([first.range()]);
12801                });
12802            }
12803            _ => self.select_next(
12804                &SelectNext {
12805                    replace_newest: true,
12806                },
12807                window,
12808                cx,
12809            )?,
12810        }
12811        Ok(())
12812    }
12813
12814    pub fn find_previous_match(
12815        &mut self,
12816        _: &FindPreviousMatch,
12817        window: &mut Window,
12818        cx: &mut Context<Self>,
12819    ) -> Result<()> {
12820        let selections = self.selections.disjoint_anchors();
12821        match selections.last() {
12822            Some(last) if selections.len() >= 2 => {
12823                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12824                    s.select_ranges([last.range()]);
12825                });
12826            }
12827            _ => self.select_previous(
12828                &SelectPrevious {
12829                    replace_newest: true,
12830                },
12831                window,
12832                cx,
12833            )?,
12834        }
12835        Ok(())
12836    }
12837
12838    pub fn toggle_comments(
12839        &mut self,
12840        action: &ToggleComments,
12841        window: &mut Window,
12842        cx: &mut Context<Self>,
12843    ) {
12844        if self.read_only(cx) {
12845            return;
12846        }
12847        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12848        let text_layout_details = &self.text_layout_details(window);
12849        self.transact(window, cx, |this, window, cx| {
12850            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12851            let mut edits = Vec::new();
12852            let mut selection_edit_ranges = Vec::new();
12853            let mut last_toggled_row = None;
12854            let snapshot = this.buffer.read(cx).read(cx);
12855            let empty_str: Arc<str> = Arc::default();
12856            let mut suffixes_inserted = Vec::new();
12857            let ignore_indent = action.ignore_indent;
12858
12859            fn comment_prefix_range(
12860                snapshot: &MultiBufferSnapshot,
12861                row: MultiBufferRow,
12862                comment_prefix: &str,
12863                comment_prefix_whitespace: &str,
12864                ignore_indent: bool,
12865            ) -> Range<Point> {
12866                let indent_size = if ignore_indent {
12867                    0
12868                } else {
12869                    snapshot.indent_size_for_line(row).len
12870                };
12871
12872                let start = Point::new(row.0, indent_size);
12873
12874                let mut line_bytes = snapshot
12875                    .bytes_in_range(start..snapshot.max_point())
12876                    .flatten()
12877                    .copied();
12878
12879                // If this line currently begins with the line comment prefix, then record
12880                // the range containing the prefix.
12881                if line_bytes
12882                    .by_ref()
12883                    .take(comment_prefix.len())
12884                    .eq(comment_prefix.bytes())
12885                {
12886                    // Include any whitespace that matches the comment prefix.
12887                    let matching_whitespace_len = line_bytes
12888                        .zip(comment_prefix_whitespace.bytes())
12889                        .take_while(|(a, b)| a == b)
12890                        .count() as u32;
12891                    let end = Point::new(
12892                        start.row,
12893                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12894                    );
12895                    start..end
12896                } else {
12897                    start..start
12898                }
12899            }
12900
12901            fn comment_suffix_range(
12902                snapshot: &MultiBufferSnapshot,
12903                row: MultiBufferRow,
12904                comment_suffix: &str,
12905                comment_suffix_has_leading_space: bool,
12906            ) -> Range<Point> {
12907                let end = Point::new(row.0, snapshot.line_len(row));
12908                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12909
12910                let mut line_end_bytes = snapshot
12911                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12912                    .flatten()
12913                    .copied();
12914
12915                let leading_space_len = if suffix_start_column > 0
12916                    && line_end_bytes.next() == Some(b' ')
12917                    && comment_suffix_has_leading_space
12918                {
12919                    1
12920                } else {
12921                    0
12922                };
12923
12924                // If this line currently begins with the line comment prefix, then record
12925                // the range containing the prefix.
12926                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12927                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12928                    start..end
12929                } else {
12930                    end..end
12931                }
12932            }
12933
12934            // TODO: Handle selections that cross excerpts
12935            for selection in &mut selections {
12936                let start_column = snapshot
12937                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12938                    .len;
12939                let language = if let Some(language) =
12940                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12941                {
12942                    language
12943                } else {
12944                    continue;
12945                };
12946
12947                selection_edit_ranges.clear();
12948
12949                // If multiple selections contain a given row, avoid processing that
12950                // row more than once.
12951                let mut start_row = MultiBufferRow(selection.start.row);
12952                if last_toggled_row == Some(start_row) {
12953                    start_row = start_row.next_row();
12954                }
12955                let end_row =
12956                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12957                        MultiBufferRow(selection.end.row - 1)
12958                    } else {
12959                        MultiBufferRow(selection.end.row)
12960                    };
12961                last_toggled_row = Some(end_row);
12962
12963                if start_row > end_row {
12964                    continue;
12965                }
12966
12967                // If the language has line comments, toggle those.
12968                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12969
12970                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12971                if ignore_indent {
12972                    full_comment_prefixes = full_comment_prefixes
12973                        .into_iter()
12974                        .map(|s| Arc::from(s.trim_end()))
12975                        .collect();
12976                }
12977
12978                if !full_comment_prefixes.is_empty() {
12979                    let first_prefix = full_comment_prefixes
12980                        .first()
12981                        .expect("prefixes is non-empty");
12982                    let prefix_trimmed_lengths = full_comment_prefixes
12983                        .iter()
12984                        .map(|p| p.trim_end_matches(' ').len())
12985                        .collect::<SmallVec<[usize; 4]>>();
12986
12987                    let mut all_selection_lines_are_comments = true;
12988
12989                    for row in start_row.0..=end_row.0 {
12990                        let row = MultiBufferRow(row);
12991                        if start_row < end_row && snapshot.is_line_blank(row) {
12992                            continue;
12993                        }
12994
12995                        let prefix_range = full_comment_prefixes
12996                            .iter()
12997                            .zip(prefix_trimmed_lengths.iter().copied())
12998                            .map(|(prefix, trimmed_prefix_len)| {
12999                                comment_prefix_range(
13000                                    snapshot.deref(),
13001                                    row,
13002                                    &prefix[..trimmed_prefix_len],
13003                                    &prefix[trimmed_prefix_len..],
13004                                    ignore_indent,
13005                                )
13006                            })
13007                            .max_by_key(|range| range.end.column - range.start.column)
13008                            .expect("prefixes is non-empty");
13009
13010                        if prefix_range.is_empty() {
13011                            all_selection_lines_are_comments = false;
13012                        }
13013
13014                        selection_edit_ranges.push(prefix_range);
13015                    }
13016
13017                    if all_selection_lines_are_comments {
13018                        edits.extend(
13019                            selection_edit_ranges
13020                                .iter()
13021                                .cloned()
13022                                .map(|range| (range, empty_str.clone())),
13023                        );
13024                    } else {
13025                        let min_column = selection_edit_ranges
13026                            .iter()
13027                            .map(|range| range.start.column)
13028                            .min()
13029                            .unwrap_or(0);
13030                        edits.extend(selection_edit_ranges.iter().map(|range| {
13031                            let position = Point::new(range.start.row, min_column);
13032                            (position..position, first_prefix.clone())
13033                        }));
13034                    }
13035                } else if let Some((full_comment_prefix, comment_suffix)) =
13036                    language.block_comment_delimiters()
13037                {
13038                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13039                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13040                    let prefix_range = comment_prefix_range(
13041                        snapshot.deref(),
13042                        start_row,
13043                        comment_prefix,
13044                        comment_prefix_whitespace,
13045                        ignore_indent,
13046                    );
13047                    let suffix_range = comment_suffix_range(
13048                        snapshot.deref(),
13049                        end_row,
13050                        comment_suffix.trim_start_matches(' '),
13051                        comment_suffix.starts_with(' '),
13052                    );
13053
13054                    if prefix_range.is_empty() || suffix_range.is_empty() {
13055                        edits.push((
13056                            prefix_range.start..prefix_range.start,
13057                            full_comment_prefix.clone(),
13058                        ));
13059                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13060                        suffixes_inserted.push((end_row, comment_suffix.len()));
13061                    } else {
13062                        edits.push((prefix_range, empty_str.clone()));
13063                        edits.push((suffix_range, empty_str.clone()));
13064                    }
13065                } else {
13066                    continue;
13067                }
13068            }
13069
13070            drop(snapshot);
13071            this.buffer.update(cx, |buffer, cx| {
13072                buffer.edit(edits, None, cx);
13073            });
13074
13075            // Adjust selections so that they end before any comment suffixes that
13076            // were inserted.
13077            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13078            let mut selections = this.selections.all::<Point>(cx);
13079            let snapshot = this.buffer.read(cx).read(cx);
13080            for selection in &mut selections {
13081                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13082                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13083                        Ordering::Less => {
13084                            suffixes_inserted.next();
13085                            continue;
13086                        }
13087                        Ordering::Greater => break,
13088                        Ordering::Equal => {
13089                            if selection.end.column == snapshot.line_len(row) {
13090                                if selection.is_empty() {
13091                                    selection.start.column -= suffix_len as u32;
13092                                }
13093                                selection.end.column -= suffix_len as u32;
13094                            }
13095                            break;
13096                        }
13097                    }
13098                }
13099            }
13100
13101            drop(snapshot);
13102            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13103                s.select(selections)
13104            });
13105
13106            let selections = this.selections.all::<Point>(cx);
13107            let selections_on_single_row = selections.windows(2).all(|selections| {
13108                selections[0].start.row == selections[1].start.row
13109                    && selections[0].end.row == selections[1].end.row
13110                    && selections[0].start.row == selections[0].end.row
13111            });
13112            let selections_selecting = selections
13113                .iter()
13114                .any(|selection| selection.start != selection.end);
13115            let advance_downwards = action.advance_downwards
13116                && selections_on_single_row
13117                && !selections_selecting
13118                && !matches!(this.mode, EditorMode::SingleLine { .. });
13119
13120            if advance_downwards {
13121                let snapshot = this.buffer.read(cx).snapshot(cx);
13122
13123                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13124                    s.move_cursors_with(|display_snapshot, display_point, _| {
13125                        let mut point = display_point.to_point(display_snapshot);
13126                        point.row += 1;
13127                        point = snapshot.clip_point(point, Bias::Left);
13128                        let display_point = point.to_display_point(display_snapshot);
13129                        let goal = SelectionGoal::HorizontalPosition(
13130                            display_snapshot
13131                                .x_for_display_point(display_point, text_layout_details)
13132                                .into(),
13133                        );
13134                        (display_point, goal)
13135                    })
13136                });
13137            }
13138        });
13139    }
13140
13141    pub fn select_enclosing_symbol(
13142        &mut self,
13143        _: &SelectEnclosingSymbol,
13144        window: &mut Window,
13145        cx: &mut Context<Self>,
13146    ) {
13147        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13148
13149        let buffer = self.buffer.read(cx).snapshot(cx);
13150        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13151
13152        fn update_selection(
13153            selection: &Selection<usize>,
13154            buffer_snap: &MultiBufferSnapshot,
13155        ) -> Option<Selection<usize>> {
13156            let cursor = selection.head();
13157            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13158            for symbol in symbols.iter().rev() {
13159                let start = symbol.range.start.to_offset(buffer_snap);
13160                let end = symbol.range.end.to_offset(buffer_snap);
13161                let new_range = start..end;
13162                if start < selection.start || end > selection.end {
13163                    return Some(Selection {
13164                        id: selection.id,
13165                        start: new_range.start,
13166                        end: new_range.end,
13167                        goal: SelectionGoal::None,
13168                        reversed: selection.reversed,
13169                    });
13170                }
13171            }
13172            None
13173        }
13174
13175        let mut selected_larger_symbol = false;
13176        let new_selections = old_selections
13177            .iter()
13178            .map(|selection| match update_selection(selection, &buffer) {
13179                Some(new_selection) => {
13180                    if new_selection.range() != selection.range() {
13181                        selected_larger_symbol = true;
13182                    }
13183                    new_selection
13184                }
13185                None => selection.clone(),
13186            })
13187            .collect::<Vec<_>>();
13188
13189        if selected_larger_symbol {
13190            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13191                s.select(new_selections);
13192            });
13193        }
13194    }
13195
13196    pub fn select_larger_syntax_node(
13197        &mut self,
13198        _: &SelectLargerSyntaxNode,
13199        window: &mut Window,
13200        cx: &mut Context<Self>,
13201    ) {
13202        let Some(visible_row_count) = self.visible_row_count() else {
13203            return;
13204        };
13205        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13206        if old_selections.is_empty() {
13207            return;
13208        }
13209
13210        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13211
13212        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13213        let buffer = self.buffer.read(cx).snapshot(cx);
13214
13215        let mut selected_larger_node = false;
13216        let mut new_selections = old_selections
13217            .iter()
13218            .map(|selection| {
13219                let old_range = selection.start..selection.end;
13220
13221                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13222                    // manually select word at selection
13223                    if ["string_content", "inline"].contains(&node.kind()) {
13224                        let word_range = {
13225                            let display_point = buffer
13226                                .offset_to_point(old_range.start)
13227                                .to_display_point(&display_map);
13228                            let Range { start, end } =
13229                                movement::surrounding_word(&display_map, display_point);
13230                            start.to_point(&display_map).to_offset(&buffer)
13231                                ..end.to_point(&display_map).to_offset(&buffer)
13232                        };
13233                        // ignore if word is already selected
13234                        if !word_range.is_empty() && old_range != word_range {
13235                            let last_word_range = {
13236                                let display_point = buffer
13237                                    .offset_to_point(old_range.end)
13238                                    .to_display_point(&display_map);
13239                                let Range { start, end } =
13240                                    movement::surrounding_word(&display_map, display_point);
13241                                start.to_point(&display_map).to_offset(&buffer)
13242                                    ..end.to_point(&display_map).to_offset(&buffer)
13243                            };
13244                            // only select word if start and end point belongs to same word
13245                            if word_range == last_word_range {
13246                                selected_larger_node = true;
13247                                return Selection {
13248                                    id: selection.id,
13249                                    start: word_range.start,
13250                                    end: word_range.end,
13251                                    goal: SelectionGoal::None,
13252                                    reversed: selection.reversed,
13253                                };
13254                            }
13255                        }
13256                    }
13257                }
13258
13259                let mut new_range = old_range.clone();
13260                while let Some((_node, containing_range)) =
13261                    buffer.syntax_ancestor(new_range.clone())
13262                {
13263                    new_range = match containing_range {
13264                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13265                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13266                    };
13267                    if !display_map.intersects_fold(new_range.start)
13268                        && !display_map.intersects_fold(new_range.end)
13269                    {
13270                        break;
13271                    }
13272                }
13273
13274                selected_larger_node |= new_range != old_range;
13275                Selection {
13276                    id: selection.id,
13277                    start: new_range.start,
13278                    end: new_range.end,
13279                    goal: SelectionGoal::None,
13280                    reversed: selection.reversed,
13281                }
13282            })
13283            .collect::<Vec<_>>();
13284
13285        if !selected_larger_node {
13286            return; // don't put this call in the history
13287        }
13288
13289        // scroll based on transformation done to the last selection created by the user
13290        let (last_old, last_new) = old_selections
13291            .last()
13292            .zip(new_selections.last().cloned())
13293            .expect("old_selections isn't empty");
13294
13295        // revert selection
13296        let is_selection_reversed = {
13297            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13298            new_selections.last_mut().expect("checked above").reversed =
13299                should_newest_selection_be_reversed;
13300            should_newest_selection_be_reversed
13301        };
13302
13303        if selected_larger_node {
13304            self.select_syntax_node_history.disable_clearing = true;
13305            self.change_selections(None, window, cx, |s| {
13306                s.select(new_selections.clone());
13307            });
13308            self.select_syntax_node_history.disable_clearing = false;
13309        }
13310
13311        let start_row = last_new.start.to_display_point(&display_map).row().0;
13312        let end_row = last_new.end.to_display_point(&display_map).row().0;
13313        let selection_height = end_row - start_row + 1;
13314        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13315
13316        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13317        let scroll_behavior = if fits_on_the_screen {
13318            self.request_autoscroll(Autoscroll::fit(), cx);
13319            SelectSyntaxNodeScrollBehavior::FitSelection
13320        } else if is_selection_reversed {
13321            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13322            SelectSyntaxNodeScrollBehavior::CursorTop
13323        } else {
13324            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13325            SelectSyntaxNodeScrollBehavior::CursorBottom
13326        };
13327
13328        self.select_syntax_node_history.push((
13329            old_selections,
13330            scroll_behavior,
13331            is_selection_reversed,
13332        ));
13333    }
13334
13335    pub fn select_smaller_syntax_node(
13336        &mut self,
13337        _: &SelectSmallerSyntaxNode,
13338        window: &mut Window,
13339        cx: &mut Context<Self>,
13340    ) {
13341        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13342
13343        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13344            self.select_syntax_node_history.pop()
13345        {
13346            if let Some(selection) = selections.last_mut() {
13347                selection.reversed = is_selection_reversed;
13348            }
13349
13350            self.select_syntax_node_history.disable_clearing = true;
13351            self.change_selections(None, window, cx, |s| {
13352                s.select(selections.to_vec());
13353            });
13354            self.select_syntax_node_history.disable_clearing = false;
13355
13356            match scroll_behavior {
13357                SelectSyntaxNodeScrollBehavior::CursorTop => {
13358                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13359                }
13360                SelectSyntaxNodeScrollBehavior::FitSelection => {
13361                    self.request_autoscroll(Autoscroll::fit(), cx);
13362                }
13363                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13364                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13365                }
13366            }
13367        }
13368    }
13369
13370    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13371        if !EditorSettings::get_global(cx).gutter.runnables {
13372            self.clear_tasks();
13373            return Task::ready(());
13374        }
13375        let project = self.project.as_ref().map(Entity::downgrade);
13376        let task_sources = self.lsp_task_sources(cx);
13377        cx.spawn_in(window, async move |editor, cx| {
13378            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13379            let Some(project) = project.and_then(|p| p.upgrade()) else {
13380                return;
13381            };
13382            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13383                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13384            }) else {
13385                return;
13386            };
13387
13388            let hide_runnables = project
13389                .update(cx, |project, cx| {
13390                    // Do not display any test indicators in non-dev server remote projects.
13391                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13392                })
13393                .unwrap_or(true);
13394            if hide_runnables {
13395                return;
13396            }
13397            let new_rows =
13398                cx.background_spawn({
13399                    let snapshot = display_snapshot.clone();
13400                    async move {
13401                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13402                    }
13403                })
13404                    .await;
13405            let Ok(lsp_tasks) =
13406                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13407            else {
13408                return;
13409            };
13410            let lsp_tasks = lsp_tasks.await;
13411
13412            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13413                lsp_tasks
13414                    .into_iter()
13415                    .flat_map(|(kind, tasks)| {
13416                        tasks.into_iter().filter_map(move |(location, task)| {
13417                            Some((kind.clone(), location?, task))
13418                        })
13419                    })
13420                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13421                        let buffer = location.target.buffer;
13422                        let buffer_snapshot = buffer.read(cx).snapshot();
13423                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13424                            |(excerpt_id, snapshot, _)| {
13425                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13426                                    display_snapshot
13427                                        .buffer_snapshot
13428                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13429                                } else {
13430                                    None
13431                                }
13432                            },
13433                        );
13434                        if let Some(offset) = offset {
13435                            let task_buffer_range =
13436                                location.target.range.to_point(&buffer_snapshot);
13437                            let context_buffer_range =
13438                                task_buffer_range.to_offset(&buffer_snapshot);
13439                            let context_range = BufferOffset(context_buffer_range.start)
13440                                ..BufferOffset(context_buffer_range.end);
13441
13442                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13443                                .or_insert_with(|| RunnableTasks {
13444                                    templates: Vec::new(),
13445                                    offset,
13446                                    column: task_buffer_range.start.column,
13447                                    extra_variables: HashMap::default(),
13448                                    context_range,
13449                                })
13450                                .templates
13451                                .push((kind, task.original_task().clone()));
13452                        }
13453
13454                        acc
13455                    })
13456            }) else {
13457                return;
13458            };
13459
13460            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13461            editor
13462                .update(cx, |editor, _| {
13463                    editor.clear_tasks();
13464                    for (key, mut value) in rows {
13465                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13466                            value.templates.extend(lsp_tasks.templates);
13467                        }
13468
13469                        editor.insert_tasks(key, value);
13470                    }
13471                    for (key, value) in lsp_tasks_by_rows {
13472                        editor.insert_tasks(key, value);
13473                    }
13474                })
13475                .ok();
13476        })
13477    }
13478    fn fetch_runnable_ranges(
13479        snapshot: &DisplaySnapshot,
13480        range: Range<Anchor>,
13481    ) -> Vec<language::RunnableRange> {
13482        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13483    }
13484
13485    fn runnable_rows(
13486        project: Entity<Project>,
13487        snapshot: DisplaySnapshot,
13488        runnable_ranges: Vec<RunnableRange>,
13489        mut cx: AsyncWindowContext,
13490    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13491        runnable_ranges
13492            .into_iter()
13493            .filter_map(|mut runnable| {
13494                let tasks = cx
13495                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13496                    .ok()?;
13497                if tasks.is_empty() {
13498                    return None;
13499                }
13500
13501                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13502
13503                let row = snapshot
13504                    .buffer_snapshot
13505                    .buffer_line_for_row(MultiBufferRow(point.row))?
13506                    .1
13507                    .start
13508                    .row;
13509
13510                let context_range =
13511                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13512                Some((
13513                    (runnable.buffer_id, row),
13514                    RunnableTasks {
13515                        templates: tasks,
13516                        offset: snapshot
13517                            .buffer_snapshot
13518                            .anchor_before(runnable.run_range.start),
13519                        context_range,
13520                        column: point.column,
13521                        extra_variables: runnable.extra_captures,
13522                    },
13523                ))
13524            })
13525            .collect()
13526    }
13527
13528    fn templates_with_tags(
13529        project: &Entity<Project>,
13530        runnable: &mut Runnable,
13531        cx: &mut App,
13532    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13533        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13534            let (worktree_id, file) = project
13535                .buffer_for_id(runnable.buffer, cx)
13536                .and_then(|buffer| buffer.read(cx).file())
13537                .map(|file| (file.worktree_id(cx), file.clone()))
13538                .unzip();
13539
13540            (
13541                project.task_store().read(cx).task_inventory().cloned(),
13542                worktree_id,
13543                file,
13544            )
13545        });
13546
13547        let mut templates_with_tags = mem::take(&mut runnable.tags)
13548            .into_iter()
13549            .flat_map(|RunnableTag(tag)| {
13550                inventory
13551                    .as_ref()
13552                    .into_iter()
13553                    .flat_map(|inventory| {
13554                        inventory.read(cx).list_tasks(
13555                            file.clone(),
13556                            Some(runnable.language.clone()),
13557                            worktree_id,
13558                            cx,
13559                        )
13560                    })
13561                    .filter(move |(_, template)| {
13562                        template.tags.iter().any(|source_tag| source_tag == &tag)
13563                    })
13564            })
13565            .sorted_by_key(|(kind, _)| kind.to_owned())
13566            .collect::<Vec<_>>();
13567        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13568            // Strongest source wins; if we have worktree tag binding, prefer that to
13569            // global and language bindings;
13570            // if we have a global binding, prefer that to language binding.
13571            let first_mismatch = templates_with_tags
13572                .iter()
13573                .position(|(tag_source, _)| tag_source != leading_tag_source);
13574            if let Some(index) = first_mismatch {
13575                templates_with_tags.truncate(index);
13576            }
13577        }
13578
13579        templates_with_tags
13580    }
13581
13582    pub fn move_to_enclosing_bracket(
13583        &mut self,
13584        _: &MoveToEnclosingBracket,
13585        window: &mut Window,
13586        cx: &mut Context<Self>,
13587    ) {
13588        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13589        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13590            s.move_offsets_with(|snapshot, selection| {
13591                let Some(enclosing_bracket_ranges) =
13592                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13593                else {
13594                    return;
13595                };
13596
13597                let mut best_length = usize::MAX;
13598                let mut best_inside = false;
13599                let mut best_in_bracket_range = false;
13600                let mut best_destination = None;
13601                for (open, close) in enclosing_bracket_ranges {
13602                    let close = close.to_inclusive();
13603                    let length = close.end() - open.start;
13604                    let inside = selection.start >= open.end && selection.end <= *close.start();
13605                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13606                        || close.contains(&selection.head());
13607
13608                    // If best is next to a bracket and current isn't, skip
13609                    if !in_bracket_range && best_in_bracket_range {
13610                        continue;
13611                    }
13612
13613                    // Prefer smaller lengths unless best is inside and current isn't
13614                    if length > best_length && (best_inside || !inside) {
13615                        continue;
13616                    }
13617
13618                    best_length = length;
13619                    best_inside = inside;
13620                    best_in_bracket_range = in_bracket_range;
13621                    best_destination = Some(
13622                        if close.contains(&selection.start) && close.contains(&selection.end) {
13623                            if inside { open.end } else { open.start }
13624                        } else if inside {
13625                            *close.start()
13626                        } else {
13627                            *close.end()
13628                        },
13629                    );
13630                }
13631
13632                if let Some(destination) = best_destination {
13633                    selection.collapse_to(destination, SelectionGoal::None);
13634                }
13635            })
13636        });
13637    }
13638
13639    pub fn undo_selection(
13640        &mut self,
13641        _: &UndoSelection,
13642        window: &mut Window,
13643        cx: &mut Context<Self>,
13644    ) {
13645        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13646        self.end_selection(window, cx);
13647        self.selection_history.mode = SelectionHistoryMode::Undoing;
13648        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13649            self.change_selections(None, window, cx, |s| {
13650                s.select_anchors(entry.selections.to_vec())
13651            });
13652            self.select_next_state = entry.select_next_state;
13653            self.select_prev_state = entry.select_prev_state;
13654            self.add_selections_state = entry.add_selections_state;
13655            self.request_autoscroll(Autoscroll::newest(), cx);
13656        }
13657        self.selection_history.mode = SelectionHistoryMode::Normal;
13658    }
13659
13660    pub fn redo_selection(
13661        &mut self,
13662        _: &RedoSelection,
13663        window: &mut Window,
13664        cx: &mut Context<Self>,
13665    ) {
13666        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13667        self.end_selection(window, cx);
13668        self.selection_history.mode = SelectionHistoryMode::Redoing;
13669        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13670            self.change_selections(None, window, cx, |s| {
13671                s.select_anchors(entry.selections.to_vec())
13672            });
13673            self.select_next_state = entry.select_next_state;
13674            self.select_prev_state = entry.select_prev_state;
13675            self.add_selections_state = entry.add_selections_state;
13676            self.request_autoscroll(Autoscroll::newest(), cx);
13677        }
13678        self.selection_history.mode = SelectionHistoryMode::Normal;
13679    }
13680
13681    pub fn expand_excerpts(
13682        &mut self,
13683        action: &ExpandExcerpts,
13684        _: &mut Window,
13685        cx: &mut Context<Self>,
13686    ) {
13687        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13688    }
13689
13690    pub fn expand_excerpts_down(
13691        &mut self,
13692        action: &ExpandExcerptsDown,
13693        _: &mut Window,
13694        cx: &mut Context<Self>,
13695    ) {
13696        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13697    }
13698
13699    pub fn expand_excerpts_up(
13700        &mut self,
13701        action: &ExpandExcerptsUp,
13702        _: &mut Window,
13703        cx: &mut Context<Self>,
13704    ) {
13705        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13706    }
13707
13708    pub fn expand_excerpts_for_direction(
13709        &mut self,
13710        lines: u32,
13711        direction: ExpandExcerptDirection,
13712
13713        cx: &mut Context<Self>,
13714    ) {
13715        let selections = self.selections.disjoint_anchors();
13716
13717        let lines = if lines == 0 {
13718            EditorSettings::get_global(cx).expand_excerpt_lines
13719        } else {
13720            lines
13721        };
13722
13723        self.buffer.update(cx, |buffer, cx| {
13724            let snapshot = buffer.snapshot(cx);
13725            let mut excerpt_ids = selections
13726                .iter()
13727                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13728                .collect::<Vec<_>>();
13729            excerpt_ids.sort();
13730            excerpt_ids.dedup();
13731            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13732        })
13733    }
13734
13735    pub fn expand_excerpt(
13736        &mut self,
13737        excerpt: ExcerptId,
13738        direction: ExpandExcerptDirection,
13739        window: &mut Window,
13740        cx: &mut Context<Self>,
13741    ) {
13742        let current_scroll_position = self.scroll_position(cx);
13743        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13744        let mut should_scroll_up = false;
13745
13746        if direction == ExpandExcerptDirection::Down {
13747            let multi_buffer = self.buffer.read(cx);
13748            let snapshot = multi_buffer.snapshot(cx);
13749            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13750                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13751                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13752                        let buffer_snapshot = buffer.read(cx).snapshot();
13753                        let excerpt_end_row =
13754                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13755                        let last_row = buffer_snapshot.max_point().row;
13756                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13757                        should_scroll_up = lines_below >= lines_to_expand;
13758                    }
13759                }
13760            }
13761        }
13762
13763        self.buffer.update(cx, |buffer, cx| {
13764            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13765        });
13766
13767        if should_scroll_up {
13768            let new_scroll_position =
13769                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13770            self.set_scroll_position(new_scroll_position, window, cx);
13771        }
13772    }
13773
13774    pub fn go_to_singleton_buffer_point(
13775        &mut self,
13776        point: Point,
13777        window: &mut Window,
13778        cx: &mut Context<Self>,
13779    ) {
13780        self.go_to_singleton_buffer_range(point..point, window, cx);
13781    }
13782
13783    pub fn go_to_singleton_buffer_range(
13784        &mut self,
13785        range: Range<Point>,
13786        window: &mut Window,
13787        cx: &mut Context<Self>,
13788    ) {
13789        let multibuffer = self.buffer().read(cx);
13790        let Some(buffer) = multibuffer.as_singleton() else {
13791            return;
13792        };
13793        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13794            return;
13795        };
13796        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13797            return;
13798        };
13799        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13800            s.select_anchor_ranges([start..end])
13801        });
13802    }
13803
13804    pub fn go_to_diagnostic(
13805        &mut self,
13806        _: &GoToDiagnostic,
13807        window: &mut Window,
13808        cx: &mut Context<Self>,
13809    ) {
13810        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13811        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13812    }
13813
13814    pub fn go_to_prev_diagnostic(
13815        &mut self,
13816        _: &GoToPreviousDiagnostic,
13817        window: &mut Window,
13818        cx: &mut Context<Self>,
13819    ) {
13820        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13821        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13822    }
13823
13824    pub fn go_to_diagnostic_impl(
13825        &mut self,
13826        direction: Direction,
13827        window: &mut Window,
13828        cx: &mut Context<Self>,
13829    ) {
13830        let buffer = self.buffer.read(cx).snapshot(cx);
13831        let selection = self.selections.newest::<usize>(cx);
13832
13833        let mut active_group_id = None;
13834        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13835            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13836                active_group_id = Some(active_group.group_id);
13837            }
13838        }
13839
13840        fn filtered(
13841            snapshot: EditorSnapshot,
13842            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13843        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13844            diagnostics
13845                .filter(|entry| entry.range.start != entry.range.end)
13846                .filter(|entry| !entry.diagnostic.is_unnecessary)
13847                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13848        }
13849
13850        let snapshot = self.snapshot(window, cx);
13851        let before = filtered(
13852            snapshot.clone(),
13853            buffer
13854                .diagnostics_in_range(0..selection.start)
13855                .filter(|entry| entry.range.start <= selection.start),
13856        );
13857        let after = filtered(
13858            snapshot,
13859            buffer
13860                .diagnostics_in_range(selection.start..buffer.len())
13861                .filter(|entry| entry.range.start >= selection.start),
13862        );
13863
13864        let mut found: Option<DiagnosticEntry<usize>> = None;
13865        if direction == Direction::Prev {
13866            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13867            {
13868                for diagnostic in prev_diagnostics.into_iter().rev() {
13869                    if diagnostic.range.start != selection.start
13870                        || active_group_id
13871                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13872                    {
13873                        found = Some(diagnostic);
13874                        break 'outer;
13875                    }
13876                }
13877            }
13878        } else {
13879            for diagnostic in after.chain(before) {
13880                if diagnostic.range.start != selection.start
13881                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13882                {
13883                    found = Some(diagnostic);
13884                    break;
13885                }
13886            }
13887        }
13888        let Some(next_diagnostic) = found else {
13889            return;
13890        };
13891
13892        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13893            return;
13894        };
13895        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13896            s.select_ranges(vec![
13897                next_diagnostic.range.start..next_diagnostic.range.start,
13898            ])
13899        });
13900        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13901        self.refresh_inline_completion(false, true, window, cx);
13902    }
13903
13904    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13905        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13906        let snapshot = self.snapshot(window, cx);
13907        let selection = self.selections.newest::<Point>(cx);
13908        self.go_to_hunk_before_or_after_position(
13909            &snapshot,
13910            selection.head(),
13911            Direction::Next,
13912            window,
13913            cx,
13914        );
13915    }
13916
13917    pub fn go_to_hunk_before_or_after_position(
13918        &mut self,
13919        snapshot: &EditorSnapshot,
13920        position: Point,
13921        direction: Direction,
13922        window: &mut Window,
13923        cx: &mut Context<Editor>,
13924    ) {
13925        let row = if direction == Direction::Next {
13926            self.hunk_after_position(snapshot, position)
13927                .map(|hunk| hunk.row_range.start)
13928        } else {
13929            self.hunk_before_position(snapshot, position)
13930        };
13931
13932        if let Some(row) = row {
13933            let destination = Point::new(row.0, 0);
13934            let autoscroll = Autoscroll::center();
13935
13936            self.unfold_ranges(&[destination..destination], false, false, cx);
13937            self.change_selections(Some(autoscroll), window, cx, |s| {
13938                s.select_ranges([destination..destination]);
13939            });
13940        }
13941    }
13942
13943    fn hunk_after_position(
13944        &mut self,
13945        snapshot: &EditorSnapshot,
13946        position: Point,
13947    ) -> Option<MultiBufferDiffHunk> {
13948        snapshot
13949            .buffer_snapshot
13950            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13951            .find(|hunk| hunk.row_range.start.0 > position.row)
13952            .or_else(|| {
13953                snapshot
13954                    .buffer_snapshot
13955                    .diff_hunks_in_range(Point::zero()..position)
13956                    .find(|hunk| hunk.row_range.end.0 < position.row)
13957            })
13958    }
13959
13960    fn go_to_prev_hunk(
13961        &mut self,
13962        _: &GoToPreviousHunk,
13963        window: &mut Window,
13964        cx: &mut Context<Self>,
13965    ) {
13966        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13967        let snapshot = self.snapshot(window, cx);
13968        let selection = self.selections.newest::<Point>(cx);
13969        self.go_to_hunk_before_or_after_position(
13970            &snapshot,
13971            selection.head(),
13972            Direction::Prev,
13973            window,
13974            cx,
13975        );
13976    }
13977
13978    fn hunk_before_position(
13979        &mut self,
13980        snapshot: &EditorSnapshot,
13981        position: Point,
13982    ) -> Option<MultiBufferRow> {
13983        snapshot
13984            .buffer_snapshot
13985            .diff_hunk_before(position)
13986            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
13987    }
13988
13989    fn go_to_next_change(
13990        &mut self,
13991        _: &GoToNextChange,
13992        window: &mut Window,
13993        cx: &mut Context<Self>,
13994    ) {
13995        if let Some(selections) = self
13996            .change_list
13997            .next_change(1, Direction::Next)
13998            .map(|s| s.to_vec())
13999        {
14000            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14001                let map = s.display_map();
14002                s.select_display_ranges(selections.iter().map(|a| {
14003                    let point = a.to_display_point(&map);
14004                    point..point
14005                }))
14006            })
14007        }
14008    }
14009
14010    fn go_to_previous_change(
14011        &mut self,
14012        _: &GoToPreviousChange,
14013        window: &mut Window,
14014        cx: &mut Context<Self>,
14015    ) {
14016        if let Some(selections) = self
14017            .change_list
14018            .next_change(1, Direction::Prev)
14019            .map(|s| s.to_vec())
14020        {
14021            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14022                let map = s.display_map();
14023                s.select_display_ranges(selections.iter().map(|a| {
14024                    let point = a.to_display_point(&map);
14025                    point..point
14026                }))
14027            })
14028        }
14029    }
14030
14031    fn go_to_line<T: 'static>(
14032        &mut self,
14033        position: Anchor,
14034        highlight_color: Option<Hsla>,
14035        window: &mut Window,
14036        cx: &mut Context<Self>,
14037    ) {
14038        let snapshot = self.snapshot(window, cx).display_snapshot;
14039        let position = position.to_point(&snapshot.buffer_snapshot);
14040        let start = snapshot
14041            .buffer_snapshot
14042            .clip_point(Point::new(position.row, 0), Bias::Left);
14043        let end = start + Point::new(1, 0);
14044        let start = snapshot.buffer_snapshot.anchor_before(start);
14045        let end = snapshot.buffer_snapshot.anchor_before(end);
14046
14047        self.highlight_rows::<T>(
14048            start..end,
14049            highlight_color
14050                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14051            Default::default(),
14052            cx,
14053        );
14054
14055        if self.buffer.read(cx).is_singleton() {
14056            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14057        }
14058    }
14059
14060    pub fn go_to_definition(
14061        &mut self,
14062        _: &GoToDefinition,
14063        window: &mut Window,
14064        cx: &mut Context<Self>,
14065    ) -> Task<Result<Navigated>> {
14066        let definition =
14067            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14068        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14069        cx.spawn_in(window, async move |editor, cx| {
14070            if definition.await? == Navigated::Yes {
14071                return Ok(Navigated::Yes);
14072            }
14073            match fallback_strategy {
14074                GoToDefinitionFallback::None => Ok(Navigated::No),
14075                GoToDefinitionFallback::FindAllReferences => {
14076                    match editor.update_in(cx, |editor, window, cx| {
14077                        editor.find_all_references(&FindAllReferences, window, cx)
14078                    })? {
14079                        Some(references) => references.await,
14080                        None => Ok(Navigated::No),
14081                    }
14082                }
14083            }
14084        })
14085    }
14086
14087    pub fn go_to_declaration(
14088        &mut self,
14089        _: &GoToDeclaration,
14090        window: &mut Window,
14091        cx: &mut Context<Self>,
14092    ) -> Task<Result<Navigated>> {
14093        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14094    }
14095
14096    pub fn go_to_declaration_split(
14097        &mut self,
14098        _: &GoToDeclaration,
14099        window: &mut Window,
14100        cx: &mut Context<Self>,
14101    ) -> Task<Result<Navigated>> {
14102        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14103    }
14104
14105    pub fn go_to_implementation(
14106        &mut self,
14107        _: &GoToImplementation,
14108        window: &mut Window,
14109        cx: &mut Context<Self>,
14110    ) -> Task<Result<Navigated>> {
14111        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14112    }
14113
14114    pub fn go_to_implementation_split(
14115        &mut self,
14116        _: &GoToImplementationSplit,
14117        window: &mut Window,
14118        cx: &mut Context<Self>,
14119    ) -> Task<Result<Navigated>> {
14120        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14121    }
14122
14123    pub fn go_to_type_definition(
14124        &mut self,
14125        _: &GoToTypeDefinition,
14126        window: &mut Window,
14127        cx: &mut Context<Self>,
14128    ) -> Task<Result<Navigated>> {
14129        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14130    }
14131
14132    pub fn go_to_definition_split(
14133        &mut self,
14134        _: &GoToDefinitionSplit,
14135        window: &mut Window,
14136        cx: &mut Context<Self>,
14137    ) -> Task<Result<Navigated>> {
14138        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14139    }
14140
14141    pub fn go_to_type_definition_split(
14142        &mut self,
14143        _: &GoToTypeDefinitionSplit,
14144        window: &mut Window,
14145        cx: &mut Context<Self>,
14146    ) -> Task<Result<Navigated>> {
14147        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14148    }
14149
14150    fn go_to_definition_of_kind(
14151        &mut self,
14152        kind: GotoDefinitionKind,
14153        split: bool,
14154        window: &mut Window,
14155        cx: &mut Context<Self>,
14156    ) -> Task<Result<Navigated>> {
14157        let Some(provider) = self.semantics_provider.clone() else {
14158            return Task::ready(Ok(Navigated::No));
14159        };
14160        let head = self.selections.newest::<usize>(cx).head();
14161        let buffer = self.buffer.read(cx);
14162        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14163            text_anchor
14164        } else {
14165            return Task::ready(Ok(Navigated::No));
14166        };
14167
14168        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14169            return Task::ready(Ok(Navigated::No));
14170        };
14171
14172        cx.spawn_in(window, async move |editor, cx| {
14173            let definitions = definitions.await?;
14174            let navigated = editor
14175                .update_in(cx, |editor, window, cx| {
14176                    editor.navigate_to_hover_links(
14177                        Some(kind),
14178                        definitions
14179                            .into_iter()
14180                            .filter(|location| {
14181                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14182                            })
14183                            .map(HoverLink::Text)
14184                            .collect::<Vec<_>>(),
14185                        split,
14186                        window,
14187                        cx,
14188                    )
14189                })?
14190                .await?;
14191            anyhow::Ok(navigated)
14192        })
14193    }
14194
14195    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14196        let selection = self.selections.newest_anchor();
14197        let head = selection.head();
14198        let tail = selection.tail();
14199
14200        let Some((buffer, start_position)) =
14201            self.buffer.read(cx).text_anchor_for_position(head, cx)
14202        else {
14203            return;
14204        };
14205
14206        let end_position = if head != tail {
14207            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14208                return;
14209            };
14210            Some(pos)
14211        } else {
14212            None
14213        };
14214
14215        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14216            let url = if let Some(end_pos) = end_position {
14217                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14218            } else {
14219                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14220            };
14221
14222            if let Some(url) = url {
14223                editor.update(cx, |_, cx| {
14224                    cx.open_url(&url);
14225                })
14226            } else {
14227                Ok(())
14228            }
14229        });
14230
14231        url_finder.detach();
14232    }
14233
14234    pub fn open_selected_filename(
14235        &mut self,
14236        _: &OpenSelectedFilename,
14237        window: &mut Window,
14238        cx: &mut Context<Self>,
14239    ) {
14240        let Some(workspace) = self.workspace() else {
14241            return;
14242        };
14243
14244        let position = self.selections.newest_anchor().head();
14245
14246        let Some((buffer, buffer_position)) =
14247            self.buffer.read(cx).text_anchor_for_position(position, cx)
14248        else {
14249            return;
14250        };
14251
14252        let project = self.project.clone();
14253
14254        cx.spawn_in(window, async move |_, cx| {
14255            let result = find_file(&buffer, project, buffer_position, cx).await;
14256
14257            if let Some((_, path)) = result {
14258                workspace
14259                    .update_in(cx, |workspace, window, cx| {
14260                        workspace.open_resolved_path(path, window, cx)
14261                    })?
14262                    .await?;
14263            }
14264            anyhow::Ok(())
14265        })
14266        .detach();
14267    }
14268
14269    pub(crate) fn navigate_to_hover_links(
14270        &mut self,
14271        kind: Option<GotoDefinitionKind>,
14272        mut definitions: Vec<HoverLink>,
14273        split: bool,
14274        window: &mut Window,
14275        cx: &mut Context<Editor>,
14276    ) -> Task<Result<Navigated>> {
14277        // If there is one definition, just open it directly
14278        if definitions.len() == 1 {
14279            let definition = definitions.pop().unwrap();
14280
14281            enum TargetTaskResult {
14282                Location(Option<Location>),
14283                AlreadyNavigated,
14284            }
14285
14286            let target_task = match definition {
14287                HoverLink::Text(link) => {
14288                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14289                }
14290                HoverLink::InlayHint(lsp_location, server_id) => {
14291                    let computation =
14292                        self.compute_target_location(lsp_location, server_id, window, cx);
14293                    cx.background_spawn(async move {
14294                        let location = computation.await?;
14295                        Ok(TargetTaskResult::Location(location))
14296                    })
14297                }
14298                HoverLink::Url(url) => {
14299                    cx.open_url(&url);
14300                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14301                }
14302                HoverLink::File(path) => {
14303                    if let Some(workspace) = self.workspace() {
14304                        cx.spawn_in(window, async move |_, cx| {
14305                            workspace
14306                                .update_in(cx, |workspace, window, cx| {
14307                                    workspace.open_resolved_path(path, window, cx)
14308                                })?
14309                                .await
14310                                .map(|_| TargetTaskResult::AlreadyNavigated)
14311                        })
14312                    } else {
14313                        Task::ready(Ok(TargetTaskResult::Location(None)))
14314                    }
14315                }
14316            };
14317            cx.spawn_in(window, async move |editor, cx| {
14318                let target = match target_task.await.context("target resolution task")? {
14319                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14320                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14321                    TargetTaskResult::Location(Some(target)) => target,
14322                };
14323
14324                editor.update_in(cx, |editor, window, cx| {
14325                    let Some(workspace) = editor.workspace() else {
14326                        return Navigated::No;
14327                    };
14328                    let pane = workspace.read(cx).active_pane().clone();
14329
14330                    let range = target.range.to_point(target.buffer.read(cx));
14331                    let range = editor.range_for_match(&range);
14332                    let range = collapse_multiline_range(range);
14333
14334                    if !split
14335                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14336                    {
14337                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14338                    } else {
14339                        window.defer(cx, move |window, cx| {
14340                            let target_editor: Entity<Self> =
14341                                workspace.update(cx, |workspace, cx| {
14342                                    let pane = if split {
14343                                        workspace.adjacent_pane(window, cx)
14344                                    } else {
14345                                        workspace.active_pane().clone()
14346                                    };
14347
14348                                    workspace.open_project_item(
14349                                        pane,
14350                                        target.buffer.clone(),
14351                                        true,
14352                                        true,
14353                                        window,
14354                                        cx,
14355                                    )
14356                                });
14357                            target_editor.update(cx, |target_editor, cx| {
14358                                // When selecting a definition in a different buffer, disable the nav history
14359                                // to avoid creating a history entry at the previous cursor location.
14360                                pane.update(cx, |pane, _| pane.disable_history());
14361                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14362                                pane.update(cx, |pane, _| pane.enable_history());
14363                            });
14364                        });
14365                    }
14366                    Navigated::Yes
14367                })
14368            })
14369        } else if !definitions.is_empty() {
14370            cx.spawn_in(window, async move |editor, cx| {
14371                let (title, location_tasks, workspace) = editor
14372                    .update_in(cx, |editor, window, cx| {
14373                        let tab_kind = match kind {
14374                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14375                            _ => "Definitions",
14376                        };
14377                        let title = definitions
14378                            .iter()
14379                            .find_map(|definition| match definition {
14380                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14381                                    let buffer = origin.buffer.read(cx);
14382                                    format!(
14383                                        "{} for {}",
14384                                        tab_kind,
14385                                        buffer
14386                                            .text_for_range(origin.range.clone())
14387                                            .collect::<String>()
14388                                    )
14389                                }),
14390                                HoverLink::InlayHint(_, _) => None,
14391                                HoverLink::Url(_) => None,
14392                                HoverLink::File(_) => None,
14393                            })
14394                            .unwrap_or(tab_kind.to_string());
14395                        let location_tasks = definitions
14396                            .into_iter()
14397                            .map(|definition| match definition {
14398                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14399                                HoverLink::InlayHint(lsp_location, server_id) => editor
14400                                    .compute_target_location(lsp_location, server_id, window, cx),
14401                                HoverLink::Url(_) => Task::ready(Ok(None)),
14402                                HoverLink::File(_) => Task::ready(Ok(None)),
14403                            })
14404                            .collect::<Vec<_>>();
14405                        (title, location_tasks, editor.workspace().clone())
14406                    })
14407                    .context("location tasks preparation")?;
14408
14409                let locations = future::join_all(location_tasks)
14410                    .await
14411                    .into_iter()
14412                    .filter_map(|location| location.transpose())
14413                    .collect::<Result<_>>()
14414                    .context("location tasks")?;
14415
14416                let Some(workspace) = workspace else {
14417                    return Ok(Navigated::No);
14418                };
14419                let opened = workspace
14420                    .update_in(cx, |workspace, window, cx| {
14421                        Self::open_locations_in_multibuffer(
14422                            workspace,
14423                            locations,
14424                            title,
14425                            split,
14426                            MultibufferSelectionMode::First,
14427                            window,
14428                            cx,
14429                        )
14430                    })
14431                    .ok();
14432
14433                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14434            })
14435        } else {
14436            Task::ready(Ok(Navigated::No))
14437        }
14438    }
14439
14440    fn compute_target_location(
14441        &self,
14442        lsp_location: lsp::Location,
14443        server_id: LanguageServerId,
14444        window: &mut Window,
14445        cx: &mut Context<Self>,
14446    ) -> Task<anyhow::Result<Option<Location>>> {
14447        let Some(project) = self.project.clone() else {
14448            return Task::ready(Ok(None));
14449        };
14450
14451        cx.spawn_in(window, async move |editor, cx| {
14452            let location_task = editor.update(cx, |_, cx| {
14453                project.update(cx, |project, cx| {
14454                    let language_server_name = project
14455                        .language_server_statuses(cx)
14456                        .find(|(id, _)| server_id == *id)
14457                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14458                    language_server_name.map(|language_server_name| {
14459                        project.open_local_buffer_via_lsp(
14460                            lsp_location.uri.clone(),
14461                            server_id,
14462                            language_server_name,
14463                            cx,
14464                        )
14465                    })
14466                })
14467            })?;
14468            let location = match location_task {
14469                Some(task) => Some({
14470                    let target_buffer_handle = task.await.context("open local buffer")?;
14471                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14472                        let target_start = target_buffer
14473                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14474                        let target_end = target_buffer
14475                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14476                        target_buffer.anchor_after(target_start)
14477                            ..target_buffer.anchor_before(target_end)
14478                    })?;
14479                    Location {
14480                        buffer: target_buffer_handle,
14481                        range,
14482                    }
14483                }),
14484                None => None,
14485            };
14486            Ok(location)
14487        })
14488    }
14489
14490    pub fn find_all_references(
14491        &mut self,
14492        _: &FindAllReferences,
14493        window: &mut Window,
14494        cx: &mut Context<Self>,
14495    ) -> Option<Task<Result<Navigated>>> {
14496        let selection = self.selections.newest::<usize>(cx);
14497        let multi_buffer = self.buffer.read(cx);
14498        let head = selection.head();
14499
14500        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14501        let head_anchor = multi_buffer_snapshot.anchor_at(
14502            head,
14503            if head < selection.tail() {
14504                Bias::Right
14505            } else {
14506                Bias::Left
14507            },
14508        );
14509
14510        match self
14511            .find_all_references_task_sources
14512            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14513        {
14514            Ok(_) => {
14515                log::info!(
14516                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14517                );
14518                return None;
14519            }
14520            Err(i) => {
14521                self.find_all_references_task_sources.insert(i, head_anchor);
14522            }
14523        }
14524
14525        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14526        let workspace = self.workspace()?;
14527        let project = workspace.read(cx).project().clone();
14528        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14529        Some(cx.spawn_in(window, async move |editor, cx| {
14530            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14531                if let Ok(i) = editor
14532                    .find_all_references_task_sources
14533                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14534                {
14535                    editor.find_all_references_task_sources.remove(i);
14536                }
14537            });
14538
14539            let locations = references.await?;
14540            if locations.is_empty() {
14541                return anyhow::Ok(Navigated::No);
14542            }
14543
14544            workspace.update_in(cx, |workspace, window, cx| {
14545                let title = locations
14546                    .first()
14547                    .as_ref()
14548                    .map(|location| {
14549                        let buffer = location.buffer.read(cx);
14550                        format!(
14551                            "References to `{}`",
14552                            buffer
14553                                .text_for_range(location.range.clone())
14554                                .collect::<String>()
14555                        )
14556                    })
14557                    .unwrap();
14558                Self::open_locations_in_multibuffer(
14559                    workspace,
14560                    locations,
14561                    title,
14562                    false,
14563                    MultibufferSelectionMode::First,
14564                    window,
14565                    cx,
14566                );
14567                Navigated::Yes
14568            })
14569        }))
14570    }
14571
14572    /// Opens a multibuffer with the given project locations in it
14573    pub fn open_locations_in_multibuffer(
14574        workspace: &mut Workspace,
14575        mut locations: Vec<Location>,
14576        title: String,
14577        split: bool,
14578        multibuffer_selection_mode: MultibufferSelectionMode,
14579        window: &mut Window,
14580        cx: &mut Context<Workspace>,
14581    ) {
14582        // If there are multiple definitions, open them in a multibuffer
14583        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14584        let mut locations = locations.into_iter().peekable();
14585        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14586        let capability = workspace.project().read(cx).capability();
14587
14588        let excerpt_buffer = cx.new(|cx| {
14589            let mut multibuffer = MultiBuffer::new(capability);
14590            while let Some(location) = locations.next() {
14591                let buffer = location.buffer.read(cx);
14592                let mut ranges_for_buffer = Vec::new();
14593                let range = location.range.to_point(buffer);
14594                ranges_for_buffer.push(range.clone());
14595
14596                while let Some(next_location) = locations.peek() {
14597                    if next_location.buffer == location.buffer {
14598                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14599                        locations.next();
14600                    } else {
14601                        break;
14602                    }
14603                }
14604
14605                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14606                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14607                    PathKey::for_buffer(&location.buffer, cx),
14608                    location.buffer.clone(),
14609                    ranges_for_buffer,
14610                    DEFAULT_MULTIBUFFER_CONTEXT,
14611                    cx,
14612                );
14613                ranges.extend(new_ranges)
14614            }
14615
14616            multibuffer.with_title(title)
14617        });
14618
14619        let editor = cx.new(|cx| {
14620            Editor::for_multibuffer(
14621                excerpt_buffer,
14622                Some(workspace.project().clone()),
14623                window,
14624                cx,
14625            )
14626        });
14627        editor.update(cx, |editor, cx| {
14628            match multibuffer_selection_mode {
14629                MultibufferSelectionMode::First => {
14630                    if let Some(first_range) = ranges.first() {
14631                        editor.change_selections(None, window, cx, |selections| {
14632                            selections.clear_disjoint();
14633                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14634                        });
14635                    }
14636                    editor.highlight_background::<Self>(
14637                        &ranges,
14638                        |theme| theme.editor_highlighted_line_background,
14639                        cx,
14640                    );
14641                }
14642                MultibufferSelectionMode::All => {
14643                    editor.change_selections(None, window, cx, |selections| {
14644                        selections.clear_disjoint();
14645                        selections.select_anchor_ranges(ranges);
14646                    });
14647                }
14648            }
14649            editor.register_buffers_with_language_servers(cx);
14650        });
14651
14652        let item = Box::new(editor);
14653        let item_id = item.item_id();
14654
14655        if split {
14656            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14657        } else {
14658            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14659                let (preview_item_id, preview_item_idx) =
14660                    workspace.active_pane().update(cx, |pane, _| {
14661                        (pane.preview_item_id(), pane.preview_item_idx())
14662                    });
14663
14664                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14665
14666                if let Some(preview_item_id) = preview_item_id {
14667                    workspace.active_pane().update(cx, |pane, cx| {
14668                        pane.remove_item(preview_item_id, false, false, window, cx);
14669                    });
14670                }
14671            } else {
14672                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14673            }
14674        }
14675        workspace.active_pane().update(cx, |pane, cx| {
14676            pane.set_preview_item_id(Some(item_id), cx);
14677        });
14678    }
14679
14680    pub fn rename(
14681        &mut self,
14682        _: &Rename,
14683        window: &mut Window,
14684        cx: &mut Context<Self>,
14685    ) -> Option<Task<Result<()>>> {
14686        use language::ToOffset as _;
14687
14688        let provider = self.semantics_provider.clone()?;
14689        let selection = self.selections.newest_anchor().clone();
14690        let (cursor_buffer, cursor_buffer_position) = self
14691            .buffer
14692            .read(cx)
14693            .text_anchor_for_position(selection.head(), cx)?;
14694        let (tail_buffer, cursor_buffer_position_end) = self
14695            .buffer
14696            .read(cx)
14697            .text_anchor_for_position(selection.tail(), cx)?;
14698        if tail_buffer != cursor_buffer {
14699            return None;
14700        }
14701
14702        let snapshot = cursor_buffer.read(cx).snapshot();
14703        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14704        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14705        let prepare_rename = provider
14706            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14707            .unwrap_or_else(|| Task::ready(Ok(None)));
14708        drop(snapshot);
14709
14710        Some(cx.spawn_in(window, async move |this, cx| {
14711            let rename_range = if let Some(range) = prepare_rename.await? {
14712                Some(range)
14713            } else {
14714                this.update(cx, |this, cx| {
14715                    let buffer = this.buffer.read(cx).snapshot(cx);
14716                    let mut buffer_highlights = this
14717                        .document_highlights_for_position(selection.head(), &buffer)
14718                        .filter(|highlight| {
14719                            highlight.start.excerpt_id == selection.head().excerpt_id
14720                                && highlight.end.excerpt_id == selection.head().excerpt_id
14721                        });
14722                    buffer_highlights
14723                        .next()
14724                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14725                })?
14726            };
14727            if let Some(rename_range) = rename_range {
14728                this.update_in(cx, |this, window, cx| {
14729                    let snapshot = cursor_buffer.read(cx).snapshot();
14730                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14731                    let cursor_offset_in_rename_range =
14732                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14733                    let cursor_offset_in_rename_range_end =
14734                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14735
14736                    this.take_rename(false, window, cx);
14737                    let buffer = this.buffer.read(cx).read(cx);
14738                    let cursor_offset = selection.head().to_offset(&buffer);
14739                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14740                    let rename_end = rename_start + rename_buffer_range.len();
14741                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14742                    let mut old_highlight_id = None;
14743                    let old_name: Arc<str> = buffer
14744                        .chunks(rename_start..rename_end, true)
14745                        .map(|chunk| {
14746                            if old_highlight_id.is_none() {
14747                                old_highlight_id = chunk.syntax_highlight_id;
14748                            }
14749                            chunk.text
14750                        })
14751                        .collect::<String>()
14752                        .into();
14753
14754                    drop(buffer);
14755
14756                    // Position the selection in the rename editor so that it matches the current selection.
14757                    this.show_local_selections = false;
14758                    let rename_editor = cx.new(|cx| {
14759                        let mut editor = Editor::single_line(window, cx);
14760                        editor.buffer.update(cx, |buffer, cx| {
14761                            buffer.edit([(0..0, old_name.clone())], None, cx)
14762                        });
14763                        let rename_selection_range = match cursor_offset_in_rename_range
14764                            .cmp(&cursor_offset_in_rename_range_end)
14765                        {
14766                            Ordering::Equal => {
14767                                editor.select_all(&SelectAll, window, cx);
14768                                return editor;
14769                            }
14770                            Ordering::Less => {
14771                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14772                            }
14773                            Ordering::Greater => {
14774                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14775                            }
14776                        };
14777                        if rename_selection_range.end > old_name.len() {
14778                            editor.select_all(&SelectAll, window, cx);
14779                        } else {
14780                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14781                                s.select_ranges([rename_selection_range]);
14782                            });
14783                        }
14784                        editor
14785                    });
14786                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14787                        if e == &EditorEvent::Focused {
14788                            cx.emit(EditorEvent::FocusedIn)
14789                        }
14790                    })
14791                    .detach();
14792
14793                    let write_highlights =
14794                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14795                    let read_highlights =
14796                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14797                    let ranges = write_highlights
14798                        .iter()
14799                        .flat_map(|(_, ranges)| ranges.iter())
14800                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14801                        .cloned()
14802                        .collect();
14803
14804                    this.highlight_text::<Rename>(
14805                        ranges,
14806                        HighlightStyle {
14807                            fade_out: Some(0.6),
14808                            ..Default::default()
14809                        },
14810                        cx,
14811                    );
14812                    let rename_focus_handle = rename_editor.focus_handle(cx);
14813                    window.focus(&rename_focus_handle);
14814                    let block_id = this.insert_blocks(
14815                        [BlockProperties {
14816                            style: BlockStyle::Flex,
14817                            placement: BlockPlacement::Below(range.start),
14818                            height: Some(1),
14819                            render: Arc::new({
14820                                let rename_editor = rename_editor.clone();
14821                                move |cx: &mut BlockContext| {
14822                                    let mut text_style = cx.editor_style.text.clone();
14823                                    if let Some(highlight_style) = old_highlight_id
14824                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14825                                    {
14826                                        text_style = text_style.highlight(highlight_style);
14827                                    }
14828                                    div()
14829                                        .block_mouse_down()
14830                                        .pl(cx.anchor_x)
14831                                        .child(EditorElement::new(
14832                                            &rename_editor,
14833                                            EditorStyle {
14834                                                background: cx.theme().system().transparent,
14835                                                local_player: cx.editor_style.local_player,
14836                                                text: text_style,
14837                                                scrollbar_width: cx.editor_style.scrollbar_width,
14838                                                syntax: cx.editor_style.syntax.clone(),
14839                                                status: cx.editor_style.status.clone(),
14840                                                inlay_hints_style: HighlightStyle {
14841                                                    font_weight: Some(FontWeight::BOLD),
14842                                                    ..make_inlay_hints_style(cx.app)
14843                                                },
14844                                                inline_completion_styles: make_suggestion_styles(
14845                                                    cx.app,
14846                                                ),
14847                                                ..EditorStyle::default()
14848                                            },
14849                                        ))
14850                                        .into_any_element()
14851                                }
14852                            }),
14853                            priority: 0,
14854                            render_in_minimap: true,
14855                        }],
14856                        Some(Autoscroll::fit()),
14857                        cx,
14858                    )[0];
14859                    this.pending_rename = Some(RenameState {
14860                        range,
14861                        old_name,
14862                        editor: rename_editor,
14863                        block_id,
14864                    });
14865                })?;
14866            }
14867
14868            Ok(())
14869        }))
14870    }
14871
14872    pub fn confirm_rename(
14873        &mut self,
14874        _: &ConfirmRename,
14875        window: &mut Window,
14876        cx: &mut Context<Self>,
14877    ) -> Option<Task<Result<()>>> {
14878        let rename = self.take_rename(false, window, cx)?;
14879        let workspace = self.workspace()?.downgrade();
14880        let (buffer, start) = self
14881            .buffer
14882            .read(cx)
14883            .text_anchor_for_position(rename.range.start, cx)?;
14884        let (end_buffer, _) = self
14885            .buffer
14886            .read(cx)
14887            .text_anchor_for_position(rename.range.end, cx)?;
14888        if buffer != end_buffer {
14889            return None;
14890        }
14891
14892        let old_name = rename.old_name;
14893        let new_name = rename.editor.read(cx).text(cx);
14894
14895        let rename = self.semantics_provider.as_ref()?.perform_rename(
14896            &buffer,
14897            start,
14898            new_name.clone(),
14899            cx,
14900        )?;
14901
14902        Some(cx.spawn_in(window, async move |editor, cx| {
14903            let project_transaction = rename.await?;
14904            Self::open_project_transaction(
14905                &editor,
14906                workspace,
14907                project_transaction,
14908                format!("Rename: {}{}", old_name, new_name),
14909                cx,
14910            )
14911            .await?;
14912
14913            editor.update(cx, |editor, cx| {
14914                editor.refresh_document_highlights(cx);
14915            })?;
14916            Ok(())
14917        }))
14918    }
14919
14920    fn take_rename(
14921        &mut self,
14922        moving_cursor: bool,
14923        window: &mut Window,
14924        cx: &mut Context<Self>,
14925    ) -> Option<RenameState> {
14926        let rename = self.pending_rename.take()?;
14927        if rename.editor.focus_handle(cx).is_focused(window) {
14928            window.focus(&self.focus_handle);
14929        }
14930
14931        self.remove_blocks(
14932            [rename.block_id].into_iter().collect(),
14933            Some(Autoscroll::fit()),
14934            cx,
14935        );
14936        self.clear_highlights::<Rename>(cx);
14937        self.show_local_selections = true;
14938
14939        if moving_cursor {
14940            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14941                editor.selections.newest::<usize>(cx).head()
14942            });
14943
14944            // Update the selection to match the position of the selection inside
14945            // the rename editor.
14946            let snapshot = self.buffer.read(cx).read(cx);
14947            let rename_range = rename.range.to_offset(&snapshot);
14948            let cursor_in_editor = snapshot
14949                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14950                .min(rename_range.end);
14951            drop(snapshot);
14952
14953            self.change_selections(None, window, cx, |s| {
14954                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14955            });
14956        } else {
14957            self.refresh_document_highlights(cx);
14958        }
14959
14960        Some(rename)
14961    }
14962
14963    pub fn pending_rename(&self) -> Option<&RenameState> {
14964        self.pending_rename.as_ref()
14965    }
14966
14967    fn format(
14968        &mut self,
14969        _: &Format,
14970        window: &mut Window,
14971        cx: &mut Context<Self>,
14972    ) -> Option<Task<Result<()>>> {
14973        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14974
14975        let project = match &self.project {
14976            Some(project) => project.clone(),
14977            None => return None,
14978        };
14979
14980        Some(self.perform_format(
14981            project,
14982            FormatTrigger::Manual,
14983            FormatTarget::Buffers,
14984            window,
14985            cx,
14986        ))
14987    }
14988
14989    fn format_selections(
14990        &mut self,
14991        _: &FormatSelections,
14992        window: &mut Window,
14993        cx: &mut Context<Self>,
14994    ) -> Option<Task<Result<()>>> {
14995        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14996
14997        let project = match &self.project {
14998            Some(project) => project.clone(),
14999            None => return None,
15000        };
15001
15002        let ranges = self
15003            .selections
15004            .all_adjusted(cx)
15005            .into_iter()
15006            .map(|selection| selection.range())
15007            .collect_vec();
15008
15009        Some(self.perform_format(
15010            project,
15011            FormatTrigger::Manual,
15012            FormatTarget::Ranges(ranges),
15013            window,
15014            cx,
15015        ))
15016    }
15017
15018    fn perform_format(
15019        &mut self,
15020        project: Entity<Project>,
15021        trigger: FormatTrigger,
15022        target: FormatTarget,
15023        window: &mut Window,
15024        cx: &mut Context<Self>,
15025    ) -> Task<Result<()>> {
15026        let buffer = self.buffer.clone();
15027        let (buffers, target) = match target {
15028            FormatTarget::Buffers => {
15029                let mut buffers = buffer.read(cx).all_buffers();
15030                if trigger == FormatTrigger::Save {
15031                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15032                }
15033                (buffers, LspFormatTarget::Buffers)
15034            }
15035            FormatTarget::Ranges(selection_ranges) => {
15036                let multi_buffer = buffer.read(cx);
15037                let snapshot = multi_buffer.read(cx);
15038                let mut buffers = HashSet::default();
15039                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15040                    BTreeMap::new();
15041                for selection_range in selection_ranges {
15042                    for (buffer, buffer_range, _) in
15043                        snapshot.range_to_buffer_ranges(selection_range)
15044                    {
15045                        let buffer_id = buffer.remote_id();
15046                        let start = buffer.anchor_before(buffer_range.start);
15047                        let end = buffer.anchor_after(buffer_range.end);
15048                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15049                        buffer_id_to_ranges
15050                            .entry(buffer_id)
15051                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15052                            .or_insert_with(|| vec![start..end]);
15053                    }
15054                }
15055                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15056            }
15057        };
15058
15059        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15060        let selections_prev = transaction_id_prev
15061            .and_then(|transaction_id_prev| {
15062                // default to selections as they were after the last edit, if we have them,
15063                // instead of how they are now.
15064                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15065                // will take you back to where you made the last edit, instead of staying where you scrolled
15066                self.selection_history
15067                    .transaction(transaction_id_prev)
15068                    .map(|t| t.0.clone())
15069            })
15070            .unwrap_or_else(|| {
15071                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15072                self.selections.disjoint_anchors()
15073            });
15074
15075        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15076        let format = project.update(cx, |project, cx| {
15077            project.format(buffers, target, true, trigger, cx)
15078        });
15079
15080        cx.spawn_in(window, async move |editor, cx| {
15081            let transaction = futures::select_biased! {
15082                transaction = format.log_err().fuse() => transaction,
15083                () = timeout => {
15084                    log::warn!("timed out waiting for formatting");
15085                    None
15086                }
15087            };
15088
15089            buffer
15090                .update(cx, |buffer, cx| {
15091                    if let Some(transaction) = transaction {
15092                        if !buffer.is_singleton() {
15093                            buffer.push_transaction(&transaction.0, cx);
15094                        }
15095                    }
15096                    cx.notify();
15097                })
15098                .ok();
15099
15100            if let Some(transaction_id_now) =
15101                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15102            {
15103                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15104                if has_new_transaction {
15105                    _ = editor.update(cx, |editor, _| {
15106                        editor
15107                            .selection_history
15108                            .insert_transaction(transaction_id_now, selections_prev);
15109                    });
15110                }
15111            }
15112
15113            Ok(())
15114        })
15115    }
15116
15117    fn organize_imports(
15118        &mut self,
15119        _: &OrganizeImports,
15120        window: &mut Window,
15121        cx: &mut Context<Self>,
15122    ) -> Option<Task<Result<()>>> {
15123        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15124        let project = match &self.project {
15125            Some(project) => project.clone(),
15126            None => return None,
15127        };
15128        Some(self.perform_code_action_kind(
15129            project,
15130            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15131            window,
15132            cx,
15133        ))
15134    }
15135
15136    fn perform_code_action_kind(
15137        &mut self,
15138        project: Entity<Project>,
15139        kind: CodeActionKind,
15140        window: &mut Window,
15141        cx: &mut Context<Self>,
15142    ) -> Task<Result<()>> {
15143        let buffer = self.buffer.clone();
15144        let buffers = buffer.read(cx).all_buffers();
15145        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15146        let apply_action = project.update(cx, |project, cx| {
15147            project.apply_code_action_kind(buffers, kind, true, cx)
15148        });
15149        cx.spawn_in(window, async move |_, cx| {
15150            let transaction = futures::select_biased! {
15151                () = timeout => {
15152                    log::warn!("timed out waiting for executing code action");
15153                    None
15154                }
15155                transaction = apply_action.log_err().fuse() => transaction,
15156            };
15157            buffer
15158                .update(cx, |buffer, cx| {
15159                    // check if we need this
15160                    if let Some(transaction) = transaction {
15161                        if !buffer.is_singleton() {
15162                            buffer.push_transaction(&transaction.0, cx);
15163                        }
15164                    }
15165                    cx.notify();
15166                })
15167                .ok();
15168            Ok(())
15169        })
15170    }
15171
15172    fn restart_language_server(
15173        &mut self,
15174        _: &RestartLanguageServer,
15175        _: &mut Window,
15176        cx: &mut Context<Self>,
15177    ) {
15178        if let Some(project) = self.project.clone() {
15179            self.buffer.update(cx, |multi_buffer, cx| {
15180                project.update(cx, |project, cx| {
15181                    project.restart_language_servers_for_buffers(
15182                        multi_buffer.all_buffers().into_iter().collect(),
15183                        cx,
15184                    );
15185                });
15186            })
15187        }
15188    }
15189
15190    fn stop_language_server(
15191        &mut self,
15192        _: &StopLanguageServer,
15193        _: &mut Window,
15194        cx: &mut Context<Self>,
15195    ) {
15196        if let Some(project) = self.project.clone() {
15197            self.buffer.update(cx, |multi_buffer, cx| {
15198                project.update(cx, |project, cx| {
15199                    project.stop_language_servers_for_buffers(
15200                        multi_buffer.all_buffers().into_iter().collect(),
15201                        cx,
15202                    );
15203                    cx.emit(project::Event::RefreshInlayHints);
15204                });
15205            });
15206        }
15207    }
15208
15209    fn cancel_language_server_work(
15210        workspace: &mut Workspace,
15211        _: &actions::CancelLanguageServerWork,
15212        _: &mut Window,
15213        cx: &mut Context<Workspace>,
15214    ) {
15215        let project = workspace.project();
15216        let buffers = workspace
15217            .active_item(cx)
15218            .and_then(|item| item.act_as::<Editor>(cx))
15219            .map_or(HashSet::default(), |editor| {
15220                editor.read(cx).buffer.read(cx).all_buffers()
15221            });
15222        project.update(cx, |project, cx| {
15223            project.cancel_language_server_work_for_buffers(buffers, cx);
15224        });
15225    }
15226
15227    fn show_character_palette(
15228        &mut self,
15229        _: &ShowCharacterPalette,
15230        window: &mut Window,
15231        _: &mut Context<Self>,
15232    ) {
15233        window.show_character_palette();
15234    }
15235
15236    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15237        if self.mode.is_minimap() {
15238            return;
15239        }
15240
15241        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15242            let buffer = self.buffer.read(cx).snapshot(cx);
15243            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15244            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15245            let is_valid = buffer
15246                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15247                .any(|entry| {
15248                    entry.diagnostic.is_primary
15249                        && !entry.range.is_empty()
15250                        && entry.range.start == primary_range_start
15251                        && entry.diagnostic.message == active_diagnostics.active_message
15252                });
15253
15254            if !is_valid {
15255                self.dismiss_diagnostics(cx);
15256            }
15257        }
15258    }
15259
15260    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15261        match &self.active_diagnostics {
15262            ActiveDiagnostic::Group(group) => Some(group),
15263            _ => None,
15264        }
15265    }
15266
15267    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15268        self.dismiss_diagnostics(cx);
15269        self.active_diagnostics = ActiveDiagnostic::All;
15270    }
15271
15272    fn activate_diagnostics(
15273        &mut self,
15274        buffer_id: BufferId,
15275        diagnostic: DiagnosticEntry<usize>,
15276        window: &mut Window,
15277        cx: &mut Context<Self>,
15278    ) {
15279        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15280            return;
15281        }
15282        self.dismiss_diagnostics(cx);
15283        let snapshot = self.snapshot(window, cx);
15284        let buffer = self.buffer.read(cx).snapshot(cx);
15285        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15286            return;
15287        };
15288
15289        let diagnostic_group = buffer
15290            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15291            .collect::<Vec<_>>();
15292
15293        let blocks =
15294            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15295
15296        let blocks = self.display_map.update(cx, |display_map, cx| {
15297            display_map.insert_blocks(blocks, cx).into_iter().collect()
15298        });
15299        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15300            active_range: buffer.anchor_before(diagnostic.range.start)
15301                ..buffer.anchor_after(diagnostic.range.end),
15302            active_message: diagnostic.diagnostic.message.clone(),
15303            group_id: diagnostic.diagnostic.group_id,
15304            blocks,
15305        });
15306        cx.notify();
15307    }
15308
15309    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15310        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15311            return;
15312        };
15313
15314        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15315        if let ActiveDiagnostic::Group(group) = prev {
15316            self.display_map.update(cx, |display_map, cx| {
15317                display_map.remove_blocks(group.blocks, cx);
15318            });
15319            cx.notify();
15320        }
15321    }
15322
15323    /// Disable inline diagnostics rendering for this editor.
15324    pub fn disable_inline_diagnostics(&mut self) {
15325        self.inline_diagnostics_enabled = false;
15326        self.inline_diagnostics_update = Task::ready(());
15327        self.inline_diagnostics.clear();
15328    }
15329
15330    pub fn diagnostics_enabled(&self) -> bool {
15331        self.mode.is_full()
15332    }
15333
15334    pub fn inline_diagnostics_enabled(&self) -> bool {
15335        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15336    }
15337
15338    pub fn show_inline_diagnostics(&self) -> bool {
15339        self.show_inline_diagnostics
15340    }
15341
15342    pub fn toggle_inline_diagnostics(
15343        &mut self,
15344        _: &ToggleInlineDiagnostics,
15345        window: &mut Window,
15346        cx: &mut Context<Editor>,
15347    ) {
15348        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15349        self.refresh_inline_diagnostics(false, window, cx);
15350    }
15351
15352    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15353        self.diagnostics_max_severity = severity;
15354        self.display_map.update(cx, |display_map, _| {
15355            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15356        });
15357    }
15358
15359    pub fn toggle_diagnostics(
15360        &mut self,
15361        _: &ToggleDiagnostics,
15362        window: &mut Window,
15363        cx: &mut Context<Editor>,
15364    ) {
15365        if !self.diagnostics_enabled() {
15366            return;
15367        }
15368
15369        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15370            EditorSettings::get_global(cx)
15371                .diagnostics_max_severity
15372                .filter(|severity| severity != &DiagnosticSeverity::Off)
15373                .unwrap_or(DiagnosticSeverity::Hint)
15374        } else {
15375            DiagnosticSeverity::Off
15376        };
15377        self.set_max_diagnostics_severity(new_severity, cx);
15378        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15379            self.active_diagnostics = ActiveDiagnostic::None;
15380            self.inline_diagnostics_update = Task::ready(());
15381            self.inline_diagnostics.clear();
15382        } else {
15383            self.refresh_inline_diagnostics(false, window, cx);
15384        }
15385
15386        cx.notify();
15387    }
15388
15389    pub fn toggle_minimap(
15390        &mut self,
15391        _: &ToggleMinimap,
15392        window: &mut Window,
15393        cx: &mut Context<Editor>,
15394    ) {
15395        if self.supports_minimap(cx) {
15396            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15397        }
15398    }
15399
15400    fn refresh_inline_diagnostics(
15401        &mut self,
15402        debounce: bool,
15403        window: &mut Window,
15404        cx: &mut Context<Self>,
15405    ) {
15406        let max_severity = ProjectSettings::get_global(cx)
15407            .diagnostics
15408            .inline
15409            .max_severity
15410            .unwrap_or(self.diagnostics_max_severity);
15411
15412        if self.mode.is_minimap()
15413            || !self.inline_diagnostics_enabled()
15414            || !self.show_inline_diagnostics
15415            || max_severity == DiagnosticSeverity::Off
15416        {
15417            self.inline_diagnostics_update = Task::ready(());
15418            self.inline_diagnostics.clear();
15419            return;
15420        }
15421
15422        let debounce_ms = ProjectSettings::get_global(cx)
15423            .diagnostics
15424            .inline
15425            .update_debounce_ms;
15426        let debounce = if debounce && debounce_ms > 0 {
15427            Some(Duration::from_millis(debounce_ms))
15428        } else {
15429            None
15430        };
15431        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15432            let editor = editor.upgrade().unwrap();
15433
15434            if let Some(debounce) = debounce {
15435                cx.background_executor().timer(debounce).await;
15436            }
15437            let Some(snapshot) = editor
15438                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15439                .ok()
15440            else {
15441                return;
15442            };
15443
15444            let new_inline_diagnostics = cx
15445                .background_spawn(async move {
15446                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15447                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15448                        let message = diagnostic_entry
15449                            .diagnostic
15450                            .message
15451                            .split_once('\n')
15452                            .map(|(line, _)| line)
15453                            .map(SharedString::new)
15454                            .unwrap_or_else(|| {
15455                                SharedString::from(diagnostic_entry.diagnostic.message)
15456                            });
15457                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15458                        let (Ok(i) | Err(i)) = inline_diagnostics
15459                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15460                        inline_diagnostics.insert(
15461                            i,
15462                            (
15463                                start_anchor,
15464                                InlineDiagnostic {
15465                                    message,
15466                                    group_id: diagnostic_entry.diagnostic.group_id,
15467                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15468                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15469                                    severity: diagnostic_entry.diagnostic.severity,
15470                                },
15471                            ),
15472                        );
15473                    }
15474                    inline_diagnostics
15475                })
15476                .await;
15477
15478            editor
15479                .update(cx, |editor, cx| {
15480                    editor.inline_diagnostics = new_inline_diagnostics;
15481                    cx.notify();
15482                })
15483                .ok();
15484        });
15485    }
15486
15487    pub fn set_selections_from_remote(
15488        &mut self,
15489        selections: Vec<Selection<Anchor>>,
15490        pending_selection: Option<Selection<Anchor>>,
15491        window: &mut Window,
15492        cx: &mut Context<Self>,
15493    ) {
15494        let old_cursor_position = self.selections.newest_anchor().head();
15495        self.selections.change_with(cx, |s| {
15496            s.select_anchors(selections);
15497            if let Some(pending_selection) = pending_selection {
15498                s.set_pending(pending_selection, SelectMode::Character);
15499            } else {
15500                s.clear_pending();
15501            }
15502        });
15503        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15504    }
15505
15506    fn push_to_selection_history(&mut self) {
15507        self.selection_history.push(SelectionHistoryEntry {
15508            selections: self.selections.disjoint_anchors(),
15509            select_next_state: self.select_next_state.clone(),
15510            select_prev_state: self.select_prev_state.clone(),
15511            add_selections_state: self.add_selections_state.clone(),
15512        });
15513    }
15514
15515    pub fn transact(
15516        &mut self,
15517        window: &mut Window,
15518        cx: &mut Context<Self>,
15519        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15520    ) -> Option<TransactionId> {
15521        self.start_transaction_at(Instant::now(), window, cx);
15522        update(self, window, cx);
15523        self.end_transaction_at(Instant::now(), cx)
15524    }
15525
15526    pub fn start_transaction_at(
15527        &mut self,
15528        now: Instant,
15529        window: &mut Window,
15530        cx: &mut Context<Self>,
15531    ) {
15532        self.end_selection(window, cx);
15533        if let Some(tx_id) = self
15534            .buffer
15535            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15536        {
15537            self.selection_history
15538                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15539            cx.emit(EditorEvent::TransactionBegun {
15540                transaction_id: tx_id,
15541            })
15542        }
15543    }
15544
15545    pub fn end_transaction_at(
15546        &mut self,
15547        now: Instant,
15548        cx: &mut Context<Self>,
15549    ) -> Option<TransactionId> {
15550        if let Some(transaction_id) = self
15551            .buffer
15552            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15553        {
15554            if let Some((_, end_selections)) =
15555                self.selection_history.transaction_mut(transaction_id)
15556            {
15557                *end_selections = Some(self.selections.disjoint_anchors());
15558            } else {
15559                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15560            }
15561
15562            cx.emit(EditorEvent::Edited { transaction_id });
15563            Some(transaction_id)
15564        } else {
15565            None
15566        }
15567    }
15568
15569    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15570        if self.selection_mark_mode {
15571            self.change_selections(None, window, cx, |s| {
15572                s.move_with(|_, sel| {
15573                    sel.collapse_to(sel.head(), SelectionGoal::None);
15574                });
15575            })
15576        }
15577        self.selection_mark_mode = true;
15578        cx.notify();
15579    }
15580
15581    pub fn swap_selection_ends(
15582        &mut self,
15583        _: &actions::SwapSelectionEnds,
15584        window: &mut Window,
15585        cx: &mut Context<Self>,
15586    ) {
15587        self.change_selections(None, window, cx, |s| {
15588            s.move_with(|_, sel| {
15589                if sel.start != sel.end {
15590                    sel.reversed = !sel.reversed
15591                }
15592            });
15593        });
15594        self.request_autoscroll(Autoscroll::newest(), cx);
15595        cx.notify();
15596    }
15597
15598    pub fn toggle_fold(
15599        &mut self,
15600        _: &actions::ToggleFold,
15601        window: &mut Window,
15602        cx: &mut Context<Self>,
15603    ) {
15604        if self.is_singleton(cx) {
15605            let selection = self.selections.newest::<Point>(cx);
15606
15607            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15608            let range = if selection.is_empty() {
15609                let point = selection.head().to_display_point(&display_map);
15610                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15611                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15612                    .to_point(&display_map);
15613                start..end
15614            } else {
15615                selection.range()
15616            };
15617            if display_map.folds_in_range(range).next().is_some() {
15618                self.unfold_lines(&Default::default(), window, cx)
15619            } else {
15620                self.fold(&Default::default(), window, cx)
15621            }
15622        } else {
15623            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15624            let buffer_ids: HashSet<_> = self
15625                .selections
15626                .disjoint_anchor_ranges()
15627                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15628                .collect();
15629
15630            let should_unfold = buffer_ids
15631                .iter()
15632                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15633
15634            for buffer_id in buffer_ids {
15635                if should_unfold {
15636                    self.unfold_buffer(buffer_id, cx);
15637                } else {
15638                    self.fold_buffer(buffer_id, cx);
15639                }
15640            }
15641        }
15642    }
15643
15644    pub fn toggle_fold_recursive(
15645        &mut self,
15646        _: &actions::ToggleFoldRecursive,
15647        window: &mut Window,
15648        cx: &mut Context<Self>,
15649    ) {
15650        let selection = self.selections.newest::<Point>(cx);
15651
15652        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15653        let range = if selection.is_empty() {
15654            let point = selection.head().to_display_point(&display_map);
15655            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15656            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15657                .to_point(&display_map);
15658            start..end
15659        } else {
15660            selection.range()
15661        };
15662        if display_map.folds_in_range(range).next().is_some() {
15663            self.unfold_recursive(&Default::default(), window, cx)
15664        } else {
15665            self.fold_recursive(&Default::default(), window, cx)
15666        }
15667    }
15668
15669    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15670        if self.is_singleton(cx) {
15671            let mut to_fold = Vec::new();
15672            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15673            let selections = self.selections.all_adjusted(cx);
15674
15675            for selection in selections {
15676                let range = selection.range().sorted();
15677                let buffer_start_row = range.start.row;
15678
15679                if range.start.row != range.end.row {
15680                    let mut found = false;
15681                    let mut row = range.start.row;
15682                    while row <= range.end.row {
15683                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15684                        {
15685                            found = true;
15686                            row = crease.range().end.row + 1;
15687                            to_fold.push(crease);
15688                        } else {
15689                            row += 1
15690                        }
15691                    }
15692                    if found {
15693                        continue;
15694                    }
15695                }
15696
15697                for row in (0..=range.start.row).rev() {
15698                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15699                        if crease.range().end.row >= buffer_start_row {
15700                            to_fold.push(crease);
15701                            if row <= range.start.row {
15702                                break;
15703                            }
15704                        }
15705                    }
15706                }
15707            }
15708
15709            self.fold_creases(to_fold, true, window, cx);
15710        } else {
15711            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15712            let buffer_ids = self
15713                .selections
15714                .disjoint_anchor_ranges()
15715                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15716                .collect::<HashSet<_>>();
15717            for buffer_id in buffer_ids {
15718                self.fold_buffer(buffer_id, cx);
15719            }
15720        }
15721    }
15722
15723    fn fold_at_level(
15724        &mut self,
15725        fold_at: &FoldAtLevel,
15726        window: &mut Window,
15727        cx: &mut Context<Self>,
15728    ) {
15729        if !self.buffer.read(cx).is_singleton() {
15730            return;
15731        }
15732
15733        let fold_at_level = fold_at.0;
15734        let snapshot = self.buffer.read(cx).snapshot(cx);
15735        let mut to_fold = Vec::new();
15736        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15737
15738        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15739            while start_row < end_row {
15740                match self
15741                    .snapshot(window, cx)
15742                    .crease_for_buffer_row(MultiBufferRow(start_row))
15743                {
15744                    Some(crease) => {
15745                        let nested_start_row = crease.range().start.row + 1;
15746                        let nested_end_row = crease.range().end.row;
15747
15748                        if current_level < fold_at_level {
15749                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15750                        } else if current_level == fold_at_level {
15751                            to_fold.push(crease);
15752                        }
15753
15754                        start_row = nested_end_row + 1;
15755                    }
15756                    None => start_row += 1,
15757                }
15758            }
15759        }
15760
15761        self.fold_creases(to_fold, true, window, cx);
15762    }
15763
15764    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15765        if self.buffer.read(cx).is_singleton() {
15766            let mut fold_ranges = Vec::new();
15767            let snapshot = self.buffer.read(cx).snapshot(cx);
15768
15769            for row in 0..snapshot.max_row().0 {
15770                if let Some(foldable_range) = self
15771                    .snapshot(window, cx)
15772                    .crease_for_buffer_row(MultiBufferRow(row))
15773                {
15774                    fold_ranges.push(foldable_range);
15775                }
15776            }
15777
15778            self.fold_creases(fold_ranges, true, window, cx);
15779        } else {
15780            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15781                editor
15782                    .update_in(cx, |editor, _, cx| {
15783                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15784                            editor.fold_buffer(buffer_id, cx);
15785                        }
15786                    })
15787                    .ok();
15788            });
15789        }
15790    }
15791
15792    pub fn fold_function_bodies(
15793        &mut self,
15794        _: &actions::FoldFunctionBodies,
15795        window: &mut Window,
15796        cx: &mut Context<Self>,
15797    ) {
15798        let snapshot = self.buffer.read(cx).snapshot(cx);
15799
15800        let ranges = snapshot
15801            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15802            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15803            .collect::<Vec<_>>();
15804
15805        let creases = ranges
15806            .into_iter()
15807            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15808            .collect();
15809
15810        self.fold_creases(creases, true, window, cx);
15811    }
15812
15813    pub fn fold_recursive(
15814        &mut self,
15815        _: &actions::FoldRecursive,
15816        window: &mut Window,
15817        cx: &mut Context<Self>,
15818    ) {
15819        let mut to_fold = Vec::new();
15820        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15821        let selections = self.selections.all_adjusted(cx);
15822
15823        for selection in selections {
15824            let range = selection.range().sorted();
15825            let buffer_start_row = range.start.row;
15826
15827            if range.start.row != range.end.row {
15828                let mut found = false;
15829                for row in range.start.row..=range.end.row {
15830                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15831                        found = true;
15832                        to_fold.push(crease);
15833                    }
15834                }
15835                if found {
15836                    continue;
15837                }
15838            }
15839
15840            for row in (0..=range.start.row).rev() {
15841                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15842                    if crease.range().end.row >= buffer_start_row {
15843                        to_fold.push(crease);
15844                    } else {
15845                        break;
15846                    }
15847                }
15848            }
15849        }
15850
15851        self.fold_creases(to_fold, true, window, cx);
15852    }
15853
15854    pub fn fold_at(
15855        &mut self,
15856        buffer_row: MultiBufferRow,
15857        window: &mut Window,
15858        cx: &mut Context<Self>,
15859    ) {
15860        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15861
15862        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15863            let autoscroll = self
15864                .selections
15865                .all::<Point>(cx)
15866                .iter()
15867                .any(|selection| crease.range().overlaps(&selection.range()));
15868
15869            self.fold_creases(vec![crease], autoscroll, window, cx);
15870        }
15871    }
15872
15873    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15874        if self.is_singleton(cx) {
15875            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15876            let buffer = &display_map.buffer_snapshot;
15877            let selections = self.selections.all::<Point>(cx);
15878            let ranges = selections
15879                .iter()
15880                .map(|s| {
15881                    let range = s.display_range(&display_map).sorted();
15882                    let mut start = range.start.to_point(&display_map);
15883                    let mut end = range.end.to_point(&display_map);
15884                    start.column = 0;
15885                    end.column = buffer.line_len(MultiBufferRow(end.row));
15886                    start..end
15887                })
15888                .collect::<Vec<_>>();
15889
15890            self.unfold_ranges(&ranges, true, true, cx);
15891        } else {
15892            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15893            let buffer_ids = self
15894                .selections
15895                .disjoint_anchor_ranges()
15896                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15897                .collect::<HashSet<_>>();
15898            for buffer_id in buffer_ids {
15899                self.unfold_buffer(buffer_id, cx);
15900            }
15901        }
15902    }
15903
15904    pub fn unfold_recursive(
15905        &mut self,
15906        _: &UnfoldRecursive,
15907        _window: &mut Window,
15908        cx: &mut Context<Self>,
15909    ) {
15910        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15911        let selections = self.selections.all::<Point>(cx);
15912        let ranges = selections
15913            .iter()
15914            .map(|s| {
15915                let mut range = s.display_range(&display_map).sorted();
15916                *range.start.column_mut() = 0;
15917                *range.end.column_mut() = display_map.line_len(range.end.row());
15918                let start = range.start.to_point(&display_map);
15919                let end = range.end.to_point(&display_map);
15920                start..end
15921            })
15922            .collect::<Vec<_>>();
15923
15924        self.unfold_ranges(&ranges, true, true, cx);
15925    }
15926
15927    pub fn unfold_at(
15928        &mut self,
15929        buffer_row: MultiBufferRow,
15930        _window: &mut Window,
15931        cx: &mut Context<Self>,
15932    ) {
15933        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15934
15935        let intersection_range = Point::new(buffer_row.0, 0)
15936            ..Point::new(
15937                buffer_row.0,
15938                display_map.buffer_snapshot.line_len(buffer_row),
15939            );
15940
15941        let autoscroll = self
15942            .selections
15943            .all::<Point>(cx)
15944            .iter()
15945            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15946
15947        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15948    }
15949
15950    pub fn unfold_all(
15951        &mut self,
15952        _: &actions::UnfoldAll,
15953        _window: &mut Window,
15954        cx: &mut Context<Self>,
15955    ) {
15956        if self.buffer.read(cx).is_singleton() {
15957            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15958            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15959        } else {
15960            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15961                editor
15962                    .update(cx, |editor, cx| {
15963                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15964                            editor.unfold_buffer(buffer_id, cx);
15965                        }
15966                    })
15967                    .ok();
15968            });
15969        }
15970    }
15971
15972    pub fn fold_selected_ranges(
15973        &mut self,
15974        _: &FoldSelectedRanges,
15975        window: &mut Window,
15976        cx: &mut Context<Self>,
15977    ) {
15978        let selections = self.selections.all_adjusted(cx);
15979        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15980        let ranges = selections
15981            .into_iter()
15982            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
15983            .collect::<Vec<_>>();
15984        self.fold_creases(ranges, true, window, cx);
15985    }
15986
15987    pub fn fold_ranges<T: ToOffset + Clone>(
15988        &mut self,
15989        ranges: Vec<Range<T>>,
15990        auto_scroll: bool,
15991        window: &mut Window,
15992        cx: &mut Context<Self>,
15993    ) {
15994        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15995        let ranges = ranges
15996            .into_iter()
15997            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
15998            .collect::<Vec<_>>();
15999        self.fold_creases(ranges, auto_scroll, window, cx);
16000    }
16001
16002    pub fn fold_creases<T: ToOffset + Clone>(
16003        &mut self,
16004        creases: Vec<Crease<T>>,
16005        auto_scroll: bool,
16006        _window: &mut Window,
16007        cx: &mut Context<Self>,
16008    ) {
16009        if creases.is_empty() {
16010            return;
16011        }
16012
16013        let mut buffers_affected = HashSet::default();
16014        let multi_buffer = self.buffer().read(cx);
16015        for crease in &creases {
16016            if let Some((_, buffer, _)) =
16017                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16018            {
16019                buffers_affected.insert(buffer.read(cx).remote_id());
16020            };
16021        }
16022
16023        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16024
16025        if auto_scroll {
16026            self.request_autoscroll(Autoscroll::fit(), cx);
16027        }
16028
16029        cx.notify();
16030
16031        self.scrollbar_marker_state.dirty = true;
16032        self.folds_did_change(cx);
16033    }
16034
16035    /// Removes any folds whose ranges intersect any of the given ranges.
16036    pub fn unfold_ranges<T: ToOffset + Clone>(
16037        &mut self,
16038        ranges: &[Range<T>],
16039        inclusive: bool,
16040        auto_scroll: bool,
16041        cx: &mut Context<Self>,
16042    ) {
16043        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16044            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16045        });
16046        self.folds_did_change(cx);
16047    }
16048
16049    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16050        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16051            return;
16052        }
16053        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16054        self.display_map.update(cx, |display_map, cx| {
16055            display_map.fold_buffers([buffer_id], cx)
16056        });
16057        cx.emit(EditorEvent::BufferFoldToggled {
16058            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16059            folded: true,
16060        });
16061        cx.notify();
16062    }
16063
16064    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16065        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16066            return;
16067        }
16068        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16069        self.display_map.update(cx, |display_map, cx| {
16070            display_map.unfold_buffers([buffer_id], cx);
16071        });
16072        cx.emit(EditorEvent::BufferFoldToggled {
16073            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16074            folded: false,
16075        });
16076        cx.notify();
16077    }
16078
16079    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16080        self.display_map.read(cx).is_buffer_folded(buffer)
16081    }
16082
16083    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16084        self.display_map.read(cx).folded_buffers()
16085    }
16086
16087    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16088        self.display_map.update(cx, |display_map, cx| {
16089            display_map.disable_header_for_buffer(buffer_id, cx);
16090        });
16091        cx.notify();
16092    }
16093
16094    /// Removes any folds with the given ranges.
16095    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16096        &mut self,
16097        ranges: &[Range<T>],
16098        type_id: TypeId,
16099        auto_scroll: bool,
16100        cx: &mut Context<Self>,
16101    ) {
16102        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16103            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16104        });
16105        self.folds_did_change(cx);
16106    }
16107
16108    fn remove_folds_with<T: ToOffset + Clone>(
16109        &mut self,
16110        ranges: &[Range<T>],
16111        auto_scroll: bool,
16112        cx: &mut Context<Self>,
16113        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16114    ) {
16115        if ranges.is_empty() {
16116            return;
16117        }
16118
16119        let mut buffers_affected = HashSet::default();
16120        let multi_buffer = self.buffer().read(cx);
16121        for range in ranges {
16122            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16123                buffers_affected.insert(buffer.read(cx).remote_id());
16124            };
16125        }
16126
16127        self.display_map.update(cx, update);
16128
16129        if auto_scroll {
16130            self.request_autoscroll(Autoscroll::fit(), cx);
16131        }
16132
16133        cx.notify();
16134        self.scrollbar_marker_state.dirty = true;
16135        self.active_indent_guides_state.dirty = true;
16136    }
16137
16138    pub fn update_fold_widths(
16139        &mut self,
16140        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16141        cx: &mut Context<Self>,
16142    ) -> bool {
16143        self.display_map
16144            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16145    }
16146
16147    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16148        self.display_map.read(cx).fold_placeholder.clone()
16149    }
16150
16151    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16152        self.buffer.update(cx, |buffer, cx| {
16153            buffer.set_all_diff_hunks_expanded(cx);
16154        });
16155    }
16156
16157    pub fn expand_all_diff_hunks(
16158        &mut self,
16159        _: &ExpandAllDiffHunks,
16160        _window: &mut Window,
16161        cx: &mut Context<Self>,
16162    ) {
16163        self.buffer.update(cx, |buffer, cx| {
16164            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16165        });
16166    }
16167
16168    pub fn toggle_selected_diff_hunks(
16169        &mut self,
16170        _: &ToggleSelectedDiffHunks,
16171        _window: &mut Window,
16172        cx: &mut Context<Self>,
16173    ) {
16174        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16175        self.toggle_diff_hunks_in_ranges(ranges, cx);
16176    }
16177
16178    pub fn diff_hunks_in_ranges<'a>(
16179        &'a self,
16180        ranges: &'a [Range<Anchor>],
16181        buffer: &'a MultiBufferSnapshot,
16182    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16183        ranges.iter().flat_map(move |range| {
16184            let end_excerpt_id = range.end.excerpt_id;
16185            let range = range.to_point(buffer);
16186            let mut peek_end = range.end;
16187            if range.end.row < buffer.max_row().0 {
16188                peek_end = Point::new(range.end.row + 1, 0);
16189            }
16190            buffer
16191                .diff_hunks_in_range(range.start..peek_end)
16192                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16193        })
16194    }
16195
16196    pub fn has_stageable_diff_hunks_in_ranges(
16197        &self,
16198        ranges: &[Range<Anchor>],
16199        snapshot: &MultiBufferSnapshot,
16200    ) -> bool {
16201        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16202        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16203    }
16204
16205    pub fn toggle_staged_selected_diff_hunks(
16206        &mut self,
16207        _: &::git::ToggleStaged,
16208        _: &mut Window,
16209        cx: &mut Context<Self>,
16210    ) {
16211        let snapshot = self.buffer.read(cx).snapshot(cx);
16212        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16213        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16214        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16215    }
16216
16217    pub fn set_render_diff_hunk_controls(
16218        &mut self,
16219        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16220        cx: &mut Context<Self>,
16221    ) {
16222        self.render_diff_hunk_controls = render_diff_hunk_controls;
16223        cx.notify();
16224    }
16225
16226    pub fn stage_and_next(
16227        &mut self,
16228        _: &::git::StageAndNext,
16229        window: &mut Window,
16230        cx: &mut Context<Self>,
16231    ) {
16232        self.do_stage_or_unstage_and_next(true, window, cx);
16233    }
16234
16235    pub fn unstage_and_next(
16236        &mut self,
16237        _: &::git::UnstageAndNext,
16238        window: &mut Window,
16239        cx: &mut Context<Self>,
16240    ) {
16241        self.do_stage_or_unstage_and_next(false, window, cx);
16242    }
16243
16244    pub fn stage_or_unstage_diff_hunks(
16245        &mut self,
16246        stage: bool,
16247        ranges: Vec<Range<Anchor>>,
16248        cx: &mut Context<Self>,
16249    ) {
16250        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16251        cx.spawn(async move |this, cx| {
16252            task.await?;
16253            this.update(cx, |this, cx| {
16254                let snapshot = this.buffer.read(cx).snapshot(cx);
16255                let chunk_by = this
16256                    .diff_hunks_in_ranges(&ranges, &snapshot)
16257                    .chunk_by(|hunk| hunk.buffer_id);
16258                for (buffer_id, hunks) in &chunk_by {
16259                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16260                }
16261            })
16262        })
16263        .detach_and_log_err(cx);
16264    }
16265
16266    fn save_buffers_for_ranges_if_needed(
16267        &mut self,
16268        ranges: &[Range<Anchor>],
16269        cx: &mut Context<Editor>,
16270    ) -> Task<Result<()>> {
16271        let multibuffer = self.buffer.read(cx);
16272        let snapshot = multibuffer.read(cx);
16273        let buffer_ids: HashSet<_> = ranges
16274            .iter()
16275            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16276            .collect();
16277        drop(snapshot);
16278
16279        let mut buffers = HashSet::default();
16280        for buffer_id in buffer_ids {
16281            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16282                let buffer = buffer_entity.read(cx);
16283                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16284                {
16285                    buffers.insert(buffer_entity);
16286                }
16287            }
16288        }
16289
16290        if let Some(project) = &self.project {
16291            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16292        } else {
16293            Task::ready(Ok(()))
16294        }
16295    }
16296
16297    fn do_stage_or_unstage_and_next(
16298        &mut self,
16299        stage: bool,
16300        window: &mut Window,
16301        cx: &mut Context<Self>,
16302    ) {
16303        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16304
16305        if ranges.iter().any(|range| range.start != range.end) {
16306            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16307            return;
16308        }
16309
16310        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16311        let snapshot = self.snapshot(window, cx);
16312        let position = self.selections.newest::<Point>(cx).head();
16313        let mut row = snapshot
16314            .buffer_snapshot
16315            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16316            .find(|hunk| hunk.row_range.start.0 > position.row)
16317            .map(|hunk| hunk.row_range.start);
16318
16319        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16320        // Outside of the project diff editor, wrap around to the beginning.
16321        if !all_diff_hunks_expanded {
16322            row = row.or_else(|| {
16323                snapshot
16324                    .buffer_snapshot
16325                    .diff_hunks_in_range(Point::zero()..position)
16326                    .find(|hunk| hunk.row_range.end.0 < position.row)
16327                    .map(|hunk| hunk.row_range.start)
16328            });
16329        }
16330
16331        if let Some(row) = row {
16332            let destination = Point::new(row.0, 0);
16333            let autoscroll = Autoscroll::center();
16334
16335            self.unfold_ranges(&[destination..destination], false, false, cx);
16336            self.change_selections(Some(autoscroll), window, cx, |s| {
16337                s.select_ranges([destination..destination]);
16338            });
16339        }
16340    }
16341
16342    fn do_stage_or_unstage(
16343        &self,
16344        stage: bool,
16345        buffer_id: BufferId,
16346        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16347        cx: &mut App,
16348    ) -> Option<()> {
16349        let project = self.project.as_ref()?;
16350        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16351        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16352        let buffer_snapshot = buffer.read(cx).snapshot();
16353        let file_exists = buffer_snapshot
16354            .file()
16355            .is_some_and(|file| file.disk_state().exists());
16356        diff.update(cx, |diff, cx| {
16357            diff.stage_or_unstage_hunks(
16358                stage,
16359                &hunks
16360                    .map(|hunk| buffer_diff::DiffHunk {
16361                        buffer_range: hunk.buffer_range,
16362                        diff_base_byte_range: hunk.diff_base_byte_range,
16363                        secondary_status: hunk.secondary_status,
16364                        range: Point::zero()..Point::zero(), // unused
16365                    })
16366                    .collect::<Vec<_>>(),
16367                &buffer_snapshot,
16368                file_exists,
16369                cx,
16370            )
16371        });
16372        None
16373    }
16374
16375    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16376        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16377        self.buffer
16378            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16379    }
16380
16381    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16382        self.buffer.update(cx, |buffer, cx| {
16383            let ranges = vec![Anchor::min()..Anchor::max()];
16384            if !buffer.all_diff_hunks_expanded()
16385                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16386            {
16387                buffer.collapse_diff_hunks(ranges, cx);
16388                true
16389            } else {
16390                false
16391            }
16392        })
16393    }
16394
16395    fn toggle_diff_hunks_in_ranges(
16396        &mut self,
16397        ranges: Vec<Range<Anchor>>,
16398        cx: &mut Context<Editor>,
16399    ) {
16400        self.buffer.update(cx, |buffer, cx| {
16401            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16402            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16403        })
16404    }
16405
16406    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16407        self.buffer.update(cx, |buffer, cx| {
16408            let snapshot = buffer.snapshot(cx);
16409            let excerpt_id = range.end.excerpt_id;
16410            let point_range = range.to_point(&snapshot);
16411            let expand = !buffer.single_hunk_is_expanded(range, cx);
16412            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16413        })
16414    }
16415
16416    pub(crate) fn apply_all_diff_hunks(
16417        &mut self,
16418        _: &ApplyAllDiffHunks,
16419        window: &mut Window,
16420        cx: &mut Context<Self>,
16421    ) {
16422        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16423
16424        let buffers = self.buffer.read(cx).all_buffers();
16425        for branch_buffer in buffers {
16426            branch_buffer.update(cx, |branch_buffer, cx| {
16427                branch_buffer.merge_into_base(Vec::new(), cx);
16428            });
16429        }
16430
16431        if let Some(project) = self.project.clone() {
16432            self.save(true, project, window, cx).detach_and_log_err(cx);
16433        }
16434    }
16435
16436    pub(crate) fn apply_selected_diff_hunks(
16437        &mut self,
16438        _: &ApplyDiffHunk,
16439        window: &mut Window,
16440        cx: &mut Context<Self>,
16441    ) {
16442        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16443        let snapshot = self.snapshot(window, cx);
16444        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16445        let mut ranges_by_buffer = HashMap::default();
16446        self.transact(window, cx, |editor, _window, cx| {
16447            for hunk in hunks {
16448                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16449                    ranges_by_buffer
16450                        .entry(buffer.clone())
16451                        .or_insert_with(Vec::new)
16452                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16453                }
16454            }
16455
16456            for (buffer, ranges) in ranges_by_buffer {
16457                buffer.update(cx, |buffer, cx| {
16458                    buffer.merge_into_base(ranges, cx);
16459                });
16460            }
16461        });
16462
16463        if let Some(project) = self.project.clone() {
16464            self.save(true, project, window, cx).detach_and_log_err(cx);
16465        }
16466    }
16467
16468    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16469        if hovered != self.gutter_hovered {
16470            self.gutter_hovered = hovered;
16471            cx.notify();
16472        }
16473    }
16474
16475    pub fn insert_blocks(
16476        &mut self,
16477        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16478        autoscroll: Option<Autoscroll>,
16479        cx: &mut Context<Self>,
16480    ) -> Vec<CustomBlockId> {
16481        let blocks = self
16482            .display_map
16483            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16484        if let Some(autoscroll) = autoscroll {
16485            self.request_autoscroll(autoscroll, cx);
16486        }
16487        cx.notify();
16488        blocks
16489    }
16490
16491    pub fn resize_blocks(
16492        &mut self,
16493        heights: HashMap<CustomBlockId, u32>,
16494        autoscroll: Option<Autoscroll>,
16495        cx: &mut Context<Self>,
16496    ) {
16497        self.display_map
16498            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16499        if let Some(autoscroll) = autoscroll {
16500            self.request_autoscroll(autoscroll, cx);
16501        }
16502        cx.notify();
16503    }
16504
16505    pub fn replace_blocks(
16506        &mut self,
16507        renderers: HashMap<CustomBlockId, RenderBlock>,
16508        autoscroll: Option<Autoscroll>,
16509        cx: &mut Context<Self>,
16510    ) {
16511        self.display_map
16512            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16513        if let Some(autoscroll) = autoscroll {
16514            self.request_autoscroll(autoscroll, cx);
16515        }
16516        cx.notify();
16517    }
16518
16519    pub fn remove_blocks(
16520        &mut self,
16521        block_ids: HashSet<CustomBlockId>,
16522        autoscroll: Option<Autoscroll>,
16523        cx: &mut Context<Self>,
16524    ) {
16525        self.display_map.update(cx, |display_map, cx| {
16526            display_map.remove_blocks(block_ids, cx)
16527        });
16528        if let Some(autoscroll) = autoscroll {
16529            self.request_autoscroll(autoscroll, cx);
16530        }
16531        cx.notify();
16532    }
16533
16534    pub fn row_for_block(
16535        &self,
16536        block_id: CustomBlockId,
16537        cx: &mut Context<Self>,
16538    ) -> Option<DisplayRow> {
16539        self.display_map
16540            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16541    }
16542
16543    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16544        self.focused_block = Some(focused_block);
16545    }
16546
16547    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16548        self.focused_block.take()
16549    }
16550
16551    pub fn insert_creases(
16552        &mut self,
16553        creases: impl IntoIterator<Item = Crease<Anchor>>,
16554        cx: &mut Context<Self>,
16555    ) -> Vec<CreaseId> {
16556        self.display_map
16557            .update(cx, |map, cx| map.insert_creases(creases, cx))
16558    }
16559
16560    pub fn remove_creases(
16561        &mut self,
16562        ids: impl IntoIterator<Item = CreaseId>,
16563        cx: &mut Context<Self>,
16564    ) -> Vec<(CreaseId, Range<Anchor>)> {
16565        self.display_map
16566            .update(cx, |map, cx| map.remove_creases(ids, cx))
16567    }
16568
16569    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16570        self.display_map
16571            .update(cx, |map, cx| map.snapshot(cx))
16572            .longest_row()
16573    }
16574
16575    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16576        self.display_map
16577            .update(cx, |map, cx| map.snapshot(cx))
16578            .max_point()
16579    }
16580
16581    pub fn text(&self, cx: &App) -> String {
16582        self.buffer.read(cx).read(cx).text()
16583    }
16584
16585    pub fn is_empty(&self, cx: &App) -> bool {
16586        self.buffer.read(cx).read(cx).is_empty()
16587    }
16588
16589    pub fn text_option(&self, cx: &App) -> Option<String> {
16590        let text = self.text(cx);
16591        let text = text.trim();
16592
16593        if text.is_empty() {
16594            return None;
16595        }
16596
16597        Some(text.to_string())
16598    }
16599
16600    pub fn set_text(
16601        &mut self,
16602        text: impl Into<Arc<str>>,
16603        window: &mut Window,
16604        cx: &mut Context<Self>,
16605    ) {
16606        self.transact(window, cx, |this, _, cx| {
16607            this.buffer
16608                .read(cx)
16609                .as_singleton()
16610                .expect("you can only call set_text on editors for singleton buffers")
16611                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16612        });
16613    }
16614
16615    pub fn display_text(&self, cx: &mut App) -> String {
16616        self.display_map
16617            .update(cx, |map, cx| map.snapshot(cx))
16618            .text()
16619    }
16620
16621    fn create_minimap(
16622        &self,
16623        minimap_settings: MinimapSettings,
16624        window: &mut Window,
16625        cx: &mut Context<Self>,
16626    ) -> Option<Entity<Self>> {
16627        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16628            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16629    }
16630
16631    fn initialize_new_minimap(
16632        &self,
16633        minimap_settings: MinimapSettings,
16634        window: &mut Window,
16635        cx: &mut Context<Self>,
16636    ) -> Entity<Self> {
16637        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16638
16639        let mut minimap = Editor::new_internal(
16640            EditorMode::Minimap {
16641                parent: cx.weak_entity(),
16642            },
16643            self.buffer.clone(),
16644            self.project.clone(),
16645            Some(self.display_map.clone()),
16646            window,
16647            cx,
16648        );
16649        minimap.scroll_manager.clone_state(&self.scroll_manager);
16650        minimap.set_text_style_refinement(TextStyleRefinement {
16651            font_size: Some(MINIMAP_FONT_SIZE),
16652            font_weight: Some(MINIMAP_FONT_WEIGHT),
16653            ..Default::default()
16654        });
16655        minimap.update_minimap_configuration(minimap_settings, cx);
16656        cx.new(|_| minimap)
16657    }
16658
16659    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16660        let current_line_highlight = minimap_settings
16661            .current_line_highlight
16662            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16663        self.set_current_line_highlight(Some(current_line_highlight));
16664    }
16665
16666    pub fn minimap(&self) -> Option<&Entity<Self>> {
16667        self.minimap
16668            .as_ref()
16669            .filter(|_| self.minimap_visibility.visible())
16670    }
16671
16672    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16673        let mut wrap_guides = smallvec::smallvec![];
16674
16675        if self.show_wrap_guides == Some(false) {
16676            return wrap_guides;
16677        }
16678
16679        let settings = self.buffer.read(cx).language_settings(cx);
16680        if settings.show_wrap_guides {
16681            match self.soft_wrap_mode(cx) {
16682                SoftWrap::Column(soft_wrap) => {
16683                    wrap_guides.push((soft_wrap as usize, true));
16684                }
16685                SoftWrap::Bounded(soft_wrap) => {
16686                    wrap_guides.push((soft_wrap as usize, true));
16687                }
16688                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16689            }
16690            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16691        }
16692
16693        wrap_guides
16694    }
16695
16696    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16697        let settings = self.buffer.read(cx).language_settings(cx);
16698        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16699        match mode {
16700            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16701                SoftWrap::None
16702            }
16703            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16704            language_settings::SoftWrap::PreferredLineLength => {
16705                SoftWrap::Column(settings.preferred_line_length)
16706            }
16707            language_settings::SoftWrap::Bounded => {
16708                SoftWrap::Bounded(settings.preferred_line_length)
16709            }
16710        }
16711    }
16712
16713    pub fn set_soft_wrap_mode(
16714        &mut self,
16715        mode: language_settings::SoftWrap,
16716
16717        cx: &mut Context<Self>,
16718    ) {
16719        self.soft_wrap_mode_override = Some(mode);
16720        cx.notify();
16721    }
16722
16723    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16724        self.hard_wrap = hard_wrap;
16725        cx.notify();
16726    }
16727
16728    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16729        self.text_style_refinement = Some(style);
16730    }
16731
16732    /// called by the Element so we know what style we were most recently rendered with.
16733    pub(crate) fn set_style(
16734        &mut self,
16735        style: EditorStyle,
16736        window: &mut Window,
16737        cx: &mut Context<Self>,
16738    ) {
16739        // We intentionally do not inform the display map about the minimap style
16740        // so that wrapping is not recalculated and stays consistent for the editor
16741        // and its linked minimap.
16742        if !self.mode.is_minimap() {
16743            let rem_size = window.rem_size();
16744            self.display_map.update(cx, |map, cx| {
16745                map.set_font(
16746                    style.text.font(),
16747                    style.text.font_size.to_pixels(rem_size),
16748                    cx,
16749                )
16750            });
16751        }
16752        self.style = Some(style);
16753    }
16754
16755    pub fn style(&self) -> Option<&EditorStyle> {
16756        self.style.as_ref()
16757    }
16758
16759    // Called by the element. This method is not designed to be called outside of the editor
16760    // element's layout code because it does not notify when rewrapping is computed synchronously.
16761    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16762        self.display_map
16763            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16764    }
16765
16766    pub fn set_soft_wrap(&mut self) {
16767        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16768    }
16769
16770    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16771        if self.soft_wrap_mode_override.is_some() {
16772            self.soft_wrap_mode_override.take();
16773        } else {
16774            let soft_wrap = match self.soft_wrap_mode(cx) {
16775                SoftWrap::GitDiff => return,
16776                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16777                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16778                    language_settings::SoftWrap::None
16779                }
16780            };
16781            self.soft_wrap_mode_override = Some(soft_wrap);
16782        }
16783        cx.notify();
16784    }
16785
16786    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16787        let Some(workspace) = self.workspace() else {
16788            return;
16789        };
16790        let fs = workspace.read(cx).app_state().fs.clone();
16791        let current_show = TabBarSettings::get_global(cx).show;
16792        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16793            setting.show = Some(!current_show);
16794        });
16795    }
16796
16797    pub fn toggle_indent_guides(
16798        &mut self,
16799        _: &ToggleIndentGuides,
16800        _: &mut Window,
16801        cx: &mut Context<Self>,
16802    ) {
16803        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16804            self.buffer
16805                .read(cx)
16806                .language_settings(cx)
16807                .indent_guides
16808                .enabled
16809        });
16810        self.show_indent_guides = Some(!currently_enabled);
16811        cx.notify();
16812    }
16813
16814    fn should_show_indent_guides(&self) -> Option<bool> {
16815        self.show_indent_guides
16816    }
16817
16818    pub fn toggle_line_numbers(
16819        &mut self,
16820        _: &ToggleLineNumbers,
16821        _: &mut Window,
16822        cx: &mut Context<Self>,
16823    ) {
16824        let mut editor_settings = EditorSettings::get_global(cx).clone();
16825        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16826        EditorSettings::override_global(editor_settings, cx);
16827    }
16828
16829    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16830        if let Some(show_line_numbers) = self.show_line_numbers {
16831            return show_line_numbers;
16832        }
16833        EditorSettings::get_global(cx).gutter.line_numbers
16834    }
16835
16836    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16837        self.use_relative_line_numbers
16838            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16839    }
16840
16841    pub fn toggle_relative_line_numbers(
16842        &mut self,
16843        _: &ToggleRelativeLineNumbers,
16844        _: &mut Window,
16845        cx: &mut Context<Self>,
16846    ) {
16847        let is_relative = self.should_use_relative_line_numbers(cx);
16848        self.set_relative_line_number(Some(!is_relative), cx)
16849    }
16850
16851    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16852        self.use_relative_line_numbers = is_relative;
16853        cx.notify();
16854    }
16855
16856    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16857        self.show_gutter = show_gutter;
16858        cx.notify();
16859    }
16860
16861    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16862        self.show_scrollbars = show_scrollbars;
16863        cx.notify();
16864    }
16865
16866    pub fn set_minimap_visibility(
16867        &mut self,
16868        minimap_visibility: MinimapVisibility,
16869        window: &mut Window,
16870        cx: &mut Context<Self>,
16871    ) {
16872        if self.minimap_visibility != minimap_visibility {
16873            if minimap_visibility.visible() && self.minimap.is_none() {
16874                let minimap_settings = EditorSettings::get_global(cx).minimap;
16875                self.minimap =
16876                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16877            }
16878            self.minimap_visibility = minimap_visibility;
16879            cx.notify();
16880        }
16881    }
16882
16883    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16884        self.set_show_scrollbars(false, cx);
16885        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16886    }
16887
16888    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16889        self.show_line_numbers = Some(show_line_numbers);
16890        cx.notify();
16891    }
16892
16893    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16894        self.disable_expand_excerpt_buttons = true;
16895        cx.notify();
16896    }
16897
16898    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16899        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16900        cx.notify();
16901    }
16902
16903    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16904        self.show_code_actions = Some(show_code_actions);
16905        cx.notify();
16906    }
16907
16908    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16909        self.show_runnables = Some(show_runnables);
16910        cx.notify();
16911    }
16912
16913    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16914        self.show_breakpoints = Some(show_breakpoints);
16915        cx.notify();
16916    }
16917
16918    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16919        if self.display_map.read(cx).masked != masked {
16920            self.display_map.update(cx, |map, _| map.masked = masked);
16921        }
16922        cx.notify()
16923    }
16924
16925    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16926        self.show_wrap_guides = Some(show_wrap_guides);
16927        cx.notify();
16928    }
16929
16930    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16931        self.show_indent_guides = Some(show_indent_guides);
16932        cx.notify();
16933    }
16934
16935    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16936        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16937            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16938                if let Some(dir) = file.abs_path(cx).parent() {
16939                    return Some(dir.to_owned());
16940                }
16941            }
16942
16943            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16944                return Some(project_path.path.to_path_buf());
16945            }
16946        }
16947
16948        None
16949    }
16950
16951    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16952        self.active_excerpt(cx)?
16953            .1
16954            .read(cx)
16955            .file()
16956            .and_then(|f| f.as_local())
16957    }
16958
16959    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16960        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16961            let buffer = buffer.read(cx);
16962            if let Some(project_path) = buffer.project_path(cx) {
16963                let project = self.project.as_ref()?.read(cx);
16964                project.absolute_path(&project_path, cx)
16965            } else {
16966                buffer
16967                    .file()
16968                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16969            }
16970        })
16971    }
16972
16973    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16974        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16975            let project_path = buffer.read(cx).project_path(cx)?;
16976            let project = self.project.as_ref()?.read(cx);
16977            let entry = project.entry_for_path(&project_path, cx)?;
16978            let path = entry.path.to_path_buf();
16979            Some(path)
16980        })
16981    }
16982
16983    pub fn reveal_in_finder(
16984        &mut self,
16985        _: &RevealInFileManager,
16986        _window: &mut Window,
16987        cx: &mut Context<Self>,
16988    ) {
16989        if let Some(target) = self.target_file(cx) {
16990            cx.reveal_path(&target.abs_path(cx));
16991        }
16992    }
16993
16994    pub fn copy_path(
16995        &mut self,
16996        _: &zed_actions::workspace::CopyPath,
16997        _window: &mut Window,
16998        cx: &mut Context<Self>,
16999    ) {
17000        if let Some(path) = self.target_file_abs_path(cx) {
17001            if let Some(path) = path.to_str() {
17002                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17003            }
17004        }
17005    }
17006
17007    pub fn copy_relative_path(
17008        &mut self,
17009        _: &zed_actions::workspace::CopyRelativePath,
17010        _window: &mut Window,
17011        cx: &mut Context<Self>,
17012    ) {
17013        if let Some(path) = self.target_file_path(cx) {
17014            if let Some(path) = path.to_str() {
17015                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17016            }
17017        }
17018    }
17019
17020    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17021        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17022            buffer.read(cx).project_path(cx)
17023        } else {
17024            None
17025        }
17026    }
17027
17028    // Returns true if the editor handled a go-to-line request
17029    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17030        maybe!({
17031            let breakpoint_store = self.breakpoint_store.as_ref()?;
17032
17033            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17034            else {
17035                self.clear_row_highlights::<ActiveDebugLine>();
17036                return None;
17037            };
17038
17039            let position = active_stack_frame.position;
17040            let buffer_id = position.buffer_id?;
17041            let snapshot = self
17042                .project
17043                .as_ref()?
17044                .read(cx)
17045                .buffer_for_id(buffer_id, cx)?
17046                .read(cx)
17047                .snapshot();
17048
17049            let mut handled = false;
17050            for (id, ExcerptRange { context, .. }) in
17051                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17052            {
17053                if context.start.cmp(&position, &snapshot).is_ge()
17054                    || context.end.cmp(&position, &snapshot).is_lt()
17055                {
17056                    continue;
17057                }
17058                let snapshot = self.buffer.read(cx).snapshot(cx);
17059                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17060
17061                handled = true;
17062                self.clear_row_highlights::<ActiveDebugLine>();
17063
17064                self.go_to_line::<ActiveDebugLine>(
17065                    multibuffer_anchor,
17066                    Some(cx.theme().colors().editor_debugger_active_line_background),
17067                    window,
17068                    cx,
17069                );
17070
17071                cx.notify();
17072            }
17073
17074            handled.then_some(())
17075        })
17076        .is_some()
17077    }
17078
17079    pub fn copy_file_name_without_extension(
17080        &mut self,
17081        _: &CopyFileNameWithoutExtension,
17082        _: &mut Window,
17083        cx: &mut Context<Self>,
17084    ) {
17085        if let Some(file) = self.target_file(cx) {
17086            if let Some(file_stem) = file.path().file_stem() {
17087                if let Some(name) = file_stem.to_str() {
17088                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17089                }
17090            }
17091        }
17092    }
17093
17094    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17095        if let Some(file) = self.target_file(cx) {
17096            if let Some(file_name) = file.path().file_name() {
17097                if let Some(name) = file_name.to_str() {
17098                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17099                }
17100            }
17101        }
17102    }
17103
17104    pub fn toggle_git_blame(
17105        &mut self,
17106        _: &::git::Blame,
17107        window: &mut Window,
17108        cx: &mut Context<Self>,
17109    ) {
17110        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17111
17112        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17113            self.start_git_blame(true, window, cx);
17114        }
17115
17116        cx.notify();
17117    }
17118
17119    pub fn toggle_git_blame_inline(
17120        &mut self,
17121        _: &ToggleGitBlameInline,
17122        window: &mut Window,
17123        cx: &mut Context<Self>,
17124    ) {
17125        self.toggle_git_blame_inline_internal(true, window, cx);
17126        cx.notify();
17127    }
17128
17129    pub fn open_git_blame_commit(
17130        &mut self,
17131        _: &OpenGitBlameCommit,
17132        window: &mut Window,
17133        cx: &mut Context<Self>,
17134    ) {
17135        self.open_git_blame_commit_internal(window, cx);
17136    }
17137
17138    fn open_git_blame_commit_internal(
17139        &mut self,
17140        window: &mut Window,
17141        cx: &mut Context<Self>,
17142    ) -> Option<()> {
17143        let blame = self.blame.as_ref()?;
17144        let snapshot = self.snapshot(window, cx);
17145        let cursor = self.selections.newest::<Point>(cx).head();
17146        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17147        let blame_entry = blame
17148            .update(cx, |blame, cx| {
17149                blame
17150                    .blame_for_rows(
17151                        &[RowInfo {
17152                            buffer_id: Some(buffer.remote_id()),
17153                            buffer_row: Some(point.row),
17154                            ..Default::default()
17155                        }],
17156                        cx,
17157                    )
17158                    .next()
17159            })
17160            .flatten()?;
17161        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17162        let repo = blame.read(cx).repository(cx)?;
17163        let workspace = self.workspace()?.downgrade();
17164        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17165        None
17166    }
17167
17168    pub fn git_blame_inline_enabled(&self) -> bool {
17169        self.git_blame_inline_enabled
17170    }
17171
17172    pub fn toggle_selection_menu(
17173        &mut self,
17174        _: &ToggleSelectionMenu,
17175        _: &mut Window,
17176        cx: &mut Context<Self>,
17177    ) {
17178        self.show_selection_menu = self
17179            .show_selection_menu
17180            .map(|show_selections_menu| !show_selections_menu)
17181            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17182
17183        cx.notify();
17184    }
17185
17186    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17187        self.show_selection_menu
17188            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17189    }
17190
17191    fn start_git_blame(
17192        &mut self,
17193        user_triggered: bool,
17194        window: &mut Window,
17195        cx: &mut Context<Self>,
17196    ) {
17197        if let Some(project) = self.project.as_ref() {
17198            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17199                return;
17200            };
17201
17202            if buffer.read(cx).file().is_none() {
17203                return;
17204            }
17205
17206            let focused = self.focus_handle(cx).contains_focused(window, cx);
17207
17208            let project = project.clone();
17209            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17210            self.blame_subscription =
17211                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17212            self.blame = Some(blame);
17213        }
17214    }
17215
17216    fn toggle_git_blame_inline_internal(
17217        &mut self,
17218        user_triggered: bool,
17219        window: &mut Window,
17220        cx: &mut Context<Self>,
17221    ) {
17222        if self.git_blame_inline_enabled {
17223            self.git_blame_inline_enabled = false;
17224            self.show_git_blame_inline = false;
17225            self.show_git_blame_inline_delay_task.take();
17226        } else {
17227            self.git_blame_inline_enabled = true;
17228            self.start_git_blame_inline(user_triggered, window, cx);
17229        }
17230
17231        cx.notify();
17232    }
17233
17234    fn start_git_blame_inline(
17235        &mut self,
17236        user_triggered: bool,
17237        window: &mut Window,
17238        cx: &mut Context<Self>,
17239    ) {
17240        self.start_git_blame(user_triggered, window, cx);
17241
17242        if ProjectSettings::get_global(cx)
17243            .git
17244            .inline_blame_delay()
17245            .is_some()
17246        {
17247            self.start_inline_blame_timer(window, cx);
17248        } else {
17249            self.show_git_blame_inline = true
17250        }
17251    }
17252
17253    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17254        self.blame.as_ref()
17255    }
17256
17257    pub fn show_git_blame_gutter(&self) -> bool {
17258        self.show_git_blame_gutter
17259    }
17260
17261    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17262        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17263    }
17264
17265    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17266        self.show_git_blame_inline
17267            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17268            && !self.newest_selection_head_on_empty_line(cx)
17269            && self.has_blame_entries(cx)
17270    }
17271
17272    fn has_blame_entries(&self, cx: &App) -> bool {
17273        self.blame()
17274            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17275    }
17276
17277    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17278        let cursor_anchor = self.selections.newest_anchor().head();
17279
17280        let snapshot = self.buffer.read(cx).snapshot(cx);
17281        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17282
17283        snapshot.line_len(buffer_row) == 0
17284    }
17285
17286    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17287        let buffer_and_selection = maybe!({
17288            let selection = self.selections.newest::<Point>(cx);
17289            let selection_range = selection.range();
17290
17291            let multi_buffer = self.buffer().read(cx);
17292            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17293            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17294
17295            let (buffer, range, _) = if selection.reversed {
17296                buffer_ranges.first()
17297            } else {
17298                buffer_ranges.last()
17299            }?;
17300
17301            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17302                ..text::ToPoint::to_point(&range.end, &buffer).row;
17303            Some((
17304                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17305                selection,
17306            ))
17307        });
17308
17309        let Some((buffer, selection)) = buffer_and_selection else {
17310            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17311        };
17312
17313        let Some(project) = self.project.as_ref() else {
17314            return Task::ready(Err(anyhow!("editor does not have project")));
17315        };
17316
17317        project.update(cx, |project, cx| {
17318            project.get_permalink_to_line(&buffer, selection, cx)
17319        })
17320    }
17321
17322    pub fn copy_permalink_to_line(
17323        &mut self,
17324        _: &CopyPermalinkToLine,
17325        window: &mut Window,
17326        cx: &mut Context<Self>,
17327    ) {
17328        let permalink_task = self.get_permalink_to_line(cx);
17329        let workspace = self.workspace();
17330
17331        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17332            Ok(permalink) => {
17333                cx.update(|_, cx| {
17334                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17335                })
17336                .ok();
17337            }
17338            Err(err) => {
17339                let message = format!("Failed to copy permalink: {err}");
17340
17341                anyhow::Result::<()>::Err(err).log_err();
17342
17343                if let Some(workspace) = workspace {
17344                    workspace
17345                        .update_in(cx, |workspace, _, cx| {
17346                            struct CopyPermalinkToLine;
17347
17348                            workspace.show_toast(
17349                                Toast::new(
17350                                    NotificationId::unique::<CopyPermalinkToLine>(),
17351                                    message,
17352                                ),
17353                                cx,
17354                            )
17355                        })
17356                        .ok();
17357                }
17358            }
17359        })
17360        .detach();
17361    }
17362
17363    pub fn copy_file_location(
17364        &mut self,
17365        _: &CopyFileLocation,
17366        _: &mut Window,
17367        cx: &mut Context<Self>,
17368    ) {
17369        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17370        if let Some(file) = self.target_file(cx) {
17371            if let Some(path) = file.path().to_str() {
17372                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17373            }
17374        }
17375    }
17376
17377    pub fn open_permalink_to_line(
17378        &mut self,
17379        _: &OpenPermalinkToLine,
17380        window: &mut Window,
17381        cx: &mut Context<Self>,
17382    ) {
17383        let permalink_task = self.get_permalink_to_line(cx);
17384        let workspace = self.workspace();
17385
17386        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17387            Ok(permalink) => {
17388                cx.update(|_, cx| {
17389                    cx.open_url(permalink.as_ref());
17390                })
17391                .ok();
17392            }
17393            Err(err) => {
17394                let message = format!("Failed to open permalink: {err}");
17395
17396                anyhow::Result::<()>::Err(err).log_err();
17397
17398                if let Some(workspace) = workspace {
17399                    workspace
17400                        .update(cx, |workspace, cx| {
17401                            struct OpenPermalinkToLine;
17402
17403                            workspace.show_toast(
17404                                Toast::new(
17405                                    NotificationId::unique::<OpenPermalinkToLine>(),
17406                                    message,
17407                                ),
17408                                cx,
17409                            )
17410                        })
17411                        .ok();
17412                }
17413            }
17414        })
17415        .detach();
17416    }
17417
17418    pub fn insert_uuid_v4(
17419        &mut self,
17420        _: &InsertUuidV4,
17421        window: &mut Window,
17422        cx: &mut Context<Self>,
17423    ) {
17424        self.insert_uuid(UuidVersion::V4, window, cx);
17425    }
17426
17427    pub fn insert_uuid_v7(
17428        &mut self,
17429        _: &InsertUuidV7,
17430        window: &mut Window,
17431        cx: &mut Context<Self>,
17432    ) {
17433        self.insert_uuid(UuidVersion::V7, window, cx);
17434    }
17435
17436    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17437        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17438        self.transact(window, cx, |this, window, cx| {
17439            let edits = this
17440                .selections
17441                .all::<Point>(cx)
17442                .into_iter()
17443                .map(|selection| {
17444                    let uuid = match version {
17445                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17446                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17447                    };
17448
17449                    (selection.range(), uuid.to_string())
17450                });
17451            this.edit(edits, cx);
17452            this.refresh_inline_completion(true, false, window, cx);
17453        });
17454    }
17455
17456    pub fn open_selections_in_multibuffer(
17457        &mut self,
17458        _: &OpenSelectionsInMultibuffer,
17459        window: &mut Window,
17460        cx: &mut Context<Self>,
17461    ) {
17462        let multibuffer = self.buffer.read(cx);
17463
17464        let Some(buffer) = multibuffer.as_singleton() else {
17465            return;
17466        };
17467
17468        let Some(workspace) = self.workspace() else {
17469            return;
17470        };
17471
17472        let locations = self
17473            .selections
17474            .disjoint_anchors()
17475            .iter()
17476            .map(|range| Location {
17477                buffer: buffer.clone(),
17478                range: range.start.text_anchor..range.end.text_anchor,
17479            })
17480            .collect::<Vec<_>>();
17481
17482        let title = multibuffer.title(cx).to_string();
17483
17484        cx.spawn_in(window, async move |_, cx| {
17485            workspace.update_in(cx, |workspace, window, cx| {
17486                Self::open_locations_in_multibuffer(
17487                    workspace,
17488                    locations,
17489                    format!("Selections for '{title}'"),
17490                    false,
17491                    MultibufferSelectionMode::All,
17492                    window,
17493                    cx,
17494                );
17495            })
17496        })
17497        .detach();
17498    }
17499
17500    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17501    /// last highlight added will be used.
17502    ///
17503    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17504    pub fn highlight_rows<T: 'static>(
17505        &mut self,
17506        range: Range<Anchor>,
17507        color: Hsla,
17508        options: RowHighlightOptions,
17509        cx: &mut Context<Self>,
17510    ) {
17511        let snapshot = self.buffer().read(cx).snapshot(cx);
17512        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17513        let ix = row_highlights.binary_search_by(|highlight| {
17514            Ordering::Equal
17515                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17516                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17517        });
17518
17519        if let Err(mut ix) = ix {
17520            let index = post_inc(&mut self.highlight_order);
17521
17522            // If this range intersects with the preceding highlight, then merge it with
17523            // the preceding highlight. Otherwise insert a new highlight.
17524            let mut merged = false;
17525            if ix > 0 {
17526                let prev_highlight = &mut row_highlights[ix - 1];
17527                if prev_highlight
17528                    .range
17529                    .end
17530                    .cmp(&range.start, &snapshot)
17531                    .is_ge()
17532                {
17533                    ix -= 1;
17534                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17535                        prev_highlight.range.end = range.end;
17536                    }
17537                    merged = true;
17538                    prev_highlight.index = index;
17539                    prev_highlight.color = color;
17540                    prev_highlight.options = options;
17541                }
17542            }
17543
17544            if !merged {
17545                row_highlights.insert(
17546                    ix,
17547                    RowHighlight {
17548                        range: range.clone(),
17549                        index,
17550                        color,
17551                        options,
17552                        type_id: TypeId::of::<T>(),
17553                    },
17554                );
17555            }
17556
17557            // If any of the following highlights intersect with this one, merge them.
17558            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17559                let highlight = &row_highlights[ix];
17560                if next_highlight
17561                    .range
17562                    .start
17563                    .cmp(&highlight.range.end, &snapshot)
17564                    .is_le()
17565                {
17566                    if next_highlight
17567                        .range
17568                        .end
17569                        .cmp(&highlight.range.end, &snapshot)
17570                        .is_gt()
17571                    {
17572                        row_highlights[ix].range.end = next_highlight.range.end;
17573                    }
17574                    row_highlights.remove(ix + 1);
17575                } else {
17576                    break;
17577                }
17578            }
17579        }
17580    }
17581
17582    /// Remove any highlighted row ranges of the given type that intersect the
17583    /// given ranges.
17584    pub fn remove_highlighted_rows<T: 'static>(
17585        &mut self,
17586        ranges_to_remove: Vec<Range<Anchor>>,
17587        cx: &mut Context<Self>,
17588    ) {
17589        let snapshot = self.buffer().read(cx).snapshot(cx);
17590        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17591        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17592        row_highlights.retain(|highlight| {
17593            while let Some(range_to_remove) = ranges_to_remove.peek() {
17594                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17595                    Ordering::Less | Ordering::Equal => {
17596                        ranges_to_remove.next();
17597                    }
17598                    Ordering::Greater => {
17599                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17600                            Ordering::Less | Ordering::Equal => {
17601                                return false;
17602                            }
17603                            Ordering::Greater => break,
17604                        }
17605                    }
17606                }
17607            }
17608
17609            true
17610        })
17611    }
17612
17613    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17614    pub fn clear_row_highlights<T: 'static>(&mut self) {
17615        self.highlighted_rows.remove(&TypeId::of::<T>());
17616    }
17617
17618    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17619    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17620        self.highlighted_rows
17621            .get(&TypeId::of::<T>())
17622            .map_or(&[] as &[_], |vec| vec.as_slice())
17623            .iter()
17624            .map(|highlight| (highlight.range.clone(), highlight.color))
17625    }
17626
17627    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17628    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17629    /// Allows to ignore certain kinds of highlights.
17630    pub fn highlighted_display_rows(
17631        &self,
17632        window: &mut Window,
17633        cx: &mut App,
17634    ) -> BTreeMap<DisplayRow, LineHighlight> {
17635        let snapshot = self.snapshot(window, cx);
17636        let mut used_highlight_orders = HashMap::default();
17637        self.highlighted_rows
17638            .iter()
17639            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17640            .fold(
17641                BTreeMap::<DisplayRow, LineHighlight>::new(),
17642                |mut unique_rows, highlight| {
17643                    let start = highlight.range.start.to_display_point(&snapshot);
17644                    let end = highlight.range.end.to_display_point(&snapshot);
17645                    let start_row = start.row().0;
17646                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17647                        && end.column() == 0
17648                    {
17649                        end.row().0.saturating_sub(1)
17650                    } else {
17651                        end.row().0
17652                    };
17653                    for row in start_row..=end_row {
17654                        let used_index =
17655                            used_highlight_orders.entry(row).or_insert(highlight.index);
17656                        if highlight.index >= *used_index {
17657                            *used_index = highlight.index;
17658                            unique_rows.insert(
17659                                DisplayRow(row),
17660                                LineHighlight {
17661                                    include_gutter: highlight.options.include_gutter,
17662                                    border: None,
17663                                    background: highlight.color.into(),
17664                                    type_id: Some(highlight.type_id),
17665                                },
17666                            );
17667                        }
17668                    }
17669                    unique_rows
17670                },
17671            )
17672    }
17673
17674    pub fn highlighted_display_row_for_autoscroll(
17675        &self,
17676        snapshot: &DisplaySnapshot,
17677    ) -> Option<DisplayRow> {
17678        self.highlighted_rows
17679            .values()
17680            .flat_map(|highlighted_rows| highlighted_rows.iter())
17681            .filter_map(|highlight| {
17682                if highlight.options.autoscroll {
17683                    Some(highlight.range.start.to_display_point(snapshot).row())
17684                } else {
17685                    None
17686                }
17687            })
17688            .min()
17689    }
17690
17691    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17692        self.highlight_background::<SearchWithinRange>(
17693            ranges,
17694            |colors| colors.editor_document_highlight_read_background,
17695            cx,
17696        )
17697    }
17698
17699    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17700        self.breadcrumb_header = Some(new_header);
17701    }
17702
17703    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17704        self.clear_background_highlights::<SearchWithinRange>(cx);
17705    }
17706
17707    pub fn highlight_background<T: 'static>(
17708        &mut self,
17709        ranges: &[Range<Anchor>],
17710        color_fetcher: fn(&ThemeColors) -> Hsla,
17711        cx: &mut Context<Self>,
17712    ) {
17713        self.background_highlights
17714            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17715        self.scrollbar_marker_state.dirty = true;
17716        cx.notify();
17717    }
17718
17719    pub fn clear_background_highlights<T: 'static>(
17720        &mut self,
17721        cx: &mut Context<Self>,
17722    ) -> Option<BackgroundHighlight> {
17723        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17724        if !text_highlights.1.is_empty() {
17725            self.scrollbar_marker_state.dirty = true;
17726            cx.notify();
17727        }
17728        Some(text_highlights)
17729    }
17730
17731    pub fn highlight_gutter<T: 'static>(
17732        &mut self,
17733        ranges: &[Range<Anchor>],
17734        color_fetcher: fn(&App) -> Hsla,
17735        cx: &mut Context<Self>,
17736    ) {
17737        self.gutter_highlights
17738            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17739        cx.notify();
17740    }
17741
17742    pub fn clear_gutter_highlights<T: 'static>(
17743        &mut self,
17744        cx: &mut Context<Self>,
17745    ) -> Option<GutterHighlight> {
17746        cx.notify();
17747        self.gutter_highlights.remove(&TypeId::of::<T>())
17748    }
17749
17750    #[cfg(feature = "test-support")]
17751    pub fn all_text_background_highlights(
17752        &self,
17753        window: &mut Window,
17754        cx: &mut Context<Self>,
17755    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17756        let snapshot = self.snapshot(window, cx);
17757        let buffer = &snapshot.buffer_snapshot;
17758        let start = buffer.anchor_before(0);
17759        let end = buffer.anchor_after(buffer.len());
17760        let theme = cx.theme().colors();
17761        self.background_highlights_in_range(start..end, &snapshot, theme)
17762    }
17763
17764    #[cfg(feature = "test-support")]
17765    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17766        let snapshot = self.buffer().read(cx).snapshot(cx);
17767
17768        let highlights = self
17769            .background_highlights
17770            .get(&TypeId::of::<items::BufferSearchHighlights>());
17771
17772        if let Some((_color, ranges)) = highlights {
17773            ranges
17774                .iter()
17775                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17776                .collect_vec()
17777        } else {
17778            vec![]
17779        }
17780    }
17781
17782    fn document_highlights_for_position<'a>(
17783        &'a self,
17784        position: Anchor,
17785        buffer: &'a MultiBufferSnapshot,
17786    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17787        let read_highlights = self
17788            .background_highlights
17789            .get(&TypeId::of::<DocumentHighlightRead>())
17790            .map(|h| &h.1);
17791        let write_highlights = self
17792            .background_highlights
17793            .get(&TypeId::of::<DocumentHighlightWrite>())
17794            .map(|h| &h.1);
17795        let left_position = position.bias_left(buffer);
17796        let right_position = position.bias_right(buffer);
17797        read_highlights
17798            .into_iter()
17799            .chain(write_highlights)
17800            .flat_map(move |ranges| {
17801                let start_ix = match ranges.binary_search_by(|probe| {
17802                    let cmp = probe.end.cmp(&left_position, buffer);
17803                    if cmp.is_ge() {
17804                        Ordering::Greater
17805                    } else {
17806                        Ordering::Less
17807                    }
17808                }) {
17809                    Ok(i) | Err(i) => i,
17810                };
17811
17812                ranges[start_ix..]
17813                    .iter()
17814                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17815            })
17816    }
17817
17818    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17819        self.background_highlights
17820            .get(&TypeId::of::<T>())
17821            .map_or(false, |(_, highlights)| !highlights.is_empty())
17822    }
17823
17824    pub fn background_highlights_in_range(
17825        &self,
17826        search_range: Range<Anchor>,
17827        display_snapshot: &DisplaySnapshot,
17828        theme: &ThemeColors,
17829    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17830        let mut results = Vec::new();
17831        for (color_fetcher, ranges) in self.background_highlights.values() {
17832            let color = color_fetcher(theme);
17833            let start_ix = match ranges.binary_search_by(|probe| {
17834                let cmp = probe
17835                    .end
17836                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17837                if cmp.is_gt() {
17838                    Ordering::Greater
17839                } else {
17840                    Ordering::Less
17841                }
17842            }) {
17843                Ok(i) | Err(i) => i,
17844            };
17845            for range in &ranges[start_ix..] {
17846                if range
17847                    .start
17848                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17849                    .is_ge()
17850                {
17851                    break;
17852                }
17853
17854                let start = range.start.to_display_point(display_snapshot);
17855                let end = range.end.to_display_point(display_snapshot);
17856                results.push((start..end, color))
17857            }
17858        }
17859        results
17860    }
17861
17862    pub fn background_highlight_row_ranges<T: 'static>(
17863        &self,
17864        search_range: Range<Anchor>,
17865        display_snapshot: &DisplaySnapshot,
17866        count: usize,
17867    ) -> Vec<RangeInclusive<DisplayPoint>> {
17868        let mut results = Vec::new();
17869        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17870            return vec![];
17871        };
17872
17873        let start_ix = match ranges.binary_search_by(|probe| {
17874            let cmp = probe
17875                .end
17876                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17877            if cmp.is_gt() {
17878                Ordering::Greater
17879            } else {
17880                Ordering::Less
17881            }
17882        }) {
17883            Ok(i) | Err(i) => i,
17884        };
17885        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17886            if let (Some(start_display), Some(end_display)) = (start, end) {
17887                results.push(
17888                    start_display.to_display_point(display_snapshot)
17889                        ..=end_display.to_display_point(display_snapshot),
17890                );
17891            }
17892        };
17893        let mut start_row: Option<Point> = None;
17894        let mut end_row: Option<Point> = None;
17895        if ranges.len() > count {
17896            return Vec::new();
17897        }
17898        for range in &ranges[start_ix..] {
17899            if range
17900                .start
17901                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17902                .is_ge()
17903            {
17904                break;
17905            }
17906            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17907            if let Some(current_row) = &end_row {
17908                if end.row == current_row.row {
17909                    continue;
17910                }
17911            }
17912            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17913            if start_row.is_none() {
17914                assert_eq!(end_row, None);
17915                start_row = Some(start);
17916                end_row = Some(end);
17917                continue;
17918            }
17919            if let Some(current_end) = end_row.as_mut() {
17920                if start.row > current_end.row + 1 {
17921                    push_region(start_row, end_row);
17922                    start_row = Some(start);
17923                    end_row = Some(end);
17924                } else {
17925                    // Merge two hunks.
17926                    *current_end = end;
17927                }
17928            } else {
17929                unreachable!();
17930            }
17931        }
17932        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17933        push_region(start_row, end_row);
17934        results
17935    }
17936
17937    pub fn gutter_highlights_in_range(
17938        &self,
17939        search_range: Range<Anchor>,
17940        display_snapshot: &DisplaySnapshot,
17941        cx: &App,
17942    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17943        let mut results = Vec::new();
17944        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17945            let color = color_fetcher(cx);
17946            let start_ix = match ranges.binary_search_by(|probe| {
17947                let cmp = probe
17948                    .end
17949                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17950                if cmp.is_gt() {
17951                    Ordering::Greater
17952                } else {
17953                    Ordering::Less
17954                }
17955            }) {
17956                Ok(i) | Err(i) => i,
17957            };
17958            for range in &ranges[start_ix..] {
17959                if range
17960                    .start
17961                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17962                    .is_ge()
17963                {
17964                    break;
17965                }
17966
17967                let start = range.start.to_display_point(display_snapshot);
17968                let end = range.end.to_display_point(display_snapshot);
17969                results.push((start..end, color))
17970            }
17971        }
17972        results
17973    }
17974
17975    /// Get the text ranges corresponding to the redaction query
17976    pub fn redacted_ranges(
17977        &self,
17978        search_range: Range<Anchor>,
17979        display_snapshot: &DisplaySnapshot,
17980        cx: &App,
17981    ) -> Vec<Range<DisplayPoint>> {
17982        display_snapshot
17983            .buffer_snapshot
17984            .redacted_ranges(search_range, |file| {
17985                if let Some(file) = file {
17986                    file.is_private()
17987                        && EditorSettings::get(
17988                            Some(SettingsLocation {
17989                                worktree_id: file.worktree_id(cx),
17990                                path: file.path().as_ref(),
17991                            }),
17992                            cx,
17993                        )
17994                        .redact_private_values
17995                } else {
17996                    false
17997                }
17998            })
17999            .map(|range| {
18000                range.start.to_display_point(display_snapshot)
18001                    ..range.end.to_display_point(display_snapshot)
18002            })
18003            .collect()
18004    }
18005
18006    pub fn highlight_text<T: 'static>(
18007        &mut self,
18008        ranges: Vec<Range<Anchor>>,
18009        style: HighlightStyle,
18010        cx: &mut Context<Self>,
18011    ) {
18012        self.display_map.update(cx, |map, _| {
18013            map.highlight_text(TypeId::of::<T>(), ranges, style)
18014        });
18015        cx.notify();
18016    }
18017
18018    pub(crate) fn highlight_inlays<T: 'static>(
18019        &mut self,
18020        highlights: Vec<InlayHighlight>,
18021        style: HighlightStyle,
18022        cx: &mut Context<Self>,
18023    ) {
18024        self.display_map.update(cx, |map, _| {
18025            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18026        });
18027        cx.notify();
18028    }
18029
18030    pub fn text_highlights<'a, T: 'static>(
18031        &'a self,
18032        cx: &'a App,
18033    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18034        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18035    }
18036
18037    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18038        let cleared = self
18039            .display_map
18040            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18041        if cleared {
18042            cx.notify();
18043        }
18044    }
18045
18046    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18047        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18048            && self.focus_handle.is_focused(window)
18049    }
18050
18051    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18052        self.show_cursor_when_unfocused = is_enabled;
18053        cx.notify();
18054    }
18055
18056    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18057        cx.notify();
18058    }
18059
18060    fn on_debug_session_event(
18061        &mut self,
18062        _session: Entity<Session>,
18063        event: &SessionEvent,
18064        cx: &mut Context<Self>,
18065    ) {
18066        match event {
18067            SessionEvent::InvalidateInlineValue => {
18068                self.refresh_inline_values(cx);
18069            }
18070            _ => {}
18071        }
18072    }
18073
18074    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18075        let Some(project) = self.project.clone() else {
18076            return;
18077        };
18078
18079        if !self.inline_value_cache.enabled {
18080            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18081            self.splice_inlays(&inlays, Vec::new(), cx);
18082            return;
18083        }
18084
18085        let current_execution_position = self
18086            .highlighted_rows
18087            .get(&TypeId::of::<ActiveDebugLine>())
18088            .and_then(|lines| lines.last().map(|line| line.range.start));
18089
18090        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18091            let inline_values = editor
18092                .update(cx, |editor, cx| {
18093                    let Some(current_execution_position) = current_execution_position else {
18094                        return Some(Task::ready(Ok(Vec::new())));
18095                    };
18096
18097                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18098                        let snapshot = buffer.snapshot(cx);
18099
18100                        let excerpt = snapshot.excerpt_containing(
18101                            current_execution_position..current_execution_position,
18102                        )?;
18103
18104                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18105                    })?;
18106
18107                    let range =
18108                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18109
18110                    project.inline_values(buffer, range, cx)
18111                })
18112                .ok()
18113                .flatten()?
18114                .await
18115                .context("refreshing debugger inlays")
18116                .log_err()?;
18117
18118            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18119
18120            for (buffer_id, inline_value) in inline_values
18121                .into_iter()
18122                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18123            {
18124                buffer_inline_values
18125                    .entry(buffer_id)
18126                    .or_default()
18127                    .push(inline_value);
18128            }
18129
18130            editor
18131                .update(cx, |editor, cx| {
18132                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18133                    let mut new_inlays = Vec::default();
18134
18135                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18136                        let buffer_id = buffer_snapshot.remote_id();
18137                        buffer_inline_values
18138                            .get(&buffer_id)
18139                            .into_iter()
18140                            .flatten()
18141                            .for_each(|hint| {
18142                                let inlay = Inlay::debugger_hint(
18143                                    post_inc(&mut editor.next_inlay_id),
18144                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18145                                    hint.text(),
18146                                );
18147
18148                                new_inlays.push(inlay);
18149                            });
18150                    }
18151
18152                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18153                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18154
18155                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18156                })
18157                .ok()?;
18158            Some(())
18159        });
18160    }
18161
18162    fn on_buffer_event(
18163        &mut self,
18164        multibuffer: &Entity<MultiBuffer>,
18165        event: &multi_buffer::Event,
18166        window: &mut Window,
18167        cx: &mut Context<Self>,
18168    ) {
18169        match event {
18170            multi_buffer::Event::Edited {
18171                singleton_buffer_edited,
18172                edited_buffer: buffer_edited,
18173            } => {
18174                self.scrollbar_marker_state.dirty = true;
18175                self.active_indent_guides_state.dirty = true;
18176                self.refresh_active_diagnostics(cx);
18177                self.refresh_code_actions(window, cx);
18178                self.refresh_selected_text_highlights(true, window, cx);
18179                refresh_matching_bracket_highlights(self, window, cx);
18180                if self.has_active_inline_completion() {
18181                    self.update_visible_inline_completion(window, cx);
18182                }
18183                if let Some(buffer) = buffer_edited {
18184                    let buffer_id = buffer.read(cx).remote_id();
18185                    if !self.registered_buffers.contains_key(&buffer_id) {
18186                        if let Some(project) = self.project.as_ref() {
18187                            project.update(cx, |project, cx| {
18188                                self.registered_buffers.insert(
18189                                    buffer_id,
18190                                    project.register_buffer_with_language_servers(&buffer, cx),
18191                                );
18192                            })
18193                        }
18194                    }
18195                }
18196                cx.emit(EditorEvent::BufferEdited);
18197                cx.emit(SearchEvent::MatchesInvalidated);
18198                if *singleton_buffer_edited {
18199                    if let Some(project) = &self.project {
18200                        #[allow(clippy::mutable_key_type)]
18201                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18202                            multibuffer
18203                                .all_buffers()
18204                                .into_iter()
18205                                .filter_map(|buffer| {
18206                                    buffer.update(cx, |buffer, cx| {
18207                                        let language = buffer.language()?;
18208                                        let should_discard = project.update(cx, |project, cx| {
18209                                            project.is_local()
18210                                                && !project.has_language_servers_for(buffer, cx)
18211                                        });
18212                                        should_discard.not().then_some(language.clone())
18213                                    })
18214                                })
18215                                .collect::<HashSet<_>>()
18216                        });
18217                        if !languages_affected.is_empty() {
18218                            self.refresh_inlay_hints(
18219                                InlayHintRefreshReason::BufferEdited(languages_affected),
18220                                cx,
18221                            );
18222                        }
18223                    }
18224                }
18225
18226                let Some(project) = &self.project else { return };
18227                let (telemetry, is_via_ssh) = {
18228                    let project = project.read(cx);
18229                    let telemetry = project.client().telemetry().clone();
18230                    let is_via_ssh = project.is_via_ssh();
18231                    (telemetry, is_via_ssh)
18232                };
18233                refresh_linked_ranges(self, window, cx);
18234                telemetry.log_edit_event("editor", is_via_ssh);
18235            }
18236            multi_buffer::Event::ExcerptsAdded {
18237                buffer,
18238                predecessor,
18239                excerpts,
18240            } => {
18241                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18242                let buffer_id = buffer.read(cx).remote_id();
18243                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18244                    if let Some(project) = &self.project {
18245                        update_uncommitted_diff_for_buffer(
18246                            cx.entity(),
18247                            project,
18248                            [buffer.clone()],
18249                            self.buffer.clone(),
18250                            cx,
18251                        )
18252                        .detach();
18253                    }
18254                }
18255                cx.emit(EditorEvent::ExcerptsAdded {
18256                    buffer: buffer.clone(),
18257                    predecessor: *predecessor,
18258                    excerpts: excerpts.clone(),
18259                });
18260                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18261            }
18262            multi_buffer::Event::ExcerptsRemoved {
18263                ids,
18264                removed_buffer_ids,
18265            } => {
18266                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18267                let buffer = self.buffer.read(cx);
18268                self.registered_buffers
18269                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18270                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18271                cx.emit(EditorEvent::ExcerptsRemoved {
18272                    ids: ids.clone(),
18273                    removed_buffer_ids: removed_buffer_ids.clone(),
18274                })
18275            }
18276            multi_buffer::Event::ExcerptsEdited {
18277                excerpt_ids,
18278                buffer_ids,
18279            } => {
18280                self.display_map.update(cx, |map, cx| {
18281                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18282                });
18283                cx.emit(EditorEvent::ExcerptsEdited {
18284                    ids: excerpt_ids.clone(),
18285                })
18286            }
18287            multi_buffer::Event::ExcerptsExpanded { ids } => {
18288                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18289                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18290            }
18291            multi_buffer::Event::Reparsed(buffer_id) => {
18292                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18293                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18294
18295                cx.emit(EditorEvent::Reparsed(*buffer_id));
18296            }
18297            multi_buffer::Event::DiffHunksToggled => {
18298                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18299            }
18300            multi_buffer::Event::LanguageChanged(buffer_id) => {
18301                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18302                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18303                cx.emit(EditorEvent::Reparsed(*buffer_id));
18304                cx.notify();
18305            }
18306            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18307            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18308            multi_buffer::Event::FileHandleChanged
18309            | multi_buffer::Event::Reloaded
18310            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18311            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18312            multi_buffer::Event::DiagnosticsUpdated => {
18313                self.refresh_active_diagnostics(cx);
18314                self.refresh_inline_diagnostics(true, window, cx);
18315                self.scrollbar_marker_state.dirty = true;
18316                cx.notify();
18317            }
18318            _ => {}
18319        };
18320    }
18321
18322    pub fn start_temporary_diff_override(&mut self) {
18323        self.load_diff_task.take();
18324        self.temporary_diff_override = true;
18325    }
18326
18327    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18328        self.temporary_diff_override = false;
18329        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18330        self.buffer.update(cx, |buffer, cx| {
18331            buffer.set_all_diff_hunks_collapsed(cx);
18332        });
18333
18334        if let Some(project) = self.project.clone() {
18335            self.load_diff_task = Some(
18336                update_uncommitted_diff_for_buffer(
18337                    cx.entity(),
18338                    &project,
18339                    self.buffer.read(cx).all_buffers(),
18340                    self.buffer.clone(),
18341                    cx,
18342                )
18343                .shared(),
18344            );
18345        }
18346    }
18347
18348    fn on_display_map_changed(
18349        &mut self,
18350        _: Entity<DisplayMap>,
18351        _: &mut Window,
18352        cx: &mut Context<Self>,
18353    ) {
18354        cx.notify();
18355    }
18356
18357    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18358        let new_severity = if self.diagnostics_enabled() {
18359            EditorSettings::get_global(cx)
18360                .diagnostics_max_severity
18361                .unwrap_or(DiagnosticSeverity::Hint)
18362        } else {
18363            DiagnosticSeverity::Off
18364        };
18365        self.set_max_diagnostics_severity(new_severity, cx);
18366        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18367        self.update_edit_prediction_settings(cx);
18368        self.refresh_inline_completion(true, false, window, cx);
18369        self.refresh_inlay_hints(
18370            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18371                self.selections.newest_anchor().head(),
18372                &self.buffer.read(cx).snapshot(cx),
18373                cx,
18374            )),
18375            cx,
18376        );
18377
18378        let old_cursor_shape = self.cursor_shape;
18379
18380        {
18381            let editor_settings = EditorSettings::get_global(cx);
18382            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18383            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18384            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18385            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18386        }
18387
18388        if old_cursor_shape != self.cursor_shape {
18389            cx.emit(EditorEvent::CursorShapeChanged);
18390        }
18391
18392        let project_settings = ProjectSettings::get_global(cx);
18393        self.serialize_dirty_buffers =
18394            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18395
18396        if self.mode.is_full() {
18397            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18398            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18399            if self.show_inline_diagnostics != show_inline_diagnostics {
18400                self.show_inline_diagnostics = show_inline_diagnostics;
18401                self.refresh_inline_diagnostics(false, window, cx);
18402            }
18403
18404            if self.git_blame_inline_enabled != inline_blame_enabled {
18405                self.toggle_git_blame_inline_internal(false, window, cx);
18406            }
18407
18408            let minimap_settings = EditorSettings::get_global(cx).minimap;
18409            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18410                self.set_minimap_visibility(
18411                    self.minimap_visibility.toggle_visibility(),
18412                    window,
18413                    cx,
18414                );
18415            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18416                minimap_entity.update(cx, |minimap_editor, cx| {
18417                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18418                })
18419            }
18420        }
18421
18422        cx.notify();
18423    }
18424
18425    pub fn set_searchable(&mut self, searchable: bool) {
18426        self.searchable = searchable;
18427    }
18428
18429    pub fn searchable(&self) -> bool {
18430        self.searchable
18431    }
18432
18433    fn open_proposed_changes_editor(
18434        &mut self,
18435        _: &OpenProposedChangesEditor,
18436        window: &mut Window,
18437        cx: &mut Context<Self>,
18438    ) {
18439        let Some(workspace) = self.workspace() else {
18440            cx.propagate();
18441            return;
18442        };
18443
18444        let selections = self.selections.all::<usize>(cx);
18445        let multi_buffer = self.buffer.read(cx);
18446        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18447        let mut new_selections_by_buffer = HashMap::default();
18448        for selection in selections {
18449            for (buffer, range, _) in
18450                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18451            {
18452                let mut range = range.to_point(buffer);
18453                range.start.column = 0;
18454                range.end.column = buffer.line_len(range.end.row);
18455                new_selections_by_buffer
18456                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18457                    .or_insert(Vec::new())
18458                    .push(range)
18459            }
18460        }
18461
18462        let proposed_changes_buffers = new_selections_by_buffer
18463            .into_iter()
18464            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18465            .collect::<Vec<_>>();
18466        let proposed_changes_editor = cx.new(|cx| {
18467            ProposedChangesEditor::new(
18468                "Proposed changes",
18469                proposed_changes_buffers,
18470                self.project.clone(),
18471                window,
18472                cx,
18473            )
18474        });
18475
18476        window.defer(cx, move |window, cx| {
18477            workspace.update(cx, |workspace, cx| {
18478                workspace.active_pane().update(cx, |pane, cx| {
18479                    pane.add_item(
18480                        Box::new(proposed_changes_editor),
18481                        true,
18482                        true,
18483                        None,
18484                        window,
18485                        cx,
18486                    );
18487                });
18488            });
18489        });
18490    }
18491
18492    pub fn open_excerpts_in_split(
18493        &mut self,
18494        _: &OpenExcerptsSplit,
18495        window: &mut Window,
18496        cx: &mut Context<Self>,
18497    ) {
18498        self.open_excerpts_common(None, true, window, cx)
18499    }
18500
18501    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18502        self.open_excerpts_common(None, false, window, cx)
18503    }
18504
18505    fn open_excerpts_common(
18506        &mut self,
18507        jump_data: Option<JumpData>,
18508        split: bool,
18509        window: &mut Window,
18510        cx: &mut Context<Self>,
18511    ) {
18512        let Some(workspace) = self.workspace() else {
18513            cx.propagate();
18514            return;
18515        };
18516
18517        if self.buffer.read(cx).is_singleton() {
18518            cx.propagate();
18519            return;
18520        }
18521
18522        let mut new_selections_by_buffer = HashMap::default();
18523        match &jump_data {
18524            Some(JumpData::MultiBufferPoint {
18525                excerpt_id,
18526                position,
18527                anchor,
18528                line_offset_from_top,
18529            }) => {
18530                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18531                if let Some(buffer) = multi_buffer_snapshot
18532                    .buffer_id_for_excerpt(*excerpt_id)
18533                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18534                {
18535                    let buffer_snapshot = buffer.read(cx).snapshot();
18536                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18537                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18538                    } else {
18539                        buffer_snapshot.clip_point(*position, Bias::Left)
18540                    };
18541                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18542                    new_selections_by_buffer.insert(
18543                        buffer,
18544                        (
18545                            vec![jump_to_offset..jump_to_offset],
18546                            Some(*line_offset_from_top),
18547                        ),
18548                    );
18549                }
18550            }
18551            Some(JumpData::MultiBufferRow {
18552                row,
18553                line_offset_from_top,
18554            }) => {
18555                let point = MultiBufferPoint::new(row.0, 0);
18556                if let Some((buffer, buffer_point, _)) =
18557                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18558                {
18559                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18560                    new_selections_by_buffer
18561                        .entry(buffer)
18562                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18563                        .0
18564                        .push(buffer_offset..buffer_offset)
18565                }
18566            }
18567            None => {
18568                let selections = self.selections.all::<usize>(cx);
18569                let multi_buffer = self.buffer.read(cx);
18570                for selection in selections {
18571                    for (snapshot, range, _, anchor) in multi_buffer
18572                        .snapshot(cx)
18573                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18574                    {
18575                        if let Some(anchor) = anchor {
18576                            // selection is in a deleted hunk
18577                            let Some(buffer_id) = anchor.buffer_id else {
18578                                continue;
18579                            };
18580                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18581                                continue;
18582                            };
18583                            let offset = text::ToOffset::to_offset(
18584                                &anchor.text_anchor,
18585                                &buffer_handle.read(cx).snapshot(),
18586                            );
18587                            let range = offset..offset;
18588                            new_selections_by_buffer
18589                                .entry(buffer_handle)
18590                                .or_insert((Vec::new(), None))
18591                                .0
18592                                .push(range)
18593                        } else {
18594                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18595                            else {
18596                                continue;
18597                            };
18598                            new_selections_by_buffer
18599                                .entry(buffer_handle)
18600                                .or_insert((Vec::new(), None))
18601                                .0
18602                                .push(range)
18603                        }
18604                    }
18605                }
18606            }
18607        }
18608
18609        new_selections_by_buffer
18610            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18611
18612        if new_selections_by_buffer.is_empty() {
18613            return;
18614        }
18615
18616        // We defer the pane interaction because we ourselves are a workspace item
18617        // and activating a new item causes the pane to call a method on us reentrantly,
18618        // which panics if we're on the stack.
18619        window.defer(cx, move |window, cx| {
18620            workspace.update(cx, |workspace, cx| {
18621                let pane = if split {
18622                    workspace.adjacent_pane(window, cx)
18623                } else {
18624                    workspace.active_pane().clone()
18625                };
18626
18627                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18628                    let editor = buffer
18629                        .read(cx)
18630                        .file()
18631                        .is_none()
18632                        .then(|| {
18633                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18634                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18635                            // Instead, we try to activate the existing editor in the pane first.
18636                            let (editor, pane_item_index) =
18637                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18638                                    let editor = item.downcast::<Editor>()?;
18639                                    let singleton_buffer =
18640                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18641                                    if singleton_buffer == buffer {
18642                                        Some((editor, i))
18643                                    } else {
18644                                        None
18645                                    }
18646                                })?;
18647                            pane.update(cx, |pane, cx| {
18648                                pane.activate_item(pane_item_index, true, true, window, cx)
18649                            });
18650                            Some(editor)
18651                        })
18652                        .flatten()
18653                        .unwrap_or_else(|| {
18654                            workspace.open_project_item::<Self>(
18655                                pane.clone(),
18656                                buffer,
18657                                true,
18658                                true,
18659                                window,
18660                                cx,
18661                            )
18662                        });
18663
18664                    editor.update(cx, |editor, cx| {
18665                        let autoscroll = match scroll_offset {
18666                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18667                            None => Autoscroll::newest(),
18668                        };
18669                        let nav_history = editor.nav_history.take();
18670                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18671                            s.select_ranges(ranges);
18672                        });
18673                        editor.nav_history = nav_history;
18674                    });
18675                }
18676            })
18677        });
18678    }
18679
18680    // For now, don't allow opening excerpts in buffers that aren't backed by
18681    // regular project files.
18682    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18683        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18684    }
18685
18686    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18687        let snapshot = self.buffer.read(cx).read(cx);
18688        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18689        Some(
18690            ranges
18691                .iter()
18692                .map(move |range| {
18693                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18694                })
18695                .collect(),
18696        )
18697    }
18698
18699    fn selection_replacement_ranges(
18700        &self,
18701        range: Range<OffsetUtf16>,
18702        cx: &mut App,
18703    ) -> Vec<Range<OffsetUtf16>> {
18704        let selections = self.selections.all::<OffsetUtf16>(cx);
18705        let newest_selection = selections
18706            .iter()
18707            .max_by_key(|selection| selection.id)
18708            .unwrap();
18709        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18710        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18711        let snapshot = self.buffer.read(cx).read(cx);
18712        selections
18713            .into_iter()
18714            .map(|mut selection| {
18715                selection.start.0 =
18716                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18717                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18718                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18719                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18720            })
18721            .collect()
18722    }
18723
18724    fn report_editor_event(
18725        &self,
18726        event_type: &'static str,
18727        file_extension: Option<String>,
18728        cx: &App,
18729    ) {
18730        if cfg!(any(test, feature = "test-support")) {
18731            return;
18732        }
18733
18734        let Some(project) = &self.project else { return };
18735
18736        // If None, we are in a file without an extension
18737        let file = self
18738            .buffer
18739            .read(cx)
18740            .as_singleton()
18741            .and_then(|b| b.read(cx).file());
18742        let file_extension = file_extension.or(file
18743            .as_ref()
18744            .and_then(|file| Path::new(file.file_name(cx)).extension())
18745            .and_then(|e| e.to_str())
18746            .map(|a| a.to_string()));
18747
18748        let vim_mode = vim_enabled(cx);
18749
18750        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18751        let copilot_enabled = edit_predictions_provider
18752            == language::language_settings::EditPredictionProvider::Copilot;
18753        let copilot_enabled_for_language = self
18754            .buffer
18755            .read(cx)
18756            .language_settings(cx)
18757            .show_edit_predictions;
18758
18759        let project = project.read(cx);
18760        telemetry::event!(
18761            event_type,
18762            file_extension,
18763            vim_mode,
18764            copilot_enabled,
18765            copilot_enabled_for_language,
18766            edit_predictions_provider,
18767            is_via_ssh = project.is_via_ssh(),
18768        );
18769    }
18770
18771    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18772    /// with each line being an array of {text, highlight} objects.
18773    fn copy_highlight_json(
18774        &mut self,
18775        _: &CopyHighlightJson,
18776        window: &mut Window,
18777        cx: &mut Context<Self>,
18778    ) {
18779        #[derive(Serialize)]
18780        struct Chunk<'a> {
18781            text: String,
18782            highlight: Option<&'a str>,
18783        }
18784
18785        let snapshot = self.buffer.read(cx).snapshot(cx);
18786        let range = self
18787            .selected_text_range(false, window, cx)
18788            .and_then(|selection| {
18789                if selection.range.is_empty() {
18790                    None
18791                } else {
18792                    Some(selection.range)
18793                }
18794            })
18795            .unwrap_or_else(|| 0..snapshot.len());
18796
18797        let chunks = snapshot.chunks(range, true);
18798        let mut lines = Vec::new();
18799        let mut line: VecDeque<Chunk> = VecDeque::new();
18800
18801        let Some(style) = self.style.as_ref() else {
18802            return;
18803        };
18804
18805        for chunk in chunks {
18806            let highlight = chunk
18807                .syntax_highlight_id
18808                .and_then(|id| id.name(&style.syntax));
18809            let mut chunk_lines = chunk.text.split('\n').peekable();
18810            while let Some(text) = chunk_lines.next() {
18811                let mut merged_with_last_token = false;
18812                if let Some(last_token) = line.back_mut() {
18813                    if last_token.highlight == highlight {
18814                        last_token.text.push_str(text);
18815                        merged_with_last_token = true;
18816                    }
18817                }
18818
18819                if !merged_with_last_token {
18820                    line.push_back(Chunk {
18821                        text: text.into(),
18822                        highlight,
18823                    });
18824                }
18825
18826                if chunk_lines.peek().is_some() {
18827                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18828                        line.pop_front();
18829                    }
18830                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18831                        line.pop_back();
18832                    }
18833
18834                    lines.push(mem::take(&mut line));
18835                }
18836            }
18837        }
18838
18839        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18840            return;
18841        };
18842        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18843    }
18844
18845    pub fn open_context_menu(
18846        &mut self,
18847        _: &OpenContextMenu,
18848        window: &mut Window,
18849        cx: &mut Context<Self>,
18850    ) {
18851        self.request_autoscroll(Autoscroll::newest(), cx);
18852        let position = self.selections.newest_display(cx).start;
18853        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18854    }
18855
18856    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18857        &self.inlay_hint_cache
18858    }
18859
18860    pub fn replay_insert_event(
18861        &mut self,
18862        text: &str,
18863        relative_utf16_range: Option<Range<isize>>,
18864        window: &mut Window,
18865        cx: &mut Context<Self>,
18866    ) {
18867        if !self.input_enabled {
18868            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18869            return;
18870        }
18871        if let Some(relative_utf16_range) = relative_utf16_range {
18872            let selections = self.selections.all::<OffsetUtf16>(cx);
18873            self.change_selections(None, window, cx, |s| {
18874                let new_ranges = selections.into_iter().map(|range| {
18875                    let start = OffsetUtf16(
18876                        range
18877                            .head()
18878                            .0
18879                            .saturating_add_signed(relative_utf16_range.start),
18880                    );
18881                    let end = OffsetUtf16(
18882                        range
18883                            .head()
18884                            .0
18885                            .saturating_add_signed(relative_utf16_range.end),
18886                    );
18887                    start..end
18888                });
18889                s.select_ranges(new_ranges);
18890            });
18891        }
18892
18893        self.handle_input(text, window, cx);
18894    }
18895
18896    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18897        let Some(provider) = self.semantics_provider.as_ref() else {
18898            return false;
18899        };
18900
18901        let mut supports = false;
18902        self.buffer().update(cx, |this, cx| {
18903            this.for_each_buffer(|buffer| {
18904                supports |= provider.supports_inlay_hints(buffer, cx);
18905            });
18906        });
18907
18908        supports
18909    }
18910
18911    pub fn is_focused(&self, window: &Window) -> bool {
18912        self.focus_handle.is_focused(window)
18913    }
18914
18915    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18916        cx.emit(EditorEvent::Focused);
18917
18918        if let Some(descendant) = self
18919            .last_focused_descendant
18920            .take()
18921            .and_then(|descendant| descendant.upgrade())
18922        {
18923            window.focus(&descendant);
18924        } else {
18925            if let Some(blame) = self.blame.as_ref() {
18926                blame.update(cx, GitBlame::focus)
18927            }
18928
18929            self.blink_manager.update(cx, BlinkManager::enable);
18930            self.show_cursor_names(window, cx);
18931            self.buffer.update(cx, |buffer, cx| {
18932                buffer.finalize_last_transaction(cx);
18933                if self.leader_id.is_none() {
18934                    buffer.set_active_selections(
18935                        &self.selections.disjoint_anchors(),
18936                        self.selections.line_mode,
18937                        self.cursor_shape,
18938                        cx,
18939                    );
18940                }
18941            });
18942        }
18943    }
18944
18945    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18946        cx.emit(EditorEvent::FocusedIn)
18947    }
18948
18949    fn handle_focus_out(
18950        &mut self,
18951        event: FocusOutEvent,
18952        _window: &mut Window,
18953        cx: &mut Context<Self>,
18954    ) {
18955        if event.blurred != self.focus_handle {
18956            self.last_focused_descendant = Some(event.blurred);
18957        }
18958        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18959    }
18960
18961    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18962        self.blink_manager.update(cx, BlinkManager::disable);
18963        self.buffer
18964            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18965
18966        if let Some(blame) = self.blame.as_ref() {
18967            blame.update(cx, GitBlame::blur)
18968        }
18969        if !self.hover_state.focused(window, cx) {
18970            hide_hover(self, cx);
18971        }
18972        if !self
18973            .context_menu
18974            .borrow()
18975            .as_ref()
18976            .is_some_and(|context_menu| context_menu.focused(window, cx))
18977        {
18978            self.hide_context_menu(window, cx);
18979        }
18980        self.discard_inline_completion(false, cx);
18981        cx.emit(EditorEvent::Blurred);
18982        cx.notify();
18983    }
18984
18985    pub fn register_action<A: Action>(
18986        &mut self,
18987        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
18988    ) -> Subscription {
18989        let id = self.next_editor_action_id.post_inc();
18990        let listener = Arc::new(listener);
18991        self.editor_actions.borrow_mut().insert(
18992            id,
18993            Box::new(move |window, _| {
18994                let listener = listener.clone();
18995                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
18996                    let action = action.downcast_ref().unwrap();
18997                    if phase == DispatchPhase::Bubble {
18998                        listener(action, window, cx)
18999                    }
19000                })
19001            }),
19002        );
19003
19004        let editor_actions = self.editor_actions.clone();
19005        Subscription::new(move || {
19006            editor_actions.borrow_mut().remove(&id);
19007        })
19008    }
19009
19010    pub fn file_header_size(&self) -> u32 {
19011        FILE_HEADER_HEIGHT
19012    }
19013
19014    pub fn restore(
19015        &mut self,
19016        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19017        window: &mut Window,
19018        cx: &mut Context<Self>,
19019    ) {
19020        let workspace = self.workspace();
19021        let project = self.project.as_ref();
19022        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19023            let mut tasks = Vec::new();
19024            for (buffer_id, changes) in revert_changes {
19025                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19026                    buffer.update(cx, |buffer, cx| {
19027                        buffer.edit(
19028                            changes
19029                                .into_iter()
19030                                .map(|(range, text)| (range, text.to_string())),
19031                            None,
19032                            cx,
19033                        );
19034                    });
19035
19036                    if let Some(project) =
19037                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19038                    {
19039                        project.update(cx, |project, cx| {
19040                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19041                        })
19042                    }
19043                }
19044            }
19045            tasks
19046        });
19047        cx.spawn_in(window, async move |_, cx| {
19048            for (buffer, task) in save_tasks {
19049                let result = task.await;
19050                if result.is_err() {
19051                    let Some(path) = buffer
19052                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19053                        .ok()
19054                    else {
19055                        continue;
19056                    };
19057                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19058                        let Some(task) = cx
19059                            .update_window_entity(&workspace, |workspace, window, cx| {
19060                                workspace
19061                                    .open_path_preview(path, None, false, false, false, window, cx)
19062                            })
19063                            .ok()
19064                        else {
19065                            continue;
19066                        };
19067                        task.await.log_err();
19068                    }
19069                }
19070            }
19071        })
19072        .detach();
19073        self.change_selections(None, window, cx, |selections| selections.refresh());
19074    }
19075
19076    pub fn to_pixel_point(
19077        &self,
19078        source: multi_buffer::Anchor,
19079        editor_snapshot: &EditorSnapshot,
19080        window: &mut Window,
19081    ) -> Option<gpui::Point<Pixels>> {
19082        let source_point = source.to_display_point(editor_snapshot);
19083        self.display_to_pixel_point(source_point, editor_snapshot, window)
19084    }
19085
19086    pub fn display_to_pixel_point(
19087        &self,
19088        source: DisplayPoint,
19089        editor_snapshot: &EditorSnapshot,
19090        window: &mut Window,
19091    ) -> Option<gpui::Point<Pixels>> {
19092        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19093        let text_layout_details = self.text_layout_details(window);
19094        let scroll_top = text_layout_details
19095            .scroll_anchor
19096            .scroll_position(editor_snapshot)
19097            .y;
19098
19099        if source.row().as_f32() < scroll_top.floor() {
19100            return None;
19101        }
19102        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19103        let source_y = line_height * (source.row().as_f32() - scroll_top);
19104        Some(gpui::Point::new(source_x, source_y))
19105    }
19106
19107    pub fn has_visible_completions_menu(&self) -> bool {
19108        !self.edit_prediction_preview_is_active()
19109            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19110                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19111            })
19112    }
19113
19114    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19115        if self.mode.is_minimap() {
19116            return;
19117        }
19118        self.addons
19119            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19120    }
19121
19122    pub fn unregister_addon<T: Addon>(&mut self) {
19123        self.addons.remove(&std::any::TypeId::of::<T>());
19124    }
19125
19126    pub fn addon<T: Addon>(&self) -> Option<&T> {
19127        let type_id = std::any::TypeId::of::<T>();
19128        self.addons
19129            .get(&type_id)
19130            .and_then(|item| item.to_any().downcast_ref::<T>())
19131    }
19132
19133    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19134        let type_id = std::any::TypeId::of::<T>();
19135        self.addons
19136            .get_mut(&type_id)
19137            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19138    }
19139
19140    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19141        let text_layout_details = self.text_layout_details(window);
19142        let style = &text_layout_details.editor_style;
19143        let font_id = window.text_system().resolve_font(&style.text.font());
19144        let font_size = style.text.font_size.to_pixels(window.rem_size());
19145        let line_height = style.text.line_height_in_pixels(window.rem_size());
19146        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19147
19148        gpui::Size::new(em_width, line_height)
19149    }
19150
19151    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19152        self.load_diff_task.clone()
19153    }
19154
19155    fn read_metadata_from_db(
19156        &mut self,
19157        item_id: u64,
19158        workspace_id: WorkspaceId,
19159        window: &mut Window,
19160        cx: &mut Context<Editor>,
19161    ) {
19162        if self.is_singleton(cx)
19163            && !self.mode.is_minimap()
19164            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19165        {
19166            let buffer_snapshot = OnceCell::new();
19167
19168            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19169                if !folds.is_empty() {
19170                    let snapshot =
19171                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19172                    self.fold_ranges(
19173                        folds
19174                            .into_iter()
19175                            .map(|(start, end)| {
19176                                snapshot.clip_offset(start, Bias::Left)
19177                                    ..snapshot.clip_offset(end, Bias::Right)
19178                            })
19179                            .collect(),
19180                        false,
19181                        window,
19182                        cx,
19183                    );
19184                }
19185            }
19186
19187            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19188                if !selections.is_empty() {
19189                    let snapshot =
19190                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19191                    self.change_selections(None, window, cx, |s| {
19192                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19193                            snapshot.clip_offset(start, Bias::Left)
19194                                ..snapshot.clip_offset(end, Bias::Right)
19195                        }));
19196                    });
19197                }
19198            };
19199        }
19200
19201        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19202    }
19203}
19204
19205fn vim_enabled(cx: &App) -> bool {
19206    cx.global::<SettingsStore>()
19207        .raw_user_settings()
19208        .get("vim_mode")
19209        == Some(&serde_json::Value::Bool(true))
19210}
19211
19212// Consider user intent and default settings
19213fn choose_completion_range(
19214    completion: &Completion,
19215    intent: CompletionIntent,
19216    buffer: &Entity<Buffer>,
19217    cx: &mut Context<Editor>,
19218) -> Range<usize> {
19219    fn should_replace(
19220        completion: &Completion,
19221        insert_range: &Range<text::Anchor>,
19222        intent: CompletionIntent,
19223        completion_mode_setting: LspInsertMode,
19224        buffer: &Buffer,
19225    ) -> bool {
19226        // specific actions take precedence over settings
19227        match intent {
19228            CompletionIntent::CompleteWithInsert => return false,
19229            CompletionIntent::CompleteWithReplace => return true,
19230            CompletionIntent::Complete | CompletionIntent::Compose => {}
19231        }
19232
19233        match completion_mode_setting {
19234            LspInsertMode::Insert => false,
19235            LspInsertMode::Replace => true,
19236            LspInsertMode::ReplaceSubsequence => {
19237                let mut text_to_replace = buffer.chars_for_range(
19238                    buffer.anchor_before(completion.replace_range.start)
19239                        ..buffer.anchor_after(completion.replace_range.end),
19240                );
19241                let mut completion_text = completion.new_text.chars();
19242
19243                // is `text_to_replace` a subsequence of `completion_text`
19244                text_to_replace
19245                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19246            }
19247            LspInsertMode::ReplaceSuffix => {
19248                let range_after_cursor = insert_range.end..completion.replace_range.end;
19249
19250                let text_after_cursor = buffer
19251                    .text_for_range(
19252                        buffer.anchor_before(range_after_cursor.start)
19253                            ..buffer.anchor_after(range_after_cursor.end),
19254                    )
19255                    .collect::<String>();
19256                completion.new_text.ends_with(&text_after_cursor)
19257            }
19258        }
19259    }
19260
19261    let buffer = buffer.read(cx);
19262
19263    if let CompletionSource::Lsp {
19264        insert_range: Some(insert_range),
19265        ..
19266    } = &completion.source
19267    {
19268        let completion_mode_setting =
19269            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19270                .completions
19271                .lsp_insert_mode;
19272
19273        if !should_replace(
19274            completion,
19275            &insert_range,
19276            intent,
19277            completion_mode_setting,
19278            buffer,
19279        ) {
19280            return insert_range.to_offset(buffer);
19281        }
19282    }
19283
19284    completion.replace_range.to_offset(buffer)
19285}
19286
19287fn insert_extra_newline_brackets(
19288    buffer: &MultiBufferSnapshot,
19289    range: Range<usize>,
19290    language: &language::LanguageScope,
19291) -> bool {
19292    let leading_whitespace_len = buffer
19293        .reversed_chars_at(range.start)
19294        .take_while(|c| c.is_whitespace() && *c != '\n')
19295        .map(|c| c.len_utf8())
19296        .sum::<usize>();
19297    let trailing_whitespace_len = buffer
19298        .chars_at(range.end)
19299        .take_while(|c| c.is_whitespace() && *c != '\n')
19300        .map(|c| c.len_utf8())
19301        .sum::<usize>();
19302    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19303
19304    language.brackets().any(|(pair, enabled)| {
19305        let pair_start = pair.start.trim_end();
19306        let pair_end = pair.end.trim_start();
19307
19308        enabled
19309            && pair.newline
19310            && buffer.contains_str_at(range.end, pair_end)
19311            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19312    })
19313}
19314
19315fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19316    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19317        [(buffer, range, _)] => (*buffer, range.clone()),
19318        _ => return false,
19319    };
19320    let pair = {
19321        let mut result: Option<BracketMatch> = None;
19322
19323        for pair in buffer
19324            .all_bracket_ranges(range.clone())
19325            .filter(move |pair| {
19326                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19327            })
19328        {
19329            let len = pair.close_range.end - pair.open_range.start;
19330
19331            if let Some(existing) = &result {
19332                let existing_len = existing.close_range.end - existing.open_range.start;
19333                if len > existing_len {
19334                    continue;
19335                }
19336            }
19337
19338            result = Some(pair);
19339        }
19340
19341        result
19342    };
19343    let Some(pair) = pair else {
19344        return false;
19345    };
19346    pair.newline_only
19347        && buffer
19348            .chars_for_range(pair.open_range.end..range.start)
19349            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19350            .all(|c| c.is_whitespace() && c != '\n')
19351}
19352
19353fn update_uncommitted_diff_for_buffer(
19354    editor: Entity<Editor>,
19355    project: &Entity<Project>,
19356    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19357    buffer: Entity<MultiBuffer>,
19358    cx: &mut App,
19359) -> Task<()> {
19360    let mut tasks = Vec::new();
19361    project.update(cx, |project, cx| {
19362        for buffer in buffers {
19363            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19364                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19365            }
19366        }
19367    });
19368    cx.spawn(async move |cx| {
19369        let diffs = future::join_all(tasks).await;
19370        if editor
19371            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19372            .unwrap_or(false)
19373        {
19374            return;
19375        }
19376
19377        buffer
19378            .update(cx, |buffer, cx| {
19379                for diff in diffs.into_iter().flatten() {
19380                    buffer.add_diff(diff, cx);
19381                }
19382            })
19383            .ok();
19384    })
19385}
19386
19387fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19388    let tab_size = tab_size.get() as usize;
19389    let mut width = offset;
19390
19391    for ch in text.chars() {
19392        width += if ch == '\t' {
19393            tab_size - (width % tab_size)
19394        } else {
19395            1
19396        };
19397    }
19398
19399    width - offset
19400}
19401
19402#[cfg(test)]
19403mod tests {
19404    use super::*;
19405
19406    #[test]
19407    fn test_string_size_with_expanded_tabs() {
19408        let nz = |val| NonZeroU32::new(val).unwrap();
19409        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19410        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19411        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19412        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19413        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19414        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19415        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19416        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19417    }
19418}
19419
19420/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19421struct WordBreakingTokenizer<'a> {
19422    input: &'a str,
19423}
19424
19425impl<'a> WordBreakingTokenizer<'a> {
19426    fn new(input: &'a str) -> Self {
19427        Self { input }
19428    }
19429}
19430
19431fn is_char_ideographic(ch: char) -> bool {
19432    use unicode_script::Script::*;
19433    use unicode_script::UnicodeScript;
19434    matches!(ch.script(), Han | Tangut | Yi)
19435}
19436
19437fn is_grapheme_ideographic(text: &str) -> bool {
19438    text.chars().any(is_char_ideographic)
19439}
19440
19441fn is_grapheme_whitespace(text: &str) -> bool {
19442    text.chars().any(|x| x.is_whitespace())
19443}
19444
19445fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19446    text.chars().next().map_or(false, |ch| {
19447        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19448    })
19449}
19450
19451#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19452enum WordBreakToken<'a> {
19453    Word { token: &'a str, grapheme_len: usize },
19454    InlineWhitespace { token: &'a str, grapheme_len: usize },
19455    Newline,
19456}
19457
19458impl<'a> Iterator for WordBreakingTokenizer<'a> {
19459    /// Yields a span, the count of graphemes in the token, and whether it was
19460    /// whitespace. Note that it also breaks at word boundaries.
19461    type Item = WordBreakToken<'a>;
19462
19463    fn next(&mut self) -> Option<Self::Item> {
19464        use unicode_segmentation::UnicodeSegmentation;
19465        if self.input.is_empty() {
19466            return None;
19467        }
19468
19469        let mut iter = self.input.graphemes(true).peekable();
19470        let mut offset = 0;
19471        let mut grapheme_len = 0;
19472        if let Some(first_grapheme) = iter.next() {
19473            let is_newline = first_grapheme == "\n";
19474            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19475            offset += first_grapheme.len();
19476            grapheme_len += 1;
19477            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19478                if let Some(grapheme) = iter.peek().copied() {
19479                    if should_stay_with_preceding_ideograph(grapheme) {
19480                        offset += grapheme.len();
19481                        grapheme_len += 1;
19482                    }
19483                }
19484            } else {
19485                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19486                let mut next_word_bound = words.peek().copied();
19487                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19488                    next_word_bound = words.next();
19489                }
19490                while let Some(grapheme) = iter.peek().copied() {
19491                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19492                        break;
19493                    };
19494                    if is_grapheme_whitespace(grapheme) != is_whitespace
19495                        || (grapheme == "\n") != is_newline
19496                    {
19497                        break;
19498                    };
19499                    offset += grapheme.len();
19500                    grapheme_len += 1;
19501                    iter.next();
19502                }
19503            }
19504            let token = &self.input[..offset];
19505            self.input = &self.input[offset..];
19506            if token == "\n" {
19507                Some(WordBreakToken::Newline)
19508            } else if is_whitespace {
19509                Some(WordBreakToken::InlineWhitespace {
19510                    token,
19511                    grapheme_len,
19512                })
19513            } else {
19514                Some(WordBreakToken::Word {
19515                    token,
19516                    grapheme_len,
19517                })
19518            }
19519        } else {
19520            None
19521        }
19522    }
19523}
19524
19525#[test]
19526fn test_word_breaking_tokenizer() {
19527    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19528        ("", &[]),
19529        ("  ", &[whitespace("  ", 2)]),
19530        ("Ʒ", &[word("Ʒ", 1)]),
19531        ("Ǽ", &[word("Ǽ", 1)]),
19532        ("", &[word("", 1)]),
19533        ("⋑⋑", &[word("⋑⋑", 2)]),
19534        (
19535            "原理,进而",
19536            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19537        ),
19538        (
19539            "hello world",
19540            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19541        ),
19542        (
19543            "hello, world",
19544            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19545        ),
19546        (
19547            "  hello world",
19548            &[
19549                whitespace("  ", 2),
19550                word("hello", 5),
19551                whitespace(" ", 1),
19552                word("world", 5),
19553            ],
19554        ),
19555        (
19556            "这是什么 \n 钢笔",
19557            &[
19558                word("", 1),
19559                word("", 1),
19560                word("", 1),
19561                word("", 1),
19562                whitespace(" ", 1),
19563                newline(),
19564                whitespace(" ", 1),
19565                word("", 1),
19566                word("", 1),
19567            ],
19568        ),
19569        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19570    ];
19571
19572    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19573        WordBreakToken::Word {
19574            token,
19575            grapheme_len,
19576        }
19577    }
19578
19579    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19580        WordBreakToken::InlineWhitespace {
19581            token,
19582            grapheme_len,
19583        }
19584    }
19585
19586    fn newline() -> WordBreakToken<'static> {
19587        WordBreakToken::Newline
19588    }
19589
19590    for (input, result) in tests {
19591        assert_eq!(
19592            WordBreakingTokenizer::new(input)
19593                .collect::<Vec<_>>()
19594                .as_slice(),
19595            *result,
19596        );
19597    }
19598}
19599
19600fn wrap_with_prefix(
19601    line_prefix: String,
19602    unwrapped_text: String,
19603    wrap_column: usize,
19604    tab_size: NonZeroU32,
19605    preserve_existing_whitespace: bool,
19606) -> String {
19607    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19608    let mut wrapped_text = String::new();
19609    let mut current_line = line_prefix.clone();
19610
19611    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19612    let mut current_line_len = line_prefix_len;
19613    let mut in_whitespace = false;
19614    for token in tokenizer {
19615        let have_preceding_whitespace = in_whitespace;
19616        match token {
19617            WordBreakToken::Word {
19618                token,
19619                grapheme_len,
19620            } => {
19621                in_whitespace = false;
19622                if current_line_len + grapheme_len > wrap_column
19623                    && current_line_len != line_prefix_len
19624                {
19625                    wrapped_text.push_str(current_line.trim_end());
19626                    wrapped_text.push('\n');
19627                    current_line.truncate(line_prefix.len());
19628                    current_line_len = line_prefix_len;
19629                }
19630                current_line.push_str(token);
19631                current_line_len += grapheme_len;
19632            }
19633            WordBreakToken::InlineWhitespace {
19634                mut token,
19635                mut grapheme_len,
19636            } => {
19637                in_whitespace = true;
19638                if have_preceding_whitespace && !preserve_existing_whitespace {
19639                    continue;
19640                }
19641                if !preserve_existing_whitespace {
19642                    token = " ";
19643                    grapheme_len = 1;
19644                }
19645                if current_line_len + grapheme_len > wrap_column {
19646                    wrapped_text.push_str(current_line.trim_end());
19647                    wrapped_text.push('\n');
19648                    current_line.truncate(line_prefix.len());
19649                    current_line_len = line_prefix_len;
19650                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19651                    current_line.push_str(token);
19652                    current_line_len += grapheme_len;
19653                }
19654            }
19655            WordBreakToken::Newline => {
19656                in_whitespace = true;
19657                if preserve_existing_whitespace {
19658                    wrapped_text.push_str(current_line.trim_end());
19659                    wrapped_text.push('\n');
19660                    current_line.truncate(line_prefix.len());
19661                    current_line_len = line_prefix_len;
19662                } else if have_preceding_whitespace {
19663                    continue;
19664                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19665                {
19666                    wrapped_text.push_str(current_line.trim_end());
19667                    wrapped_text.push('\n');
19668                    current_line.truncate(line_prefix.len());
19669                    current_line_len = line_prefix_len;
19670                } else if current_line_len != line_prefix_len {
19671                    current_line.push(' ');
19672                    current_line_len += 1;
19673                }
19674            }
19675        }
19676    }
19677
19678    if !current_line.is_empty() {
19679        wrapped_text.push_str(&current_line);
19680    }
19681    wrapped_text
19682}
19683
19684#[test]
19685fn test_wrap_with_prefix() {
19686    assert_eq!(
19687        wrap_with_prefix(
19688            "# ".to_string(),
19689            "abcdefg".to_string(),
19690            4,
19691            NonZeroU32::new(4).unwrap(),
19692            false,
19693        ),
19694        "# abcdefg"
19695    );
19696    assert_eq!(
19697        wrap_with_prefix(
19698            "".to_string(),
19699            "\thello world".to_string(),
19700            8,
19701            NonZeroU32::new(4).unwrap(),
19702            false,
19703        ),
19704        "hello\nworld"
19705    );
19706    assert_eq!(
19707        wrap_with_prefix(
19708            "// ".to_string(),
19709            "xx \nyy zz aa bb cc".to_string(),
19710            12,
19711            NonZeroU32::new(4).unwrap(),
19712            false,
19713        ),
19714        "// xx yy zz\n// aa bb cc"
19715    );
19716    assert_eq!(
19717        wrap_with_prefix(
19718            String::new(),
19719            "这是什么 \n 钢笔".to_string(),
19720            3,
19721            NonZeroU32::new(4).unwrap(),
19722            false,
19723        ),
19724        "这是什\n么 钢\n"
19725    );
19726}
19727
19728pub trait CollaborationHub {
19729    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19730    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19731    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19732}
19733
19734impl CollaborationHub for Entity<Project> {
19735    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19736        self.read(cx).collaborators()
19737    }
19738
19739    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19740        self.read(cx).user_store().read(cx).participant_indices()
19741    }
19742
19743    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19744        let this = self.read(cx);
19745        let user_ids = this.collaborators().values().map(|c| c.user_id);
19746        this.user_store().read_with(cx, |user_store, cx| {
19747            user_store.participant_names(user_ids, cx)
19748        })
19749    }
19750}
19751
19752pub trait SemanticsProvider {
19753    fn hover(
19754        &self,
19755        buffer: &Entity<Buffer>,
19756        position: text::Anchor,
19757        cx: &mut App,
19758    ) -> Option<Task<Vec<project::Hover>>>;
19759
19760    fn inline_values(
19761        &self,
19762        buffer_handle: Entity<Buffer>,
19763        range: Range<text::Anchor>,
19764        cx: &mut App,
19765    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19766
19767    fn inlay_hints(
19768        &self,
19769        buffer_handle: Entity<Buffer>,
19770        range: Range<text::Anchor>,
19771        cx: &mut App,
19772    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19773
19774    fn resolve_inlay_hint(
19775        &self,
19776        hint: InlayHint,
19777        buffer_handle: Entity<Buffer>,
19778        server_id: LanguageServerId,
19779        cx: &mut App,
19780    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19781
19782    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19783
19784    fn document_highlights(
19785        &self,
19786        buffer: &Entity<Buffer>,
19787        position: text::Anchor,
19788        cx: &mut App,
19789    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19790
19791    fn definitions(
19792        &self,
19793        buffer: &Entity<Buffer>,
19794        position: text::Anchor,
19795        kind: GotoDefinitionKind,
19796        cx: &mut App,
19797    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19798
19799    fn range_for_rename(
19800        &self,
19801        buffer: &Entity<Buffer>,
19802        position: text::Anchor,
19803        cx: &mut App,
19804    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19805
19806    fn perform_rename(
19807        &self,
19808        buffer: &Entity<Buffer>,
19809        position: text::Anchor,
19810        new_name: String,
19811        cx: &mut App,
19812    ) -> Option<Task<Result<ProjectTransaction>>>;
19813}
19814
19815pub trait CompletionProvider {
19816    fn completions(
19817        &self,
19818        excerpt_id: ExcerptId,
19819        buffer: &Entity<Buffer>,
19820        buffer_position: text::Anchor,
19821        trigger: CompletionContext,
19822        window: &mut Window,
19823        cx: &mut Context<Editor>,
19824    ) -> Task<Result<Option<Vec<Completion>>>>;
19825
19826    fn resolve_completions(
19827        &self,
19828        buffer: Entity<Buffer>,
19829        completion_indices: Vec<usize>,
19830        completions: Rc<RefCell<Box<[Completion]>>>,
19831        cx: &mut Context<Editor>,
19832    ) -> Task<Result<bool>>;
19833
19834    fn apply_additional_edits_for_completion(
19835        &self,
19836        _buffer: Entity<Buffer>,
19837        _completions: Rc<RefCell<Box<[Completion]>>>,
19838        _completion_index: usize,
19839        _push_to_history: bool,
19840        _cx: &mut Context<Editor>,
19841    ) -> Task<Result<Option<language::Transaction>>> {
19842        Task::ready(Ok(None))
19843    }
19844
19845    fn is_completion_trigger(
19846        &self,
19847        buffer: &Entity<Buffer>,
19848        position: language::Anchor,
19849        text: &str,
19850        trigger_in_words: bool,
19851        cx: &mut Context<Editor>,
19852    ) -> bool;
19853
19854    fn sort_completions(&self) -> bool {
19855        true
19856    }
19857
19858    fn filter_completions(&self) -> bool {
19859        true
19860    }
19861}
19862
19863pub trait CodeActionProvider {
19864    fn id(&self) -> Arc<str>;
19865
19866    fn code_actions(
19867        &self,
19868        buffer: &Entity<Buffer>,
19869        range: Range<text::Anchor>,
19870        window: &mut Window,
19871        cx: &mut App,
19872    ) -> Task<Result<Vec<CodeAction>>>;
19873
19874    fn apply_code_action(
19875        &self,
19876        buffer_handle: Entity<Buffer>,
19877        action: CodeAction,
19878        excerpt_id: ExcerptId,
19879        push_to_history: bool,
19880        window: &mut Window,
19881        cx: &mut App,
19882    ) -> Task<Result<ProjectTransaction>>;
19883}
19884
19885impl CodeActionProvider for Entity<Project> {
19886    fn id(&self) -> Arc<str> {
19887        "project".into()
19888    }
19889
19890    fn code_actions(
19891        &self,
19892        buffer: &Entity<Buffer>,
19893        range: Range<text::Anchor>,
19894        _window: &mut Window,
19895        cx: &mut App,
19896    ) -> Task<Result<Vec<CodeAction>>> {
19897        self.update(cx, |project, cx| {
19898            let code_lens = project.code_lens(buffer, range.clone(), cx);
19899            let code_actions = project.code_actions(buffer, range, None, cx);
19900            cx.background_spawn(async move {
19901                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19902                Ok(code_lens
19903                    .context("code lens fetch")?
19904                    .into_iter()
19905                    .chain(code_actions.context("code action fetch")?)
19906                    .collect())
19907            })
19908        })
19909    }
19910
19911    fn apply_code_action(
19912        &self,
19913        buffer_handle: Entity<Buffer>,
19914        action: CodeAction,
19915        _excerpt_id: ExcerptId,
19916        push_to_history: bool,
19917        _window: &mut Window,
19918        cx: &mut App,
19919    ) -> Task<Result<ProjectTransaction>> {
19920        self.update(cx, |project, cx| {
19921            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19922        })
19923    }
19924}
19925
19926fn snippet_completions(
19927    project: &Project,
19928    buffer: &Entity<Buffer>,
19929    buffer_position: text::Anchor,
19930    cx: &mut App,
19931) -> Task<Result<Vec<Completion>>> {
19932    let languages = buffer.read(cx).languages_at(buffer_position);
19933    let snippet_store = project.snippets().read(cx);
19934
19935    let scopes: Vec<_> = languages
19936        .iter()
19937        .filter_map(|language| {
19938            let language_name = language.lsp_id();
19939            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19940
19941            if snippets.is_empty() {
19942                None
19943            } else {
19944                Some((language.default_scope(), snippets))
19945            }
19946        })
19947        .collect();
19948
19949    if scopes.is_empty() {
19950        return Task::ready(Ok(vec![]));
19951    }
19952
19953    let snapshot = buffer.read(cx).text_snapshot();
19954    let chars: String = snapshot
19955        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19956        .collect();
19957    let executor = cx.background_executor().clone();
19958
19959    cx.background_spawn(async move {
19960        let mut all_results: Vec<Completion> = Vec::new();
19961        for (scope, snippets) in scopes.into_iter() {
19962            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19963            let mut last_word = chars
19964                .chars()
19965                .take_while(|c| classifier.is_word(*c))
19966                .collect::<String>();
19967            last_word = last_word.chars().rev().collect();
19968
19969            if last_word.is_empty() {
19970                return Ok(vec![]);
19971            }
19972
19973            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19974            let to_lsp = |point: &text::Anchor| {
19975                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19976                point_to_lsp(end)
19977            };
19978            let lsp_end = to_lsp(&buffer_position);
19979
19980            let candidates = snippets
19981                .iter()
19982                .enumerate()
19983                .flat_map(|(ix, snippet)| {
19984                    snippet
19985                        .prefix
19986                        .iter()
19987                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19988                })
19989                .collect::<Vec<StringMatchCandidate>>();
19990
19991            let mut matches = fuzzy::match_strings(
19992                &candidates,
19993                &last_word,
19994                last_word.chars().any(|c| c.is_uppercase()),
19995                100,
19996                &Default::default(),
19997                executor.clone(),
19998            )
19999            .await;
20000
20001            // Remove all candidates where the query's start does not match the start of any word in the candidate
20002            if let Some(query_start) = last_word.chars().next() {
20003                matches.retain(|string_match| {
20004                    split_words(&string_match.string).any(|word| {
20005                        // Check that the first codepoint of the word as lowercase matches the first
20006                        // codepoint of the query as lowercase
20007                        word.chars()
20008                            .flat_map(|codepoint| codepoint.to_lowercase())
20009                            .zip(query_start.to_lowercase())
20010                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20011                    })
20012                });
20013            }
20014
20015            let matched_strings = matches
20016                .into_iter()
20017                .map(|m| m.string)
20018                .collect::<HashSet<_>>();
20019
20020            let mut result: Vec<Completion> = snippets
20021                .iter()
20022                .filter_map(|snippet| {
20023                    let matching_prefix = snippet
20024                        .prefix
20025                        .iter()
20026                        .find(|prefix| matched_strings.contains(*prefix))?;
20027                    let start = as_offset - last_word.len();
20028                    let start = snapshot.anchor_before(start);
20029                    let range = start..buffer_position;
20030                    let lsp_start = to_lsp(&start);
20031                    let lsp_range = lsp::Range {
20032                        start: lsp_start,
20033                        end: lsp_end,
20034                    };
20035                    Some(Completion {
20036                        replace_range: range,
20037                        new_text: snippet.body.clone(),
20038                        source: CompletionSource::Lsp {
20039                            insert_range: None,
20040                            server_id: LanguageServerId(usize::MAX),
20041                            resolved: true,
20042                            lsp_completion: Box::new(lsp::CompletionItem {
20043                                label: snippet.prefix.first().unwrap().clone(),
20044                                kind: Some(CompletionItemKind::SNIPPET),
20045                                label_details: snippet.description.as_ref().map(|description| {
20046                                    lsp::CompletionItemLabelDetails {
20047                                        detail: Some(description.clone()),
20048                                        description: None,
20049                                    }
20050                                }),
20051                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20052                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20053                                    lsp::InsertReplaceEdit {
20054                                        new_text: snippet.body.clone(),
20055                                        insert: lsp_range,
20056                                        replace: lsp_range,
20057                                    },
20058                                )),
20059                                filter_text: Some(snippet.body.clone()),
20060                                sort_text: Some(char::MAX.to_string()),
20061                                ..lsp::CompletionItem::default()
20062                            }),
20063                            lsp_defaults: None,
20064                        },
20065                        label: CodeLabel {
20066                            text: matching_prefix.clone(),
20067                            runs: Vec::new(),
20068                            filter_range: 0..matching_prefix.len(),
20069                        },
20070                        icon_path: None,
20071                        documentation: Some(
20072                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20073                                single_line: snippet.name.clone().into(),
20074                                plain_text: snippet
20075                                    .description
20076                                    .clone()
20077                                    .map(|description| description.into()),
20078                            },
20079                        ),
20080                        insert_text_mode: None,
20081                        confirm: None,
20082                    })
20083                })
20084                .collect();
20085
20086            all_results.append(&mut result);
20087        }
20088
20089        Ok(all_results)
20090    })
20091}
20092
20093impl CompletionProvider for Entity<Project> {
20094    fn completions(
20095        &self,
20096        _excerpt_id: ExcerptId,
20097        buffer: &Entity<Buffer>,
20098        buffer_position: text::Anchor,
20099        options: CompletionContext,
20100        _window: &mut Window,
20101        cx: &mut Context<Editor>,
20102    ) -> Task<Result<Option<Vec<Completion>>>> {
20103        self.update(cx, |project, cx| {
20104            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20105            let project_completions = project.completions(buffer, buffer_position, options, cx);
20106            cx.background_spawn(async move {
20107                let snippets_completions = snippets.await?;
20108                match project_completions.await? {
20109                    Some(mut completions) => {
20110                        completions.extend(snippets_completions);
20111                        Ok(Some(completions))
20112                    }
20113                    None => {
20114                        if snippets_completions.is_empty() {
20115                            Ok(None)
20116                        } else {
20117                            Ok(Some(snippets_completions))
20118                        }
20119                    }
20120                }
20121            })
20122        })
20123    }
20124
20125    fn resolve_completions(
20126        &self,
20127        buffer: Entity<Buffer>,
20128        completion_indices: Vec<usize>,
20129        completions: Rc<RefCell<Box<[Completion]>>>,
20130        cx: &mut Context<Editor>,
20131    ) -> Task<Result<bool>> {
20132        self.update(cx, |project, cx| {
20133            project.lsp_store().update(cx, |lsp_store, cx| {
20134                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20135            })
20136        })
20137    }
20138
20139    fn apply_additional_edits_for_completion(
20140        &self,
20141        buffer: Entity<Buffer>,
20142        completions: Rc<RefCell<Box<[Completion]>>>,
20143        completion_index: usize,
20144        push_to_history: bool,
20145        cx: &mut Context<Editor>,
20146    ) -> Task<Result<Option<language::Transaction>>> {
20147        self.update(cx, |project, cx| {
20148            project.lsp_store().update(cx, |lsp_store, cx| {
20149                lsp_store.apply_additional_edits_for_completion(
20150                    buffer,
20151                    completions,
20152                    completion_index,
20153                    push_to_history,
20154                    cx,
20155                )
20156            })
20157        })
20158    }
20159
20160    fn is_completion_trigger(
20161        &self,
20162        buffer: &Entity<Buffer>,
20163        position: language::Anchor,
20164        text: &str,
20165        trigger_in_words: bool,
20166        cx: &mut Context<Editor>,
20167    ) -> bool {
20168        let mut chars = text.chars();
20169        let char = if let Some(char) = chars.next() {
20170            char
20171        } else {
20172            return false;
20173        };
20174        if chars.next().is_some() {
20175            return false;
20176        }
20177
20178        let buffer = buffer.read(cx);
20179        let snapshot = buffer.snapshot();
20180        if !snapshot.settings_at(position, cx).show_completions_on_input {
20181            return false;
20182        }
20183        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20184        if trigger_in_words && classifier.is_word(char) {
20185            return true;
20186        }
20187
20188        buffer.completion_triggers().contains(text)
20189    }
20190}
20191
20192impl SemanticsProvider for Entity<Project> {
20193    fn hover(
20194        &self,
20195        buffer: &Entity<Buffer>,
20196        position: text::Anchor,
20197        cx: &mut App,
20198    ) -> Option<Task<Vec<project::Hover>>> {
20199        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20200    }
20201
20202    fn document_highlights(
20203        &self,
20204        buffer: &Entity<Buffer>,
20205        position: text::Anchor,
20206        cx: &mut App,
20207    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20208        Some(self.update(cx, |project, cx| {
20209            project.document_highlights(buffer, position, cx)
20210        }))
20211    }
20212
20213    fn definitions(
20214        &self,
20215        buffer: &Entity<Buffer>,
20216        position: text::Anchor,
20217        kind: GotoDefinitionKind,
20218        cx: &mut App,
20219    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20220        Some(self.update(cx, |project, cx| match kind {
20221            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20222            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20223            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20224            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20225        }))
20226    }
20227
20228    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20229        // TODO: make this work for remote projects
20230        self.update(cx, |project, cx| {
20231            if project
20232                .active_debug_session(cx)
20233                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20234            {
20235                return true;
20236            }
20237
20238            buffer.update(cx, |buffer, cx| {
20239                project.any_language_server_supports_inlay_hints(buffer, cx)
20240            })
20241        })
20242    }
20243
20244    fn inline_values(
20245        &self,
20246        buffer_handle: Entity<Buffer>,
20247
20248        range: Range<text::Anchor>,
20249        cx: &mut App,
20250    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20251        self.update(cx, |project, cx| {
20252            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20253
20254            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20255        })
20256    }
20257
20258    fn inlay_hints(
20259        &self,
20260        buffer_handle: Entity<Buffer>,
20261        range: Range<text::Anchor>,
20262        cx: &mut App,
20263    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20264        Some(self.update(cx, |project, cx| {
20265            project.inlay_hints(buffer_handle, range, cx)
20266        }))
20267    }
20268
20269    fn resolve_inlay_hint(
20270        &self,
20271        hint: InlayHint,
20272        buffer_handle: Entity<Buffer>,
20273        server_id: LanguageServerId,
20274        cx: &mut App,
20275    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20276        Some(self.update(cx, |project, cx| {
20277            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20278        }))
20279    }
20280
20281    fn range_for_rename(
20282        &self,
20283        buffer: &Entity<Buffer>,
20284        position: text::Anchor,
20285        cx: &mut App,
20286    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20287        Some(self.update(cx, |project, cx| {
20288            let buffer = buffer.clone();
20289            let task = project.prepare_rename(buffer.clone(), position, cx);
20290            cx.spawn(async move |_, cx| {
20291                Ok(match task.await? {
20292                    PrepareRenameResponse::Success(range) => Some(range),
20293                    PrepareRenameResponse::InvalidPosition => None,
20294                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20295                        // Fallback on using TreeSitter info to determine identifier range
20296                        buffer.update(cx, |buffer, _| {
20297                            let snapshot = buffer.snapshot();
20298                            let (range, kind) = snapshot.surrounding_word(position);
20299                            if kind != Some(CharKind::Word) {
20300                                return None;
20301                            }
20302                            Some(
20303                                snapshot.anchor_before(range.start)
20304                                    ..snapshot.anchor_after(range.end),
20305                            )
20306                        })?
20307                    }
20308                })
20309            })
20310        }))
20311    }
20312
20313    fn perform_rename(
20314        &self,
20315        buffer: &Entity<Buffer>,
20316        position: text::Anchor,
20317        new_name: String,
20318        cx: &mut App,
20319    ) -> Option<Task<Result<ProjectTransaction>>> {
20320        Some(self.update(cx, |project, cx| {
20321            project.perform_rename(buffer.clone(), position, new_name, cx)
20322        }))
20323    }
20324}
20325
20326fn inlay_hint_settings(
20327    location: Anchor,
20328    snapshot: &MultiBufferSnapshot,
20329    cx: &mut Context<Editor>,
20330) -> InlayHintSettings {
20331    let file = snapshot.file_at(location);
20332    let language = snapshot.language_at(location).map(|l| l.name());
20333    language_settings(language, file, cx).inlay_hints
20334}
20335
20336fn consume_contiguous_rows(
20337    contiguous_row_selections: &mut Vec<Selection<Point>>,
20338    selection: &Selection<Point>,
20339    display_map: &DisplaySnapshot,
20340    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20341) -> (MultiBufferRow, MultiBufferRow) {
20342    contiguous_row_selections.push(selection.clone());
20343    let start_row = MultiBufferRow(selection.start.row);
20344    let mut end_row = ending_row(selection, display_map);
20345
20346    while let Some(next_selection) = selections.peek() {
20347        if next_selection.start.row <= end_row.0 {
20348            end_row = ending_row(next_selection, display_map);
20349            contiguous_row_selections.push(selections.next().unwrap().clone());
20350        } else {
20351            break;
20352        }
20353    }
20354    (start_row, end_row)
20355}
20356
20357fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20358    if next_selection.end.column > 0 || next_selection.is_empty() {
20359        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20360    } else {
20361        MultiBufferRow(next_selection.end.row)
20362    }
20363}
20364
20365impl EditorSnapshot {
20366    pub fn remote_selections_in_range<'a>(
20367        &'a self,
20368        range: &'a Range<Anchor>,
20369        collaboration_hub: &dyn CollaborationHub,
20370        cx: &'a App,
20371    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20372        let participant_names = collaboration_hub.user_names(cx);
20373        let participant_indices = collaboration_hub.user_participant_indices(cx);
20374        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20375        let collaborators_by_replica_id = collaborators_by_peer_id
20376            .values()
20377            .map(|collaborator| (collaborator.replica_id, collaborator))
20378            .collect::<HashMap<_, _>>();
20379        self.buffer_snapshot
20380            .selections_in_range(range, false)
20381            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20382                if replica_id == AGENT_REPLICA_ID {
20383                    Some(RemoteSelection {
20384                        replica_id,
20385                        selection,
20386                        cursor_shape,
20387                        line_mode,
20388                        collaborator_id: CollaboratorId::Agent,
20389                        user_name: Some("Agent".into()),
20390                        color: cx.theme().players().agent(),
20391                    })
20392                } else {
20393                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20394                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20395                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20396                    Some(RemoteSelection {
20397                        replica_id,
20398                        selection,
20399                        cursor_shape,
20400                        line_mode,
20401                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20402                        user_name,
20403                        color: if let Some(index) = participant_index {
20404                            cx.theme().players().color_for_participant(index.0)
20405                        } else {
20406                            cx.theme().players().absent()
20407                        },
20408                    })
20409                }
20410            })
20411    }
20412
20413    pub fn hunks_for_ranges(
20414        &self,
20415        ranges: impl IntoIterator<Item = Range<Point>>,
20416    ) -> Vec<MultiBufferDiffHunk> {
20417        let mut hunks = Vec::new();
20418        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20419            HashMap::default();
20420        for query_range in ranges {
20421            let query_rows =
20422                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20423            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20424                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20425            ) {
20426                // Include deleted hunks that are adjacent to the query range, because
20427                // otherwise they would be missed.
20428                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20429                if hunk.status().is_deleted() {
20430                    intersects_range |= hunk.row_range.start == query_rows.end;
20431                    intersects_range |= hunk.row_range.end == query_rows.start;
20432                }
20433                if intersects_range {
20434                    if !processed_buffer_rows
20435                        .entry(hunk.buffer_id)
20436                        .or_default()
20437                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20438                    {
20439                        continue;
20440                    }
20441                    hunks.push(hunk);
20442                }
20443            }
20444        }
20445
20446        hunks
20447    }
20448
20449    fn display_diff_hunks_for_rows<'a>(
20450        &'a self,
20451        display_rows: Range<DisplayRow>,
20452        folded_buffers: &'a HashSet<BufferId>,
20453    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20454        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20455        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20456
20457        self.buffer_snapshot
20458            .diff_hunks_in_range(buffer_start..buffer_end)
20459            .filter_map(|hunk| {
20460                if folded_buffers.contains(&hunk.buffer_id) {
20461                    return None;
20462                }
20463
20464                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20465                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20466
20467                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20468                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20469
20470                let display_hunk = if hunk_display_start.column() != 0 {
20471                    DisplayDiffHunk::Folded {
20472                        display_row: hunk_display_start.row(),
20473                    }
20474                } else {
20475                    let mut end_row = hunk_display_end.row();
20476                    if hunk_display_end.column() > 0 {
20477                        end_row.0 += 1;
20478                    }
20479                    let is_created_file = hunk.is_created_file();
20480                    DisplayDiffHunk::Unfolded {
20481                        status: hunk.status(),
20482                        diff_base_byte_range: hunk.diff_base_byte_range,
20483                        display_row_range: hunk_display_start.row()..end_row,
20484                        multi_buffer_range: Anchor::range_in_buffer(
20485                            hunk.excerpt_id,
20486                            hunk.buffer_id,
20487                            hunk.buffer_range,
20488                        ),
20489                        is_created_file,
20490                    }
20491                };
20492
20493                Some(display_hunk)
20494            })
20495    }
20496
20497    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20498        self.display_snapshot.buffer_snapshot.language_at(position)
20499    }
20500
20501    pub fn is_focused(&self) -> bool {
20502        self.is_focused
20503    }
20504
20505    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20506        self.placeholder_text.as_ref()
20507    }
20508
20509    pub fn scroll_position(&self) -> gpui::Point<f32> {
20510        self.scroll_anchor.scroll_position(&self.display_snapshot)
20511    }
20512
20513    fn gutter_dimensions(
20514        &self,
20515        font_id: FontId,
20516        font_size: Pixels,
20517        max_line_number_width: Pixels,
20518        cx: &App,
20519    ) -> Option<GutterDimensions> {
20520        if !self.show_gutter {
20521            return None;
20522        }
20523
20524        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20525        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20526
20527        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20528            matches!(
20529                ProjectSettings::get_global(cx).git.git_gutter,
20530                Some(GitGutterSetting::TrackedFiles)
20531            )
20532        });
20533        let gutter_settings = EditorSettings::get_global(cx).gutter;
20534        let show_line_numbers = self
20535            .show_line_numbers
20536            .unwrap_or(gutter_settings.line_numbers);
20537        let line_gutter_width = if show_line_numbers {
20538            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20539            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20540            max_line_number_width.max(min_width_for_number_on_gutter)
20541        } else {
20542            0.0.into()
20543        };
20544
20545        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20546        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20547
20548        let git_blame_entries_width =
20549            self.git_blame_gutter_max_author_length
20550                .map(|max_author_length| {
20551                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20552                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20553
20554                    /// The number of characters to dedicate to gaps and margins.
20555                    const SPACING_WIDTH: usize = 4;
20556
20557                    let max_char_count = max_author_length.min(renderer.max_author_length())
20558                        + ::git::SHORT_SHA_LENGTH
20559                        + MAX_RELATIVE_TIMESTAMP.len()
20560                        + SPACING_WIDTH;
20561
20562                    em_advance * max_char_count
20563                });
20564
20565        let is_singleton = self.buffer_snapshot.is_singleton();
20566
20567        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20568        left_padding += if !is_singleton {
20569            em_width * 4.0
20570        } else if show_runnables || show_breakpoints {
20571            em_width * 3.0
20572        } else if show_git_gutter && show_line_numbers {
20573            em_width * 2.0
20574        } else if show_git_gutter || show_line_numbers {
20575            em_width
20576        } else {
20577            px(0.)
20578        };
20579
20580        let shows_folds = is_singleton && gutter_settings.folds;
20581
20582        let right_padding = if shows_folds && show_line_numbers {
20583            em_width * 4.0
20584        } else if shows_folds || (!is_singleton && show_line_numbers) {
20585            em_width * 3.0
20586        } else if show_line_numbers {
20587            em_width
20588        } else {
20589            px(0.)
20590        };
20591
20592        Some(GutterDimensions {
20593            left_padding,
20594            right_padding,
20595            width: line_gutter_width + left_padding + right_padding,
20596            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20597            git_blame_entries_width,
20598        })
20599    }
20600
20601    pub fn render_crease_toggle(
20602        &self,
20603        buffer_row: MultiBufferRow,
20604        row_contains_cursor: bool,
20605        editor: Entity<Editor>,
20606        window: &mut Window,
20607        cx: &mut App,
20608    ) -> Option<AnyElement> {
20609        let folded = self.is_line_folded(buffer_row);
20610        let mut is_foldable = false;
20611
20612        if let Some(crease) = self
20613            .crease_snapshot
20614            .query_row(buffer_row, &self.buffer_snapshot)
20615        {
20616            is_foldable = true;
20617            match crease {
20618                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20619                    if let Some(render_toggle) = render_toggle {
20620                        let toggle_callback =
20621                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20622                                if folded {
20623                                    editor.update(cx, |editor, cx| {
20624                                        editor.fold_at(buffer_row, window, cx)
20625                                    });
20626                                } else {
20627                                    editor.update(cx, |editor, cx| {
20628                                        editor.unfold_at(buffer_row, window, cx)
20629                                    });
20630                                }
20631                            });
20632                        return Some((render_toggle)(
20633                            buffer_row,
20634                            folded,
20635                            toggle_callback,
20636                            window,
20637                            cx,
20638                        ));
20639                    }
20640                }
20641            }
20642        }
20643
20644        is_foldable |= self.starts_indent(buffer_row);
20645
20646        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20647            Some(
20648                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20649                    .toggle_state(folded)
20650                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20651                        if folded {
20652                            this.unfold_at(buffer_row, window, cx);
20653                        } else {
20654                            this.fold_at(buffer_row, window, cx);
20655                        }
20656                    }))
20657                    .into_any_element(),
20658            )
20659        } else {
20660            None
20661        }
20662    }
20663
20664    pub fn render_crease_trailer(
20665        &self,
20666        buffer_row: MultiBufferRow,
20667        window: &mut Window,
20668        cx: &mut App,
20669    ) -> Option<AnyElement> {
20670        let folded = self.is_line_folded(buffer_row);
20671        if let Crease::Inline { render_trailer, .. } = self
20672            .crease_snapshot
20673            .query_row(buffer_row, &self.buffer_snapshot)?
20674        {
20675            let render_trailer = render_trailer.as_ref()?;
20676            Some(render_trailer(buffer_row, folded, window, cx))
20677        } else {
20678            None
20679        }
20680    }
20681}
20682
20683impl Deref for EditorSnapshot {
20684    type Target = DisplaySnapshot;
20685
20686    fn deref(&self) -> &Self::Target {
20687        &self.display_snapshot
20688    }
20689}
20690
20691#[derive(Clone, Debug, PartialEq, Eq)]
20692pub enum EditorEvent {
20693    InputIgnored {
20694        text: Arc<str>,
20695    },
20696    InputHandled {
20697        utf16_range_to_replace: Option<Range<isize>>,
20698        text: Arc<str>,
20699    },
20700    ExcerptsAdded {
20701        buffer: Entity<Buffer>,
20702        predecessor: ExcerptId,
20703        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20704    },
20705    ExcerptsRemoved {
20706        ids: Vec<ExcerptId>,
20707        removed_buffer_ids: Vec<BufferId>,
20708    },
20709    BufferFoldToggled {
20710        ids: Vec<ExcerptId>,
20711        folded: bool,
20712    },
20713    ExcerptsEdited {
20714        ids: Vec<ExcerptId>,
20715    },
20716    ExcerptsExpanded {
20717        ids: Vec<ExcerptId>,
20718    },
20719    BufferEdited,
20720    Edited {
20721        transaction_id: clock::Lamport,
20722    },
20723    Reparsed(BufferId),
20724    Focused,
20725    FocusedIn,
20726    Blurred,
20727    DirtyChanged,
20728    Saved,
20729    TitleChanged,
20730    DiffBaseChanged,
20731    SelectionsChanged {
20732        local: bool,
20733    },
20734    ScrollPositionChanged {
20735        local: bool,
20736        autoscroll: bool,
20737    },
20738    Closed,
20739    TransactionUndone {
20740        transaction_id: clock::Lamport,
20741    },
20742    TransactionBegun {
20743        transaction_id: clock::Lamport,
20744    },
20745    Reloaded,
20746    CursorShapeChanged,
20747    PushedToNavHistory {
20748        anchor: Anchor,
20749        is_deactivate: bool,
20750    },
20751}
20752
20753impl EventEmitter<EditorEvent> for Editor {}
20754
20755impl Focusable for Editor {
20756    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20757        self.focus_handle.clone()
20758    }
20759}
20760
20761impl Render for Editor {
20762    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20763        let settings = ThemeSettings::get_global(cx);
20764
20765        let mut text_style = match self.mode {
20766            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20767                color: cx.theme().colors().editor_foreground,
20768                font_family: settings.ui_font.family.clone(),
20769                font_features: settings.ui_font.features.clone(),
20770                font_fallbacks: settings.ui_font.fallbacks.clone(),
20771                font_size: rems(0.875).into(),
20772                font_weight: settings.ui_font.weight,
20773                line_height: relative(settings.buffer_line_height.value()),
20774                ..Default::default()
20775            },
20776            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20777                color: cx.theme().colors().editor_foreground,
20778                font_family: settings.buffer_font.family.clone(),
20779                font_features: settings.buffer_font.features.clone(),
20780                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20781                font_size: settings.buffer_font_size(cx).into(),
20782                font_weight: settings.buffer_font.weight,
20783                line_height: relative(settings.buffer_line_height.value()),
20784                ..Default::default()
20785            },
20786        };
20787        if let Some(text_style_refinement) = &self.text_style_refinement {
20788            text_style.refine(text_style_refinement)
20789        }
20790
20791        let background = match self.mode {
20792            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20793            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20794            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20795            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20796        };
20797
20798        EditorElement::new(
20799            &cx.entity(),
20800            EditorStyle {
20801                background,
20802                local_player: cx.theme().players().local(),
20803                text: text_style,
20804                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20805                syntax: cx.theme().syntax().clone(),
20806                status: cx.theme().status().clone(),
20807                inlay_hints_style: make_inlay_hints_style(cx),
20808                inline_completion_styles: make_suggestion_styles(cx),
20809                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20810                show_underlines: !self.mode.is_minimap(),
20811            },
20812        )
20813    }
20814}
20815
20816impl EntityInputHandler for Editor {
20817    fn text_for_range(
20818        &mut self,
20819        range_utf16: Range<usize>,
20820        adjusted_range: &mut Option<Range<usize>>,
20821        _: &mut Window,
20822        cx: &mut Context<Self>,
20823    ) -> Option<String> {
20824        let snapshot = self.buffer.read(cx).read(cx);
20825        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20826        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20827        if (start.0..end.0) != range_utf16 {
20828            adjusted_range.replace(start.0..end.0);
20829        }
20830        Some(snapshot.text_for_range(start..end).collect())
20831    }
20832
20833    fn selected_text_range(
20834        &mut self,
20835        ignore_disabled_input: bool,
20836        _: &mut Window,
20837        cx: &mut Context<Self>,
20838    ) -> Option<UTF16Selection> {
20839        // Prevent the IME menu from appearing when holding down an alphabetic key
20840        // while input is disabled.
20841        if !ignore_disabled_input && !self.input_enabled {
20842            return None;
20843        }
20844
20845        let selection = self.selections.newest::<OffsetUtf16>(cx);
20846        let range = selection.range();
20847
20848        Some(UTF16Selection {
20849            range: range.start.0..range.end.0,
20850            reversed: selection.reversed,
20851        })
20852    }
20853
20854    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20855        let snapshot = self.buffer.read(cx).read(cx);
20856        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20857        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20858    }
20859
20860    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20861        self.clear_highlights::<InputComposition>(cx);
20862        self.ime_transaction.take();
20863    }
20864
20865    fn replace_text_in_range(
20866        &mut self,
20867        range_utf16: Option<Range<usize>>,
20868        text: &str,
20869        window: &mut Window,
20870        cx: &mut Context<Self>,
20871    ) {
20872        if !self.input_enabled {
20873            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20874            return;
20875        }
20876
20877        self.transact(window, cx, |this, window, cx| {
20878            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20879                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20880                Some(this.selection_replacement_ranges(range_utf16, cx))
20881            } else {
20882                this.marked_text_ranges(cx)
20883            };
20884
20885            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20886                let newest_selection_id = this.selections.newest_anchor().id;
20887                this.selections
20888                    .all::<OffsetUtf16>(cx)
20889                    .iter()
20890                    .zip(ranges_to_replace.iter())
20891                    .find_map(|(selection, range)| {
20892                        if selection.id == newest_selection_id {
20893                            Some(
20894                                (range.start.0 as isize - selection.head().0 as isize)
20895                                    ..(range.end.0 as isize - selection.head().0 as isize),
20896                            )
20897                        } else {
20898                            None
20899                        }
20900                    })
20901            });
20902
20903            cx.emit(EditorEvent::InputHandled {
20904                utf16_range_to_replace: range_to_replace,
20905                text: text.into(),
20906            });
20907
20908            if let Some(new_selected_ranges) = new_selected_ranges {
20909                this.change_selections(None, window, cx, |selections| {
20910                    selections.select_ranges(new_selected_ranges)
20911                });
20912                this.backspace(&Default::default(), window, cx);
20913            }
20914
20915            this.handle_input(text, window, cx);
20916        });
20917
20918        if let Some(transaction) = self.ime_transaction {
20919            self.buffer.update(cx, |buffer, cx| {
20920                buffer.group_until_transaction(transaction, cx);
20921            });
20922        }
20923
20924        self.unmark_text(window, cx);
20925    }
20926
20927    fn replace_and_mark_text_in_range(
20928        &mut self,
20929        range_utf16: Option<Range<usize>>,
20930        text: &str,
20931        new_selected_range_utf16: Option<Range<usize>>,
20932        window: &mut Window,
20933        cx: &mut Context<Self>,
20934    ) {
20935        if !self.input_enabled {
20936            return;
20937        }
20938
20939        let transaction = self.transact(window, cx, |this, window, cx| {
20940            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20941                let snapshot = this.buffer.read(cx).read(cx);
20942                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20943                    for marked_range in &mut marked_ranges {
20944                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20945                        marked_range.start.0 += relative_range_utf16.start;
20946                        marked_range.start =
20947                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20948                        marked_range.end =
20949                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20950                    }
20951                }
20952                Some(marked_ranges)
20953            } else if let Some(range_utf16) = range_utf16 {
20954                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20955                Some(this.selection_replacement_ranges(range_utf16, cx))
20956            } else {
20957                None
20958            };
20959
20960            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20961                let newest_selection_id = this.selections.newest_anchor().id;
20962                this.selections
20963                    .all::<OffsetUtf16>(cx)
20964                    .iter()
20965                    .zip(ranges_to_replace.iter())
20966                    .find_map(|(selection, range)| {
20967                        if selection.id == newest_selection_id {
20968                            Some(
20969                                (range.start.0 as isize - selection.head().0 as isize)
20970                                    ..(range.end.0 as isize - selection.head().0 as isize),
20971                            )
20972                        } else {
20973                            None
20974                        }
20975                    })
20976            });
20977
20978            cx.emit(EditorEvent::InputHandled {
20979                utf16_range_to_replace: range_to_replace,
20980                text: text.into(),
20981            });
20982
20983            if let Some(ranges) = ranges_to_replace {
20984                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20985            }
20986
20987            let marked_ranges = {
20988                let snapshot = this.buffer.read(cx).read(cx);
20989                this.selections
20990                    .disjoint_anchors()
20991                    .iter()
20992                    .map(|selection| {
20993                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20994                    })
20995                    .collect::<Vec<_>>()
20996            };
20997
20998            if text.is_empty() {
20999                this.unmark_text(window, cx);
21000            } else {
21001                this.highlight_text::<InputComposition>(
21002                    marked_ranges.clone(),
21003                    HighlightStyle {
21004                        underline: Some(UnderlineStyle {
21005                            thickness: px(1.),
21006                            color: None,
21007                            wavy: false,
21008                        }),
21009                        ..Default::default()
21010                    },
21011                    cx,
21012                );
21013            }
21014
21015            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21016            let use_autoclose = this.use_autoclose;
21017            let use_auto_surround = this.use_auto_surround;
21018            this.set_use_autoclose(false);
21019            this.set_use_auto_surround(false);
21020            this.handle_input(text, window, cx);
21021            this.set_use_autoclose(use_autoclose);
21022            this.set_use_auto_surround(use_auto_surround);
21023
21024            if let Some(new_selected_range) = new_selected_range_utf16 {
21025                let snapshot = this.buffer.read(cx).read(cx);
21026                let new_selected_ranges = marked_ranges
21027                    .into_iter()
21028                    .map(|marked_range| {
21029                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21030                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21031                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21032                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21033                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21034                    })
21035                    .collect::<Vec<_>>();
21036
21037                drop(snapshot);
21038                this.change_selections(None, window, cx, |selections| {
21039                    selections.select_ranges(new_selected_ranges)
21040                });
21041            }
21042        });
21043
21044        self.ime_transaction = self.ime_transaction.or(transaction);
21045        if let Some(transaction) = self.ime_transaction {
21046            self.buffer.update(cx, |buffer, cx| {
21047                buffer.group_until_transaction(transaction, cx);
21048            });
21049        }
21050
21051        if self.text_highlights::<InputComposition>(cx).is_none() {
21052            self.ime_transaction.take();
21053        }
21054    }
21055
21056    fn bounds_for_range(
21057        &mut self,
21058        range_utf16: Range<usize>,
21059        element_bounds: gpui::Bounds<Pixels>,
21060        window: &mut Window,
21061        cx: &mut Context<Self>,
21062    ) -> Option<gpui::Bounds<Pixels>> {
21063        let text_layout_details = self.text_layout_details(window);
21064        let gpui::Size {
21065            width: em_width,
21066            height: line_height,
21067        } = self.character_size(window);
21068
21069        let snapshot = self.snapshot(window, cx);
21070        let scroll_position = snapshot.scroll_position();
21071        let scroll_left = scroll_position.x * em_width;
21072
21073        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21074        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21075            + self.gutter_dimensions.width
21076            + self.gutter_dimensions.margin;
21077        let y = line_height * (start.row().as_f32() - scroll_position.y);
21078
21079        Some(Bounds {
21080            origin: element_bounds.origin + point(x, y),
21081            size: size(em_width, line_height),
21082        })
21083    }
21084
21085    fn character_index_for_point(
21086        &mut self,
21087        point: gpui::Point<Pixels>,
21088        _window: &mut Window,
21089        _cx: &mut Context<Self>,
21090    ) -> Option<usize> {
21091        let position_map = self.last_position_map.as_ref()?;
21092        if !position_map.text_hitbox.contains(&point) {
21093            return None;
21094        }
21095        let display_point = position_map.point_for_position(point).previous_valid;
21096        let anchor = position_map
21097            .snapshot
21098            .display_point_to_anchor(display_point, Bias::Left);
21099        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21100        Some(utf16_offset.0)
21101    }
21102}
21103
21104trait SelectionExt {
21105    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21106    fn spanned_rows(
21107        &self,
21108        include_end_if_at_line_start: bool,
21109        map: &DisplaySnapshot,
21110    ) -> Range<MultiBufferRow>;
21111}
21112
21113impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21114    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21115        let start = self
21116            .start
21117            .to_point(&map.buffer_snapshot)
21118            .to_display_point(map);
21119        let end = self
21120            .end
21121            .to_point(&map.buffer_snapshot)
21122            .to_display_point(map);
21123        if self.reversed {
21124            end..start
21125        } else {
21126            start..end
21127        }
21128    }
21129
21130    fn spanned_rows(
21131        &self,
21132        include_end_if_at_line_start: bool,
21133        map: &DisplaySnapshot,
21134    ) -> Range<MultiBufferRow> {
21135        let start = self.start.to_point(&map.buffer_snapshot);
21136        let mut end = self.end.to_point(&map.buffer_snapshot);
21137        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21138            end.row -= 1;
21139        }
21140
21141        let buffer_start = map.prev_line_boundary(start).0;
21142        let buffer_end = map.next_line_boundary(end).0;
21143        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21144    }
21145}
21146
21147impl<T: InvalidationRegion> InvalidationStack<T> {
21148    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21149    where
21150        S: Clone + ToOffset,
21151    {
21152        while let Some(region) = self.last() {
21153            let all_selections_inside_invalidation_ranges =
21154                if selections.len() == region.ranges().len() {
21155                    selections
21156                        .iter()
21157                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21158                        .all(|(selection, invalidation_range)| {
21159                            let head = selection.head().to_offset(buffer);
21160                            invalidation_range.start <= head && invalidation_range.end >= head
21161                        })
21162                } else {
21163                    false
21164                };
21165
21166            if all_selections_inside_invalidation_ranges {
21167                break;
21168            } else {
21169                self.pop();
21170            }
21171        }
21172    }
21173}
21174
21175impl<T> Default for InvalidationStack<T> {
21176    fn default() -> Self {
21177        Self(Default::default())
21178    }
21179}
21180
21181impl<T> Deref for InvalidationStack<T> {
21182    type Target = Vec<T>;
21183
21184    fn deref(&self) -> &Self::Target {
21185        &self.0
21186    }
21187}
21188
21189impl<T> DerefMut for InvalidationStack<T> {
21190    fn deref_mut(&mut self) -> &mut Self::Target {
21191        &mut self.0
21192    }
21193}
21194
21195impl InvalidationRegion for SnippetState {
21196    fn ranges(&self) -> &[Range<Anchor>] {
21197        &self.ranges[self.active_index]
21198    }
21199}
21200
21201fn inline_completion_edit_text(
21202    current_snapshot: &BufferSnapshot,
21203    edits: &[(Range<Anchor>, String)],
21204    edit_preview: &EditPreview,
21205    include_deletions: bool,
21206    cx: &App,
21207) -> HighlightedText {
21208    let edits = edits
21209        .iter()
21210        .map(|(anchor, text)| {
21211            (
21212                anchor.start.text_anchor..anchor.end.text_anchor,
21213                text.clone(),
21214            )
21215        })
21216        .collect::<Vec<_>>();
21217
21218    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21219}
21220
21221pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21222    match severity {
21223        lsp::DiagnosticSeverity::ERROR => colors.error,
21224        lsp::DiagnosticSeverity::WARNING => colors.warning,
21225        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21226        lsp::DiagnosticSeverity::HINT => colors.info,
21227        _ => colors.ignored,
21228    }
21229}
21230
21231pub fn styled_runs_for_code_label<'a>(
21232    label: &'a CodeLabel,
21233    syntax_theme: &'a theme::SyntaxTheme,
21234) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21235    let fade_out = HighlightStyle {
21236        fade_out: Some(0.35),
21237        ..Default::default()
21238    };
21239
21240    let mut prev_end = label.filter_range.end;
21241    label
21242        .runs
21243        .iter()
21244        .enumerate()
21245        .flat_map(move |(ix, (range, highlight_id))| {
21246            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21247                style
21248            } else {
21249                return Default::default();
21250            };
21251            let mut muted_style = style;
21252            muted_style.highlight(fade_out);
21253
21254            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21255            if range.start >= label.filter_range.end {
21256                if range.start > prev_end {
21257                    runs.push((prev_end..range.start, fade_out));
21258                }
21259                runs.push((range.clone(), muted_style));
21260            } else if range.end <= label.filter_range.end {
21261                runs.push((range.clone(), style));
21262            } else {
21263                runs.push((range.start..label.filter_range.end, style));
21264                runs.push((label.filter_range.end..range.end, muted_style));
21265            }
21266            prev_end = cmp::max(prev_end, range.end);
21267
21268            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21269                runs.push((prev_end..label.text.len(), fade_out));
21270            }
21271
21272            runs
21273        })
21274}
21275
21276pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21277    let mut prev_index = 0;
21278    let mut prev_codepoint: Option<char> = None;
21279    text.char_indices()
21280        .chain([(text.len(), '\0')])
21281        .filter_map(move |(index, codepoint)| {
21282            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21283            let is_boundary = index == text.len()
21284                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21285                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21286            if is_boundary {
21287                let chunk = &text[prev_index..index];
21288                prev_index = index;
21289                Some(chunk)
21290            } else {
21291                None
21292            }
21293        })
21294}
21295
21296pub trait RangeToAnchorExt: Sized {
21297    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21298
21299    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21300        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21301        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21302    }
21303}
21304
21305impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21306    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21307        let start_offset = self.start.to_offset(snapshot);
21308        let end_offset = self.end.to_offset(snapshot);
21309        if start_offset == end_offset {
21310            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21311        } else {
21312            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21313        }
21314    }
21315}
21316
21317pub trait RowExt {
21318    fn as_f32(&self) -> f32;
21319
21320    fn next_row(&self) -> Self;
21321
21322    fn previous_row(&self) -> Self;
21323
21324    fn minus(&self, other: Self) -> u32;
21325}
21326
21327impl RowExt for DisplayRow {
21328    fn as_f32(&self) -> f32 {
21329        self.0 as f32
21330    }
21331
21332    fn next_row(&self) -> Self {
21333        Self(self.0 + 1)
21334    }
21335
21336    fn previous_row(&self) -> Self {
21337        Self(self.0.saturating_sub(1))
21338    }
21339
21340    fn minus(&self, other: Self) -> u32 {
21341        self.0 - other.0
21342    }
21343}
21344
21345impl RowExt for MultiBufferRow {
21346    fn as_f32(&self) -> f32 {
21347        self.0 as f32
21348    }
21349
21350    fn next_row(&self) -> Self {
21351        Self(self.0 + 1)
21352    }
21353
21354    fn previous_row(&self) -> Self {
21355        Self(self.0.saturating_sub(1))
21356    }
21357
21358    fn minus(&self, other: Self) -> u32 {
21359        self.0 - other.0
21360    }
21361}
21362
21363trait RowRangeExt {
21364    type Row;
21365
21366    fn len(&self) -> usize;
21367
21368    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21369}
21370
21371impl RowRangeExt for Range<MultiBufferRow> {
21372    type Row = MultiBufferRow;
21373
21374    fn len(&self) -> usize {
21375        (self.end.0 - self.start.0) as usize
21376    }
21377
21378    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21379        (self.start.0..self.end.0).map(MultiBufferRow)
21380    }
21381}
21382
21383impl RowRangeExt for Range<DisplayRow> {
21384    type Row = DisplayRow;
21385
21386    fn len(&self) -> usize {
21387        (self.end.0 - self.start.0) as usize
21388    }
21389
21390    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21391        (self.start.0..self.end.0).map(DisplayRow)
21392    }
21393}
21394
21395/// If select range has more than one line, we
21396/// just point the cursor to range.start.
21397fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21398    if range.start.row == range.end.row {
21399        range
21400    } else {
21401        range.start..range.start
21402    }
21403}
21404pub struct KillRing(ClipboardItem);
21405impl Global for KillRing {}
21406
21407const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21408
21409enum BreakpointPromptEditAction {
21410    Log,
21411    Condition,
21412    HitCondition,
21413}
21414
21415struct BreakpointPromptEditor {
21416    pub(crate) prompt: Entity<Editor>,
21417    editor: WeakEntity<Editor>,
21418    breakpoint_anchor: Anchor,
21419    breakpoint: Breakpoint,
21420    edit_action: BreakpointPromptEditAction,
21421    block_ids: HashSet<CustomBlockId>,
21422    editor_margins: Arc<Mutex<EditorMargins>>,
21423    _subscriptions: Vec<Subscription>,
21424}
21425
21426impl BreakpointPromptEditor {
21427    const MAX_LINES: u8 = 4;
21428
21429    fn new(
21430        editor: WeakEntity<Editor>,
21431        breakpoint_anchor: Anchor,
21432        breakpoint: Breakpoint,
21433        edit_action: BreakpointPromptEditAction,
21434        window: &mut Window,
21435        cx: &mut Context<Self>,
21436    ) -> Self {
21437        let base_text = match edit_action {
21438            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21439            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21440            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21441        }
21442        .map(|msg| msg.to_string())
21443        .unwrap_or_default();
21444
21445        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21446        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21447
21448        let prompt = cx.new(|cx| {
21449            let mut prompt = Editor::new(
21450                EditorMode::AutoHeight {
21451                    max_lines: Self::MAX_LINES as usize,
21452                },
21453                buffer,
21454                None,
21455                window,
21456                cx,
21457            );
21458            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21459            prompt.set_show_cursor_when_unfocused(false, cx);
21460            prompt.set_placeholder_text(
21461                match edit_action {
21462                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21463                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21464                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21465                },
21466                cx,
21467            );
21468
21469            prompt
21470        });
21471
21472        Self {
21473            prompt,
21474            editor,
21475            breakpoint_anchor,
21476            breakpoint,
21477            edit_action,
21478            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21479            block_ids: Default::default(),
21480            _subscriptions: vec![],
21481        }
21482    }
21483
21484    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21485        self.block_ids.extend(block_ids)
21486    }
21487
21488    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21489        if let Some(editor) = self.editor.upgrade() {
21490            let message = self
21491                .prompt
21492                .read(cx)
21493                .buffer
21494                .read(cx)
21495                .as_singleton()
21496                .expect("A multi buffer in breakpoint prompt isn't possible")
21497                .read(cx)
21498                .as_rope()
21499                .to_string();
21500
21501            editor.update(cx, |editor, cx| {
21502                editor.edit_breakpoint_at_anchor(
21503                    self.breakpoint_anchor,
21504                    self.breakpoint.clone(),
21505                    match self.edit_action {
21506                        BreakpointPromptEditAction::Log => {
21507                            BreakpointEditAction::EditLogMessage(message.into())
21508                        }
21509                        BreakpointPromptEditAction::Condition => {
21510                            BreakpointEditAction::EditCondition(message.into())
21511                        }
21512                        BreakpointPromptEditAction::HitCondition => {
21513                            BreakpointEditAction::EditHitCondition(message.into())
21514                        }
21515                    },
21516                    cx,
21517                );
21518
21519                editor.remove_blocks(self.block_ids.clone(), None, cx);
21520                cx.focus_self(window);
21521            });
21522        }
21523    }
21524
21525    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21526        self.editor
21527            .update(cx, |editor, cx| {
21528                editor.remove_blocks(self.block_ids.clone(), None, cx);
21529                window.focus(&editor.focus_handle);
21530            })
21531            .log_err();
21532    }
21533
21534    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21535        let settings = ThemeSettings::get_global(cx);
21536        let text_style = TextStyle {
21537            color: if self.prompt.read(cx).read_only(cx) {
21538                cx.theme().colors().text_disabled
21539            } else {
21540                cx.theme().colors().text
21541            },
21542            font_family: settings.buffer_font.family.clone(),
21543            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21544            font_size: settings.buffer_font_size(cx).into(),
21545            font_weight: settings.buffer_font.weight,
21546            line_height: relative(settings.buffer_line_height.value()),
21547            ..Default::default()
21548        };
21549        EditorElement::new(
21550            &self.prompt,
21551            EditorStyle {
21552                background: cx.theme().colors().editor_background,
21553                local_player: cx.theme().players().local(),
21554                text: text_style,
21555                ..Default::default()
21556            },
21557        )
21558    }
21559}
21560
21561impl Render for BreakpointPromptEditor {
21562    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21563        let editor_margins = *self.editor_margins.lock();
21564        let gutter_dimensions = editor_margins.gutter;
21565        h_flex()
21566            .key_context("Editor")
21567            .bg(cx.theme().colors().editor_background)
21568            .border_y_1()
21569            .border_color(cx.theme().status().info_border)
21570            .size_full()
21571            .py(window.line_height() / 2.5)
21572            .on_action(cx.listener(Self::confirm))
21573            .on_action(cx.listener(Self::cancel))
21574            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21575            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21576    }
21577}
21578
21579impl Focusable for BreakpointPromptEditor {
21580    fn focus_handle(&self, cx: &App) -> FocusHandle {
21581        self.prompt.focus_handle(cx)
21582    }
21583}
21584
21585fn all_edits_insertions_or_deletions(
21586    edits: &Vec<(Range<Anchor>, String)>,
21587    snapshot: &MultiBufferSnapshot,
21588) -> bool {
21589    let mut all_insertions = true;
21590    let mut all_deletions = true;
21591
21592    for (range, new_text) in edits.iter() {
21593        let range_is_empty = range.to_offset(&snapshot).is_empty();
21594        let text_is_empty = new_text.is_empty();
21595
21596        if range_is_empty != text_is_empty {
21597            if range_is_empty {
21598                all_deletions = false;
21599            } else {
21600                all_insertions = false;
21601            }
21602        } else {
21603            return false;
21604        }
21605
21606        if !all_insertions && !all_deletions {
21607            return false;
21608        }
21609    }
21610    all_insertions || all_deletions
21611}
21612
21613struct MissingEditPredictionKeybindingTooltip;
21614
21615impl Render for MissingEditPredictionKeybindingTooltip {
21616    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21617        ui::tooltip_container(window, cx, |container, _, cx| {
21618            container
21619                .flex_shrink_0()
21620                .max_w_80()
21621                .min_h(rems_from_px(124.))
21622                .justify_between()
21623                .child(
21624                    v_flex()
21625                        .flex_1()
21626                        .text_ui_sm(cx)
21627                        .child(Label::new("Conflict with Accept Keybinding"))
21628                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21629                )
21630                .child(
21631                    h_flex()
21632                        .pb_1()
21633                        .gap_1()
21634                        .items_end()
21635                        .w_full()
21636                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21637                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21638                        }))
21639                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21640                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21641                        })),
21642                )
21643        })
21644    }
21645}
21646
21647#[derive(Debug, Clone, Copy, PartialEq)]
21648pub struct LineHighlight {
21649    pub background: Background,
21650    pub border: Option<gpui::Hsla>,
21651    pub include_gutter: bool,
21652    pub type_id: Option<TypeId>,
21653}
21654
21655fn render_diff_hunk_controls(
21656    row: u32,
21657    status: &DiffHunkStatus,
21658    hunk_range: Range<Anchor>,
21659    is_created_file: bool,
21660    line_height: Pixels,
21661    editor: &Entity<Editor>,
21662    _window: &mut Window,
21663    cx: &mut App,
21664) -> AnyElement {
21665    h_flex()
21666        .h(line_height)
21667        .mr_1()
21668        .gap_1()
21669        .px_0p5()
21670        .pb_1()
21671        .border_x_1()
21672        .border_b_1()
21673        .border_color(cx.theme().colors().border_variant)
21674        .rounded_b_lg()
21675        .bg(cx.theme().colors().editor_background)
21676        .gap_1()
21677        .occlude()
21678        .shadow_md()
21679        .child(if status.has_secondary_hunk() {
21680            Button::new(("stage", row as u64), "Stage")
21681                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21682                .tooltip({
21683                    let focus_handle = editor.focus_handle(cx);
21684                    move |window, cx| {
21685                        Tooltip::for_action_in(
21686                            "Stage Hunk",
21687                            &::git::ToggleStaged,
21688                            &focus_handle,
21689                            window,
21690                            cx,
21691                        )
21692                    }
21693                })
21694                .on_click({
21695                    let editor = editor.clone();
21696                    move |_event, _window, cx| {
21697                        editor.update(cx, |editor, cx| {
21698                            editor.stage_or_unstage_diff_hunks(
21699                                true,
21700                                vec![hunk_range.start..hunk_range.start],
21701                                cx,
21702                            );
21703                        });
21704                    }
21705                })
21706        } else {
21707            Button::new(("unstage", row as u64), "Unstage")
21708                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21709                .tooltip({
21710                    let focus_handle = editor.focus_handle(cx);
21711                    move |window, cx| {
21712                        Tooltip::for_action_in(
21713                            "Unstage Hunk",
21714                            &::git::ToggleStaged,
21715                            &focus_handle,
21716                            window,
21717                            cx,
21718                        )
21719                    }
21720                })
21721                .on_click({
21722                    let editor = editor.clone();
21723                    move |_event, _window, cx| {
21724                        editor.update(cx, |editor, cx| {
21725                            editor.stage_or_unstage_diff_hunks(
21726                                false,
21727                                vec![hunk_range.start..hunk_range.start],
21728                                cx,
21729                            );
21730                        });
21731                    }
21732                })
21733        })
21734        .child(
21735            Button::new(("restore", row as u64), "Restore")
21736                .tooltip({
21737                    let focus_handle = editor.focus_handle(cx);
21738                    move |window, cx| {
21739                        Tooltip::for_action_in(
21740                            "Restore Hunk",
21741                            &::git::Restore,
21742                            &focus_handle,
21743                            window,
21744                            cx,
21745                        )
21746                    }
21747                })
21748                .on_click({
21749                    let editor = editor.clone();
21750                    move |_event, window, cx| {
21751                        editor.update(cx, |editor, cx| {
21752                            let snapshot = editor.snapshot(window, cx);
21753                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21754                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21755                        });
21756                    }
21757                })
21758                .disabled(is_created_file),
21759        )
21760        .when(
21761            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21762            |el| {
21763                el.child(
21764                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21765                        .shape(IconButtonShape::Square)
21766                        .icon_size(IconSize::Small)
21767                        // .disabled(!has_multiple_hunks)
21768                        .tooltip({
21769                            let focus_handle = editor.focus_handle(cx);
21770                            move |window, cx| {
21771                                Tooltip::for_action_in(
21772                                    "Next Hunk",
21773                                    &GoToHunk,
21774                                    &focus_handle,
21775                                    window,
21776                                    cx,
21777                                )
21778                            }
21779                        })
21780                        .on_click({
21781                            let editor = editor.clone();
21782                            move |_event, window, cx| {
21783                                editor.update(cx, |editor, cx| {
21784                                    let snapshot = editor.snapshot(window, cx);
21785                                    let position =
21786                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21787                                    editor.go_to_hunk_before_or_after_position(
21788                                        &snapshot,
21789                                        position,
21790                                        Direction::Next,
21791                                        window,
21792                                        cx,
21793                                    );
21794                                    editor.expand_selected_diff_hunks(cx);
21795                                });
21796                            }
21797                        }),
21798                )
21799                .child(
21800                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21801                        .shape(IconButtonShape::Square)
21802                        .icon_size(IconSize::Small)
21803                        // .disabled(!has_multiple_hunks)
21804                        .tooltip({
21805                            let focus_handle = editor.focus_handle(cx);
21806                            move |window, cx| {
21807                                Tooltip::for_action_in(
21808                                    "Previous Hunk",
21809                                    &GoToPreviousHunk,
21810                                    &focus_handle,
21811                                    window,
21812                                    cx,
21813                                )
21814                            }
21815                        })
21816                        .on_click({
21817                            let editor = editor.clone();
21818                            move |_event, window, cx| {
21819                                editor.update(cx, |editor, cx| {
21820                                    let snapshot = editor.snapshot(window, cx);
21821                                    let point =
21822                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21823                                    editor.go_to_hunk_before_or_after_position(
21824                                        &snapshot,
21825                                        point,
21826                                        Direction::Prev,
21827                                        window,
21828                                        cx,
21829                                    );
21830                                    editor.expand_selected_diff_hunks(cx);
21831                                });
21832                            }
21833                        }),
21834                )
21835            },
21836        )
21837        .into_any_element()
21838}