editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, SearchSettings,
   67    ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt,
   78    future::{self, Shared, join},
   79};
   80use fuzzy::StringMatchCandidate;
   81
   82use ::git::blame::BlameEntry;
   83use ::git::{Restore, blame::ParsedCommitMessage};
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use git::blame::{GitBlame, GlobalBlameRenderer};
   89use gpui::{
   90    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   91    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   92    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   93    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   94    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   95    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   96    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   97    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   98};
   99use highlight_matching_bracket::refresh_matching_bracket_highlights;
  100use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  101pub use hover_popover::hover_markdown_style;
  102use hover_popover::{HoverState, hide_hover};
  103use indent_guides::ActiveIndentGuidesState;
  104use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  105pub use inline_completion::Direction;
  106use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  107pub use items::MAX_TAB_TITLE_LEN;
  108use itertools::Itertools;
  109use language::{
  110    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  111    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  112    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  113    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  114    language_settings::{
  115        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  116        all_language_settings, language_settings,
  117    },
  118    point_from_lsp, text_diff_with_options,
  119};
  120use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  121use linked_editing_ranges::refresh_linked_ranges;
  122use markdown::Markdown;
  123use mouse_context_menu::MouseContextMenu;
  124use persistence::DB;
  125use project::{
  126    BreakpointWithPosition, ProjectPath,
  127    debugger::{
  128        breakpoint_store::{
  129            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  130            BreakpointStoreEvent,
  131        },
  132        session::{Session, SessionEvent},
  133    },
  134    project_settings::DiagnosticSeverity,
  135};
  136
  137pub use git::blame::BlameRenderer;
  138pub use proposed_changes_editor::{
  139    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  140};
  141use smallvec::smallvec;
  142use std::{cell::OnceCell, iter::Peekable, ops::Not};
  143use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  144
  145pub use lsp::CompletionContext;
  146use lsp::{
  147    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  148    LanguageServerId, LanguageServerName,
  149};
  150
  151use language::BufferSnapshot;
  152pub use lsp_ext::lsp_tasks;
  153use movement::TextLayoutDetails;
  154pub use multi_buffer::{
  155    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  156    RowInfo, ToOffset, ToPoint,
  157};
  158use multi_buffer::{
  159    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  160    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  161};
  162use parking_lot::Mutex;
  163use project::{
  164    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  165    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  166    TaskSourceKind,
  167    debugger::breakpoint_store::Breakpoint,
  168    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  169    project_settings::{GitGutterSetting, ProjectSettings},
  170};
  171use rand::prelude::*;
  172use rpc::{ErrorExt, proto::*};
  173use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  174use selections_collection::{
  175    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  176};
  177use serde::{Deserialize, Serialize};
  178use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  179use smallvec::SmallVec;
  180use snippet::Snippet;
  181use std::sync::Arc;
  182use std::{
  183    any::TypeId,
  184    borrow::Cow,
  185    cell::RefCell,
  186    cmp::{self, Ordering, Reverse},
  187    mem,
  188    num::NonZeroU32,
  189    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  190    path::{Path, PathBuf},
  191    rc::Rc,
  192    time::{Duration, Instant},
  193};
  194pub use sum_tree::Bias;
  195use sum_tree::TreeMap;
  196use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  197use theme::{
  198    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  199    observe_buffer_font_size_adjustment,
  200};
  201use ui::{
  202    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  203    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  204};
  205use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  206use workspace::{
  207    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  208    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  209    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  210    item::{ItemHandle, PreviewTabsSettings},
  211    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  212    searchable::SearchEvent,
  213};
  214
  215use crate::hover_links::{find_url, find_url_from_range};
  216use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  217
  218pub const FILE_HEADER_HEIGHT: u32 = 2;
  219pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  220pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  221const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  222const MAX_LINE_LEN: usize = 1024;
  223const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  224const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  225pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  226#[doc(hidden)]
  227pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  228const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  229
  230pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  233
  234pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  235pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  236pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  237pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  238
  239pub type RenderDiffHunkControlsFn = Arc<
  240    dyn Fn(
  241        u32,
  242        &DiffHunkStatus,
  243        Range<Anchor>,
  244        bool,
  245        Pixels,
  246        &Entity<Editor>,
  247        &mut Window,
  248        &mut App,
  249    ) -> AnyElement,
  250>;
  251
  252const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  253    alt: true,
  254    shift: true,
  255    control: false,
  256    platform: false,
  257    function: false,
  258};
  259
  260struct InlineValueCache {
  261    enabled: bool,
  262    inlays: Vec<InlayId>,
  263    refresh_task: Task<Option<()>>,
  264}
  265
  266impl InlineValueCache {
  267    fn new(enabled: bool) -> Self {
  268        Self {
  269            enabled,
  270            inlays: Vec::new(),
  271            refresh_task: Task::ready(None),
  272        }
  273    }
  274}
  275
  276#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  277pub enum InlayId {
  278    InlineCompletion(usize),
  279    Hint(usize),
  280    DebuggerValue(usize),
  281}
  282
  283impl InlayId {
  284    fn id(&self) -> usize {
  285        match self {
  286            Self::InlineCompletion(id) => *id,
  287            Self::Hint(id) => *id,
  288            Self::DebuggerValue(id) => *id,
  289        }
  290    }
  291}
  292
  293pub enum ActiveDebugLine {}
  294pub enum DebugStackFrameLine {}
  295enum DocumentHighlightRead {}
  296enum DocumentHighlightWrite {}
  297enum InputComposition {}
  298enum SelectedTextHighlight {}
  299
  300pub enum ConflictsOuter {}
  301pub enum ConflictsOurs {}
  302pub enum ConflictsTheirs {}
  303pub enum ConflictsOursMarker {}
  304pub enum ConflictsTheirsMarker {}
  305
  306#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  307pub enum Navigated {
  308    Yes,
  309    No,
  310}
  311
  312impl Navigated {
  313    pub fn from_bool(yes: bool) -> Navigated {
  314        if yes { Navigated::Yes } else { Navigated::No }
  315    }
  316}
  317
  318#[derive(Debug, Clone, PartialEq, Eq)]
  319enum DisplayDiffHunk {
  320    Folded {
  321        display_row: DisplayRow,
  322    },
  323    Unfolded {
  324        is_created_file: bool,
  325        diff_base_byte_range: Range<usize>,
  326        display_row_range: Range<DisplayRow>,
  327        multi_buffer_range: Range<Anchor>,
  328        status: DiffHunkStatus,
  329    },
  330}
  331
  332pub enum HideMouseCursorOrigin {
  333    TypingAction,
  334    MovementAction,
  335}
  336
  337pub fn init_settings(cx: &mut App) {
  338    EditorSettings::register(cx);
  339}
  340
  341pub fn init(cx: &mut App) {
  342    init_settings(cx);
  343
  344    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  345
  346    workspace::register_project_item::<Editor>(cx);
  347    workspace::FollowableViewRegistry::register::<Editor>(cx);
  348    workspace::register_serializable_item::<Editor>(cx);
  349
  350    cx.observe_new(
  351        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  352            workspace.register_action(Editor::new_file);
  353            workspace.register_action(Editor::new_file_vertical);
  354            workspace.register_action(Editor::new_file_horizontal);
  355            workspace.register_action(Editor::cancel_language_server_work);
  356        },
  357    )
  358    .detach();
  359
  360    cx.on_action(move |_: &workspace::NewFile, cx| {
  361        let app_state = workspace::AppState::global(cx);
  362        if let Some(app_state) = app_state.upgrade() {
  363            workspace::open_new(
  364                Default::default(),
  365                app_state,
  366                cx,
  367                |workspace, window, cx| {
  368                    Editor::new_file(workspace, &Default::default(), window, cx)
  369                },
  370            )
  371            .detach();
  372        }
  373    });
  374    cx.on_action(move |_: &workspace::NewWindow, cx| {
  375        let app_state = workspace::AppState::global(cx);
  376        if let Some(app_state) = app_state.upgrade() {
  377            workspace::open_new(
  378                Default::default(),
  379                app_state,
  380                cx,
  381                |workspace, window, cx| {
  382                    cx.activate(true);
  383                    Editor::new_file(workspace, &Default::default(), window, cx)
  384                },
  385            )
  386            .detach();
  387        }
  388    });
  389}
  390
  391pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  392    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  393}
  394
  395pub trait DiagnosticRenderer {
  396    fn render_group(
  397        &self,
  398        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  399        buffer_id: BufferId,
  400        snapshot: EditorSnapshot,
  401        editor: WeakEntity<Editor>,
  402        cx: &mut App,
  403    ) -> Vec<BlockProperties<Anchor>>;
  404
  405    fn render_hover(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  408        range: Range<Point>,
  409        buffer_id: BufferId,
  410        cx: &mut App,
  411    ) -> Option<Entity<markdown::Markdown>>;
  412
  413    fn open_link(
  414        &self,
  415        editor: &mut Editor,
  416        link: SharedString,
  417        window: &mut Window,
  418        cx: &mut Context<Editor>,
  419    );
  420}
  421
  422pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  423
  424impl GlobalDiagnosticRenderer {
  425    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  426        cx.try_global::<Self>().map(|g| g.0.clone())
  427    }
  428}
  429
  430impl gpui::Global for GlobalDiagnosticRenderer {}
  431pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  432    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  433}
  434
  435pub struct SearchWithinRange;
  436
  437trait InvalidationRegion {
  438    fn ranges(&self) -> &[Range<Anchor>];
  439}
  440
  441#[derive(Clone, Debug, PartialEq)]
  442pub enum SelectPhase {
  443    Begin {
  444        position: DisplayPoint,
  445        add: bool,
  446        click_count: usize,
  447    },
  448    BeginColumnar {
  449        position: DisplayPoint,
  450        reset: bool,
  451        goal_column: u32,
  452    },
  453    Extend {
  454        position: DisplayPoint,
  455        click_count: usize,
  456    },
  457    Update {
  458        position: DisplayPoint,
  459        goal_column: u32,
  460        scroll_delta: gpui::Point<f32>,
  461    },
  462    End,
  463}
  464
  465#[derive(Clone, Debug)]
  466pub enum SelectMode {
  467    Character,
  468    Word(Range<Anchor>),
  469    Line(Range<Anchor>),
  470    All,
  471}
  472
  473#[derive(Clone, PartialEq, Eq, Debug)]
  474pub enum EditorMode {
  475    SingleLine {
  476        auto_width: bool,
  477    },
  478    AutoHeight {
  479        max_lines: usize,
  480    },
  481    Full {
  482        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  483        scale_ui_elements_with_buffer_font_size: bool,
  484        /// When set to `true`, the editor will render a background for the active line.
  485        show_active_line_background: bool,
  486        /// When set to `true`, the editor's height will be determined by its content.
  487        sized_by_content: bool,
  488    },
  489    Minimap {
  490        parent: WeakEntity<Editor>,
  491    },
  492}
  493
  494impl EditorMode {
  495    pub fn full() -> Self {
  496        Self::Full {
  497            scale_ui_elements_with_buffer_font_size: true,
  498            show_active_line_background: true,
  499            sized_by_content: false,
  500        }
  501    }
  502
  503    pub fn is_full(&self) -> bool {
  504        matches!(self, Self::Full { .. })
  505    }
  506
  507    fn is_minimap(&self) -> bool {
  508        matches!(self, Self::Minimap { .. })
  509    }
  510}
  511
  512#[derive(Copy, Clone, Debug)]
  513pub enum SoftWrap {
  514    /// Prefer not to wrap at all.
  515    ///
  516    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  517    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  518    GitDiff,
  519    /// Prefer a single line generally, unless an overly long line is encountered.
  520    None,
  521    /// Soft wrap lines that exceed the editor width.
  522    EditorWidth,
  523    /// Soft wrap lines at the preferred line length.
  524    Column(u32),
  525    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  526    Bounded(u32),
  527}
  528
  529#[derive(Clone)]
  530pub struct EditorStyle {
  531    pub background: Hsla,
  532    pub local_player: PlayerColor,
  533    pub text: TextStyle,
  534    pub scrollbar_width: Pixels,
  535    pub syntax: Arc<SyntaxTheme>,
  536    pub status: StatusColors,
  537    pub inlay_hints_style: HighlightStyle,
  538    pub inline_completion_styles: InlineCompletionStyles,
  539    pub unnecessary_code_fade: f32,
  540    pub show_underlines: bool,
  541}
  542
  543impl Default for EditorStyle {
  544    fn default() -> Self {
  545        Self {
  546            background: Hsla::default(),
  547            local_player: PlayerColor::default(),
  548            text: TextStyle::default(),
  549            scrollbar_width: Pixels::default(),
  550            syntax: Default::default(),
  551            // HACK: Status colors don't have a real default.
  552            // We should look into removing the status colors from the editor
  553            // style and retrieve them directly from the theme.
  554            status: StatusColors::dark(),
  555            inlay_hints_style: HighlightStyle::default(),
  556            inline_completion_styles: InlineCompletionStyles {
  557                insertion: HighlightStyle::default(),
  558                whitespace: HighlightStyle::default(),
  559            },
  560            unnecessary_code_fade: Default::default(),
  561            show_underlines: true,
  562        }
  563    }
  564}
  565
  566pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  567    let show_background = language_settings::language_settings(None, None, cx)
  568        .inlay_hints
  569        .show_background;
  570
  571    HighlightStyle {
  572        color: Some(cx.theme().status().hint),
  573        background_color: show_background.then(|| cx.theme().status().hint_background),
  574        ..HighlightStyle::default()
  575    }
  576}
  577
  578pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  579    InlineCompletionStyles {
  580        insertion: HighlightStyle {
  581            color: Some(cx.theme().status().predictive),
  582            ..HighlightStyle::default()
  583        },
  584        whitespace: HighlightStyle {
  585            background_color: Some(cx.theme().status().created_background),
  586            ..HighlightStyle::default()
  587        },
  588    }
  589}
  590
  591type CompletionId = usize;
  592
  593pub(crate) enum EditDisplayMode {
  594    TabAccept,
  595    DiffPopover,
  596    Inline,
  597}
  598
  599enum InlineCompletion {
  600    Edit {
  601        edits: Vec<(Range<Anchor>, String)>,
  602        edit_preview: Option<EditPreview>,
  603        display_mode: EditDisplayMode,
  604        snapshot: BufferSnapshot,
  605    },
  606    Move {
  607        target: Anchor,
  608        snapshot: BufferSnapshot,
  609    },
  610}
  611
  612struct InlineCompletionState {
  613    inlay_ids: Vec<InlayId>,
  614    completion: InlineCompletion,
  615    completion_id: Option<SharedString>,
  616    invalidation_range: Range<Anchor>,
  617}
  618
  619enum EditPredictionSettings {
  620    Disabled,
  621    Enabled {
  622        show_in_menu: bool,
  623        preview_requires_modifier: bool,
  624    },
  625}
  626
  627enum InlineCompletionHighlight {}
  628
  629#[derive(Debug, Clone)]
  630struct InlineDiagnostic {
  631    message: SharedString,
  632    group_id: usize,
  633    is_primary: bool,
  634    start: Point,
  635    severity: lsp::DiagnosticSeverity,
  636}
  637
  638pub enum MenuInlineCompletionsPolicy {
  639    Never,
  640    ByProvider,
  641}
  642
  643pub enum EditPredictionPreview {
  644    /// Modifier is not pressed
  645    Inactive { released_too_fast: bool },
  646    /// Modifier pressed
  647    Active {
  648        since: Instant,
  649        previous_scroll_position: Option<ScrollAnchor>,
  650    },
  651}
  652
  653impl EditPredictionPreview {
  654    pub fn released_too_fast(&self) -> bool {
  655        match self {
  656            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  657            EditPredictionPreview::Active { .. } => false,
  658        }
  659    }
  660
  661    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  662        if let EditPredictionPreview::Active {
  663            previous_scroll_position,
  664            ..
  665        } = self
  666        {
  667            *previous_scroll_position = scroll_position;
  668        }
  669    }
  670}
  671
  672pub struct ContextMenuOptions {
  673    pub min_entries_visible: usize,
  674    pub max_entries_visible: usize,
  675    pub placement: Option<ContextMenuPlacement>,
  676}
  677
  678#[derive(Debug, Clone, PartialEq, Eq)]
  679pub enum ContextMenuPlacement {
  680    Above,
  681    Below,
  682}
  683
  684#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  685struct EditorActionId(usize);
  686
  687impl EditorActionId {
  688    pub fn post_inc(&mut self) -> Self {
  689        let answer = self.0;
  690
  691        *self = Self(answer + 1);
  692
  693        Self(answer)
  694    }
  695}
  696
  697// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  698// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  699
  700type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  701type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  702
  703#[derive(Default)]
  704struct ScrollbarMarkerState {
  705    scrollbar_size: Size<Pixels>,
  706    dirty: bool,
  707    markers: Arc<[PaintQuad]>,
  708    pending_refresh: Option<Task<Result<()>>>,
  709}
  710
  711impl ScrollbarMarkerState {
  712    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  713        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  714    }
  715}
  716
  717#[derive(Clone, Copy, PartialEq, Eq)]
  718pub enum MinimapVisibility {
  719    Disabled,
  720    Enabled(bool),
  721}
  722
  723impl MinimapVisibility {
  724    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  725        if mode.is_full() {
  726            Self::Enabled(EditorSettings::get_global(cx).minimap.minimap_enabled())
  727        } else {
  728            Self::Disabled
  729        }
  730    }
  731
  732    fn disabled(&self) -> bool {
  733        match *self {
  734            Self::Disabled => true,
  735            _ => false,
  736        }
  737    }
  738
  739    fn visible(&self) -> bool {
  740        match *self {
  741            Self::Enabled(visible) => visible,
  742            _ => false,
  743        }
  744    }
  745
  746    fn toggle_visibility(&self) -> Self {
  747        match *self {
  748            Self::Enabled(visible) => Self::Enabled(!visible),
  749            Self::Disabled => Self::Disabled,
  750        }
  751    }
  752}
  753
  754#[derive(Clone, Debug)]
  755struct RunnableTasks {
  756    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  757    offset: multi_buffer::Anchor,
  758    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  759    column: u32,
  760    // Values of all named captures, including those starting with '_'
  761    extra_variables: HashMap<String, String>,
  762    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  763    context_range: Range<BufferOffset>,
  764}
  765
  766impl RunnableTasks {
  767    fn resolve<'a>(
  768        &'a self,
  769        cx: &'a task::TaskContext,
  770    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  771        self.templates.iter().filter_map(|(kind, template)| {
  772            template
  773                .resolve_task(&kind.to_id_base(), cx)
  774                .map(|task| (kind.clone(), task))
  775        })
  776    }
  777}
  778
  779#[derive(Clone)]
  780pub struct ResolvedTasks {
  781    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  782    position: Anchor,
  783}
  784
  785#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  786struct BufferOffset(usize);
  787
  788// Addons allow storing per-editor state in other crates (e.g. Vim)
  789pub trait Addon: 'static {
  790    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  791
  792    fn render_buffer_header_controls(
  793        &self,
  794        _: &ExcerptInfo,
  795        _: &Window,
  796        _: &App,
  797    ) -> Option<AnyElement> {
  798        None
  799    }
  800
  801    fn to_any(&self) -> &dyn std::any::Any;
  802
  803    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  804        None
  805    }
  806}
  807
  808/// A set of caret positions, registered when the editor was edited.
  809pub struct ChangeList {
  810    changes: Vec<Vec<Anchor>>,
  811    /// Currently "selected" change.
  812    position: Option<usize>,
  813}
  814
  815impl ChangeList {
  816    pub fn new() -> Self {
  817        Self {
  818            changes: Vec::new(),
  819            position: None,
  820        }
  821    }
  822
  823    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  824    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  825    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  826        if self.changes.is_empty() {
  827            return None;
  828        }
  829
  830        let prev = self.position.unwrap_or(self.changes.len());
  831        let next = if direction == Direction::Prev {
  832            prev.saturating_sub(count)
  833        } else {
  834            (prev + count).min(self.changes.len() - 1)
  835        };
  836        self.position = Some(next);
  837        self.changes.get(next).map(|anchors| anchors.as_slice())
  838    }
  839
  840    /// Adds a new change to the list, resetting the change list position.
  841    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  842        self.position.take();
  843        if pop_state {
  844            self.changes.pop();
  845        }
  846        self.changes.push(new_positions.clone());
  847    }
  848
  849    pub fn last(&self) -> Option<&[Anchor]> {
  850        self.changes.last().map(|anchors| anchors.as_slice())
  851    }
  852}
  853
  854#[derive(Clone)]
  855struct InlineBlamePopoverState {
  856    scroll_handle: ScrollHandle,
  857    commit_message: Option<ParsedCommitMessage>,
  858    markdown: Entity<Markdown>,
  859}
  860
  861struct InlineBlamePopover {
  862    position: gpui::Point<Pixels>,
  863    show_task: Option<Task<()>>,
  864    hide_task: Option<Task<()>>,
  865    popover_bounds: Option<Bounds<Pixels>>,
  866    popover_state: InlineBlamePopoverState,
  867}
  868
  869/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  870/// a breakpoint on them.
  871#[derive(Clone, Copy, Debug)]
  872struct PhantomBreakpointIndicator {
  873    display_row: DisplayRow,
  874    /// There's a small debounce between hovering over the line and showing the indicator.
  875    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  876    is_active: bool,
  877    collides_with_existing_breakpoint: bool,
  878}
  879/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  880///
  881/// See the [module level documentation](self) for more information.
  882pub struct Editor {
  883    focus_handle: FocusHandle,
  884    last_focused_descendant: Option<WeakFocusHandle>,
  885    /// The text buffer being edited
  886    buffer: Entity<MultiBuffer>,
  887    /// Map of how text in the buffer should be displayed.
  888    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  889    pub display_map: Entity<DisplayMap>,
  890    pub selections: SelectionsCollection,
  891    pub scroll_manager: ScrollManager,
  892    /// When inline assist editors are linked, they all render cursors because
  893    /// typing enters text into each of them, even the ones that aren't focused.
  894    pub(crate) show_cursor_when_unfocused: bool,
  895    columnar_selection_tail: Option<Anchor>,
  896    add_selections_state: Option<AddSelectionsState>,
  897    select_next_state: Option<SelectNextState>,
  898    select_prev_state: Option<SelectNextState>,
  899    selection_history: SelectionHistory,
  900    autoclose_regions: Vec<AutocloseRegion>,
  901    snippet_stack: InvalidationStack<SnippetState>,
  902    select_syntax_node_history: SelectSyntaxNodeHistory,
  903    ime_transaction: Option<TransactionId>,
  904    pub diagnostics_max_severity: DiagnosticSeverity,
  905    active_diagnostics: ActiveDiagnostic,
  906    show_inline_diagnostics: bool,
  907    inline_diagnostics_update: Task<()>,
  908    inline_diagnostics_enabled: bool,
  909    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  910    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  911    hard_wrap: Option<usize>,
  912
  913    // TODO: make this a access method
  914    pub project: Option<Entity<Project>>,
  915    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  916    completion_provider: Option<Box<dyn CompletionProvider>>,
  917    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  918    blink_manager: Entity<BlinkManager>,
  919    show_cursor_names: bool,
  920    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  921    pub show_local_selections: bool,
  922    mode: EditorMode,
  923    show_breadcrumbs: bool,
  924    show_gutter: bool,
  925    show_scrollbars: bool,
  926    minimap_visibility: MinimapVisibility,
  927    disable_expand_excerpt_buttons: bool,
  928    show_line_numbers: Option<bool>,
  929    use_relative_line_numbers: Option<bool>,
  930    show_git_diff_gutter: Option<bool>,
  931    show_code_actions: Option<bool>,
  932    show_runnables: Option<bool>,
  933    show_breakpoints: Option<bool>,
  934    show_wrap_guides: Option<bool>,
  935    show_indent_guides: Option<bool>,
  936    placeholder_text: Option<Arc<str>>,
  937    highlight_order: usize,
  938    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  939    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  940    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  941    scrollbar_marker_state: ScrollbarMarkerState,
  942    active_indent_guides_state: ActiveIndentGuidesState,
  943    nav_history: Option<ItemNavHistory>,
  944    context_menu: RefCell<Option<CodeContextMenu>>,
  945    context_menu_options: Option<ContextMenuOptions>,
  946    mouse_context_menu: Option<MouseContextMenu>,
  947    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  948    inline_blame_popover: Option<InlineBlamePopover>,
  949    signature_help_state: SignatureHelpState,
  950    auto_signature_help: Option<bool>,
  951    find_all_references_task_sources: Vec<Anchor>,
  952    next_completion_id: CompletionId,
  953    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  954    code_actions_task: Option<Task<Result<()>>>,
  955    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  956    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  957    document_highlights_task: Option<Task<()>>,
  958    linked_editing_range_task: Option<Task<Option<()>>>,
  959    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  960    pending_rename: Option<RenameState>,
  961    searchable: bool,
  962    cursor_shape: CursorShape,
  963    current_line_highlight: Option<CurrentLineHighlight>,
  964    collapse_matches: bool,
  965    autoindent_mode: Option<AutoindentMode>,
  966    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  967    input_enabled: bool,
  968    use_modal_editing: bool,
  969    read_only: bool,
  970    leader_id: Option<CollaboratorId>,
  971    remote_id: Option<ViewId>,
  972    pub hover_state: HoverState,
  973    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  974    gutter_hovered: bool,
  975    hovered_link_state: Option<HoveredLinkState>,
  976    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  977    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  978    active_inline_completion: Option<InlineCompletionState>,
  979    /// Used to prevent flickering as the user types while the menu is open
  980    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  981    edit_prediction_settings: EditPredictionSettings,
  982    inline_completions_hidden_for_vim_mode: bool,
  983    show_inline_completions_override: Option<bool>,
  984    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  985    edit_prediction_preview: EditPredictionPreview,
  986    edit_prediction_indent_conflict: bool,
  987    edit_prediction_requires_modifier_in_indent_conflict: bool,
  988    inlay_hint_cache: InlayHintCache,
  989    next_inlay_id: usize,
  990    _subscriptions: Vec<Subscription>,
  991    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  992    gutter_dimensions: GutterDimensions,
  993    style: Option<EditorStyle>,
  994    text_style_refinement: Option<TextStyleRefinement>,
  995    next_editor_action_id: EditorActionId,
  996    editor_actions:
  997        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  998    use_autoclose: bool,
  999    use_auto_surround: bool,
 1000    auto_replace_emoji_shortcode: bool,
 1001    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1002    show_git_blame_gutter: bool,
 1003    show_git_blame_inline: bool,
 1004    show_git_blame_inline_delay_task: Option<Task<()>>,
 1005    git_blame_inline_enabled: bool,
 1006    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1007    serialize_dirty_buffers: bool,
 1008    show_selection_menu: Option<bool>,
 1009    blame: Option<Entity<GitBlame>>,
 1010    blame_subscription: Option<Subscription>,
 1011    custom_context_menu: Option<
 1012        Box<
 1013            dyn 'static
 1014                + Fn(
 1015                    &mut Self,
 1016                    DisplayPoint,
 1017                    &mut Window,
 1018                    &mut Context<Self>,
 1019                ) -> Option<Entity<ui::ContextMenu>>,
 1020        >,
 1021    >,
 1022    last_bounds: Option<Bounds<Pixels>>,
 1023    last_position_map: Option<Rc<PositionMap>>,
 1024    expect_bounds_change: Option<Bounds<Pixels>>,
 1025    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1026    tasks_update_task: Option<Task<()>>,
 1027    breakpoint_store: Option<Entity<BreakpointStore>>,
 1028    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1029    in_project_search: bool,
 1030    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1031    breadcrumb_header: Option<String>,
 1032    focused_block: Option<FocusedBlock>,
 1033    next_scroll_position: NextScrollCursorCenterTopBottom,
 1034    addons: HashMap<TypeId, Box<dyn Addon>>,
 1035    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1036    load_diff_task: Option<Shared<Task<()>>>,
 1037    /// Whether we are temporarily displaying a diff other than git's
 1038    temporary_diff_override: bool,
 1039    selection_mark_mode: bool,
 1040    toggle_fold_multiple_buffers: Task<()>,
 1041    _scroll_cursor_center_top_bottom_task: Task<()>,
 1042    serialize_selections: Task<()>,
 1043    serialize_folds: Task<()>,
 1044    mouse_cursor_hidden: bool,
 1045    minimap: Option<Entity<Self>>,
 1046    hide_mouse_mode: HideMouseMode,
 1047    pub change_list: ChangeList,
 1048    inline_value_cache: InlineValueCache,
 1049}
 1050
 1051#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1052enum NextScrollCursorCenterTopBottom {
 1053    #[default]
 1054    Center,
 1055    Top,
 1056    Bottom,
 1057}
 1058
 1059impl NextScrollCursorCenterTopBottom {
 1060    fn next(&self) -> Self {
 1061        match self {
 1062            Self::Center => Self::Top,
 1063            Self::Top => Self::Bottom,
 1064            Self::Bottom => Self::Center,
 1065        }
 1066    }
 1067}
 1068
 1069#[derive(Clone)]
 1070pub struct EditorSnapshot {
 1071    pub mode: EditorMode,
 1072    show_gutter: bool,
 1073    show_line_numbers: Option<bool>,
 1074    show_git_diff_gutter: Option<bool>,
 1075    show_runnables: Option<bool>,
 1076    show_breakpoints: Option<bool>,
 1077    git_blame_gutter_max_author_length: Option<usize>,
 1078    pub display_snapshot: DisplaySnapshot,
 1079    pub placeholder_text: Option<Arc<str>>,
 1080    is_focused: bool,
 1081    scroll_anchor: ScrollAnchor,
 1082    ongoing_scroll: OngoingScroll,
 1083    current_line_highlight: CurrentLineHighlight,
 1084    gutter_hovered: bool,
 1085}
 1086
 1087#[derive(Default, Debug, Clone, Copy)]
 1088pub struct GutterDimensions {
 1089    pub left_padding: Pixels,
 1090    pub right_padding: Pixels,
 1091    pub width: Pixels,
 1092    pub margin: Pixels,
 1093    pub git_blame_entries_width: Option<Pixels>,
 1094}
 1095
 1096impl GutterDimensions {
 1097    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1098        Self {
 1099            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1100            ..Default::default()
 1101        }
 1102    }
 1103
 1104    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1105        -cx.text_system().descent(font_id, font_size)
 1106    }
 1107    /// The full width of the space taken up by the gutter.
 1108    pub fn full_width(&self) -> Pixels {
 1109        self.margin + self.width
 1110    }
 1111
 1112    /// The width of the space reserved for the fold indicators,
 1113    /// use alongside 'justify_end' and `gutter_width` to
 1114    /// right align content with the line numbers
 1115    pub fn fold_area_width(&self) -> Pixels {
 1116        self.margin + self.right_padding
 1117    }
 1118}
 1119
 1120#[derive(Debug)]
 1121pub struct RemoteSelection {
 1122    pub replica_id: ReplicaId,
 1123    pub selection: Selection<Anchor>,
 1124    pub cursor_shape: CursorShape,
 1125    pub collaborator_id: CollaboratorId,
 1126    pub line_mode: bool,
 1127    pub user_name: Option<SharedString>,
 1128    pub color: PlayerColor,
 1129}
 1130
 1131#[derive(Clone, Debug)]
 1132struct SelectionHistoryEntry {
 1133    selections: Arc<[Selection<Anchor>]>,
 1134    select_next_state: Option<SelectNextState>,
 1135    select_prev_state: Option<SelectNextState>,
 1136    add_selections_state: Option<AddSelectionsState>,
 1137}
 1138
 1139enum SelectionHistoryMode {
 1140    Normal,
 1141    Undoing,
 1142    Redoing,
 1143}
 1144
 1145#[derive(Clone, PartialEq, Eq, Hash)]
 1146struct HoveredCursor {
 1147    replica_id: u16,
 1148    selection_id: usize,
 1149}
 1150
 1151impl Default for SelectionHistoryMode {
 1152    fn default() -> Self {
 1153        Self::Normal
 1154    }
 1155}
 1156
 1157#[derive(Default)]
 1158struct SelectionHistory {
 1159    #[allow(clippy::type_complexity)]
 1160    selections_by_transaction:
 1161        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1162    mode: SelectionHistoryMode,
 1163    undo_stack: VecDeque<SelectionHistoryEntry>,
 1164    redo_stack: VecDeque<SelectionHistoryEntry>,
 1165}
 1166
 1167impl SelectionHistory {
 1168    fn insert_transaction(
 1169        &mut self,
 1170        transaction_id: TransactionId,
 1171        selections: Arc<[Selection<Anchor>]>,
 1172    ) {
 1173        self.selections_by_transaction
 1174            .insert(transaction_id, (selections, None));
 1175    }
 1176
 1177    #[allow(clippy::type_complexity)]
 1178    fn transaction(
 1179        &self,
 1180        transaction_id: TransactionId,
 1181    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1182        self.selections_by_transaction.get(&transaction_id)
 1183    }
 1184
 1185    #[allow(clippy::type_complexity)]
 1186    fn transaction_mut(
 1187        &mut self,
 1188        transaction_id: TransactionId,
 1189    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1190        self.selections_by_transaction.get_mut(&transaction_id)
 1191    }
 1192
 1193    fn push(&mut self, entry: SelectionHistoryEntry) {
 1194        if !entry.selections.is_empty() {
 1195            match self.mode {
 1196                SelectionHistoryMode::Normal => {
 1197                    self.push_undo(entry);
 1198                    self.redo_stack.clear();
 1199                }
 1200                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1201                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1202            }
 1203        }
 1204    }
 1205
 1206    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1207        if self
 1208            .undo_stack
 1209            .back()
 1210            .map_or(true, |e| e.selections != entry.selections)
 1211        {
 1212            self.undo_stack.push_back(entry);
 1213            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1214                self.undo_stack.pop_front();
 1215            }
 1216        }
 1217    }
 1218
 1219    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1220        if self
 1221            .redo_stack
 1222            .back()
 1223            .map_or(true, |e| e.selections != entry.selections)
 1224        {
 1225            self.redo_stack.push_back(entry);
 1226            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1227                self.redo_stack.pop_front();
 1228            }
 1229        }
 1230    }
 1231}
 1232
 1233#[derive(Clone, Copy)]
 1234pub struct RowHighlightOptions {
 1235    pub autoscroll: bool,
 1236    pub include_gutter: bool,
 1237}
 1238
 1239impl Default for RowHighlightOptions {
 1240    fn default() -> Self {
 1241        Self {
 1242            autoscroll: Default::default(),
 1243            include_gutter: true,
 1244        }
 1245    }
 1246}
 1247
 1248struct RowHighlight {
 1249    index: usize,
 1250    range: Range<Anchor>,
 1251    color: Hsla,
 1252    options: RowHighlightOptions,
 1253    type_id: TypeId,
 1254}
 1255
 1256#[derive(Clone, Debug)]
 1257struct AddSelectionsState {
 1258    above: bool,
 1259    stack: Vec<usize>,
 1260}
 1261
 1262#[derive(Clone)]
 1263struct SelectNextState {
 1264    query: AhoCorasick,
 1265    wordwise: bool,
 1266    done: bool,
 1267}
 1268
 1269impl std::fmt::Debug for SelectNextState {
 1270    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1271        f.debug_struct(std::any::type_name::<Self>())
 1272            .field("wordwise", &self.wordwise)
 1273            .field("done", &self.done)
 1274            .finish()
 1275    }
 1276}
 1277
 1278#[derive(Debug)]
 1279struct AutocloseRegion {
 1280    selection_id: usize,
 1281    range: Range<Anchor>,
 1282    pair: BracketPair,
 1283}
 1284
 1285#[derive(Debug)]
 1286struct SnippetState {
 1287    ranges: Vec<Vec<Range<Anchor>>>,
 1288    active_index: usize,
 1289    choices: Vec<Option<Vec<String>>>,
 1290}
 1291
 1292#[doc(hidden)]
 1293pub struct RenameState {
 1294    pub range: Range<Anchor>,
 1295    pub old_name: Arc<str>,
 1296    pub editor: Entity<Editor>,
 1297    block_id: CustomBlockId,
 1298}
 1299
 1300struct InvalidationStack<T>(Vec<T>);
 1301
 1302struct RegisteredInlineCompletionProvider {
 1303    provider: Arc<dyn InlineCompletionProviderHandle>,
 1304    _subscription: Subscription,
 1305}
 1306
 1307#[derive(Debug, PartialEq, Eq)]
 1308pub struct ActiveDiagnosticGroup {
 1309    pub active_range: Range<Anchor>,
 1310    pub active_message: String,
 1311    pub group_id: usize,
 1312    pub blocks: HashSet<CustomBlockId>,
 1313}
 1314
 1315#[derive(Debug, PartialEq, Eq)]
 1316
 1317pub(crate) enum ActiveDiagnostic {
 1318    None,
 1319    All,
 1320    Group(ActiveDiagnosticGroup),
 1321}
 1322
 1323#[derive(Serialize, Deserialize, Clone, Debug)]
 1324pub struct ClipboardSelection {
 1325    /// The number of bytes in this selection.
 1326    pub len: usize,
 1327    /// Whether this was a full-line selection.
 1328    pub is_entire_line: bool,
 1329    /// The indentation of the first line when this content was originally copied.
 1330    pub first_line_indent: u32,
 1331}
 1332
 1333// selections, scroll behavior, was newest selection reversed
 1334type SelectSyntaxNodeHistoryState = (
 1335    Box<[Selection<usize>]>,
 1336    SelectSyntaxNodeScrollBehavior,
 1337    bool,
 1338);
 1339
 1340#[derive(Default)]
 1341struct SelectSyntaxNodeHistory {
 1342    stack: Vec<SelectSyntaxNodeHistoryState>,
 1343    // disable temporarily to allow changing selections without losing the stack
 1344    pub disable_clearing: bool,
 1345}
 1346
 1347impl SelectSyntaxNodeHistory {
 1348    pub fn try_clear(&mut self) {
 1349        if !self.disable_clearing {
 1350            self.stack.clear();
 1351        }
 1352    }
 1353
 1354    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1355        self.stack.push(selection);
 1356    }
 1357
 1358    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1359        self.stack.pop()
 1360    }
 1361}
 1362
 1363enum SelectSyntaxNodeScrollBehavior {
 1364    CursorTop,
 1365    FitSelection,
 1366    CursorBottom,
 1367}
 1368
 1369#[derive(Debug)]
 1370pub(crate) struct NavigationData {
 1371    cursor_anchor: Anchor,
 1372    cursor_position: Point,
 1373    scroll_anchor: ScrollAnchor,
 1374    scroll_top_row: u32,
 1375}
 1376
 1377#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1378pub enum GotoDefinitionKind {
 1379    Symbol,
 1380    Declaration,
 1381    Type,
 1382    Implementation,
 1383}
 1384
 1385#[derive(Debug, Clone)]
 1386enum InlayHintRefreshReason {
 1387    ModifiersChanged(bool),
 1388    Toggle(bool),
 1389    SettingsChange(InlayHintSettings),
 1390    NewLinesShown,
 1391    BufferEdited(HashSet<Arc<Language>>),
 1392    RefreshRequested,
 1393    ExcerptsRemoved(Vec<ExcerptId>),
 1394}
 1395
 1396impl InlayHintRefreshReason {
 1397    fn description(&self) -> &'static str {
 1398        match self {
 1399            Self::ModifiersChanged(_) => "modifiers changed",
 1400            Self::Toggle(_) => "toggle",
 1401            Self::SettingsChange(_) => "settings change",
 1402            Self::NewLinesShown => "new lines shown",
 1403            Self::BufferEdited(_) => "buffer edited",
 1404            Self::RefreshRequested => "refresh requested",
 1405            Self::ExcerptsRemoved(_) => "excerpts removed",
 1406        }
 1407    }
 1408}
 1409
 1410pub enum FormatTarget {
 1411    Buffers,
 1412    Ranges(Vec<Range<MultiBufferPoint>>),
 1413}
 1414
 1415pub(crate) struct FocusedBlock {
 1416    id: BlockId,
 1417    focus_handle: WeakFocusHandle,
 1418}
 1419
 1420#[derive(Clone)]
 1421enum JumpData {
 1422    MultiBufferRow {
 1423        row: MultiBufferRow,
 1424        line_offset_from_top: u32,
 1425    },
 1426    MultiBufferPoint {
 1427        excerpt_id: ExcerptId,
 1428        position: Point,
 1429        anchor: text::Anchor,
 1430        line_offset_from_top: u32,
 1431    },
 1432}
 1433
 1434pub enum MultibufferSelectionMode {
 1435    First,
 1436    All,
 1437}
 1438
 1439#[derive(Clone, Copy, Debug, Default)]
 1440pub struct RewrapOptions {
 1441    pub override_language_settings: bool,
 1442    pub preserve_existing_whitespace: bool,
 1443}
 1444
 1445impl Editor {
 1446    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1447        let buffer = cx.new(|cx| Buffer::local("", cx));
 1448        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1449        Self::new(
 1450            EditorMode::SingleLine { auto_width: false },
 1451            buffer,
 1452            None,
 1453            window,
 1454            cx,
 1455        )
 1456    }
 1457
 1458    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1459        let buffer = cx.new(|cx| Buffer::local("", cx));
 1460        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1461        Self::new(EditorMode::full(), buffer, None, window, cx)
 1462    }
 1463
 1464    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1465        let buffer = cx.new(|cx| Buffer::local("", cx));
 1466        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1467        Self::new(
 1468            EditorMode::SingleLine { auto_width: true },
 1469            buffer,
 1470            None,
 1471            window,
 1472            cx,
 1473        )
 1474    }
 1475
 1476    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1477        let buffer = cx.new(|cx| Buffer::local("", cx));
 1478        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1479        Self::new(
 1480            EditorMode::AutoHeight { max_lines },
 1481            buffer,
 1482            None,
 1483            window,
 1484            cx,
 1485        )
 1486    }
 1487
 1488    pub fn for_buffer(
 1489        buffer: Entity<Buffer>,
 1490        project: Option<Entity<Project>>,
 1491        window: &mut Window,
 1492        cx: &mut Context<Self>,
 1493    ) -> Self {
 1494        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1495        Self::new(EditorMode::full(), buffer, project, window, cx)
 1496    }
 1497
 1498    pub fn for_multibuffer(
 1499        buffer: Entity<MultiBuffer>,
 1500        project: Option<Entity<Project>>,
 1501        window: &mut Window,
 1502        cx: &mut Context<Self>,
 1503    ) -> Self {
 1504        Self::new(EditorMode::full(), buffer, project, window, cx)
 1505    }
 1506
 1507    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1508        let mut clone = Self::new(
 1509            self.mode.clone(),
 1510            self.buffer.clone(),
 1511            self.project.clone(),
 1512            window,
 1513            cx,
 1514        );
 1515        self.display_map.update(cx, |display_map, cx| {
 1516            let snapshot = display_map.snapshot(cx);
 1517            clone.display_map.update(cx, |display_map, cx| {
 1518                display_map.set_state(&snapshot, cx);
 1519            });
 1520        });
 1521        clone.folds_did_change(cx);
 1522        clone.selections.clone_state(&self.selections);
 1523        clone.scroll_manager.clone_state(&self.scroll_manager);
 1524        clone.searchable = self.searchable;
 1525        clone.read_only = self.read_only;
 1526        clone
 1527    }
 1528
 1529    pub fn new(
 1530        mode: EditorMode,
 1531        buffer: Entity<MultiBuffer>,
 1532        project: Option<Entity<Project>>,
 1533        window: &mut Window,
 1534        cx: &mut Context<Self>,
 1535    ) -> Self {
 1536        Editor::new_internal(mode, buffer, project, None, window, cx)
 1537    }
 1538
 1539    fn new_internal(
 1540        mode: EditorMode,
 1541        buffer: Entity<MultiBuffer>,
 1542        project: Option<Entity<Project>>,
 1543        display_map: Option<Entity<DisplayMap>>,
 1544        window: &mut Window,
 1545        cx: &mut Context<Self>,
 1546    ) -> Self {
 1547        debug_assert!(
 1548            display_map.is_none() || mode.is_minimap(),
 1549            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1550        );
 1551
 1552        let full_mode = mode.is_full();
 1553        let diagnostics_max_severity = if full_mode {
 1554            EditorSettings::get_global(cx)
 1555                .diagnostics_max_severity
 1556                .unwrap_or(DiagnosticSeverity::Hint)
 1557        } else {
 1558            DiagnosticSeverity::Off
 1559        };
 1560        let style = window.text_style();
 1561        let font_size = style.font_size.to_pixels(window.rem_size());
 1562        let editor = cx.entity().downgrade();
 1563        let fold_placeholder = FoldPlaceholder {
 1564            constrain_width: true,
 1565            render: Arc::new(move |fold_id, fold_range, cx| {
 1566                let editor = editor.clone();
 1567                div()
 1568                    .id(fold_id)
 1569                    .bg(cx.theme().colors().ghost_element_background)
 1570                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1571                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1572                    .rounded_xs()
 1573                    .size_full()
 1574                    .cursor_pointer()
 1575                    .child("")
 1576                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1577                    .on_click(move |_, _window, cx| {
 1578                        editor
 1579                            .update(cx, |editor, cx| {
 1580                                editor.unfold_ranges(
 1581                                    &[fold_range.start..fold_range.end],
 1582                                    true,
 1583                                    false,
 1584                                    cx,
 1585                                );
 1586                                cx.stop_propagation();
 1587                            })
 1588                            .ok();
 1589                    })
 1590                    .into_any()
 1591            }),
 1592            merge_adjacent: true,
 1593            ..FoldPlaceholder::default()
 1594        };
 1595        let display_map = display_map.unwrap_or_else(|| {
 1596            cx.new(|cx| {
 1597                DisplayMap::new(
 1598                    buffer.clone(),
 1599                    style.font(),
 1600                    font_size,
 1601                    None,
 1602                    FILE_HEADER_HEIGHT,
 1603                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1604                    fold_placeholder,
 1605                    diagnostics_max_severity,
 1606                    cx,
 1607                )
 1608            })
 1609        });
 1610
 1611        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1612
 1613        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1614
 1615        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1616            .then(|| language_settings::SoftWrap::None);
 1617
 1618        let mut project_subscriptions = Vec::new();
 1619        if mode.is_full() {
 1620            if let Some(project) = project.as_ref() {
 1621                project_subscriptions.push(cx.subscribe_in(
 1622                    project,
 1623                    window,
 1624                    |editor, _, event, window, cx| match event {
 1625                        project::Event::RefreshCodeLens => {
 1626                            // we always query lens with actions, without storing them, always refreshing them
 1627                        }
 1628                        project::Event::RefreshInlayHints => {
 1629                            editor
 1630                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1631                        }
 1632                        project::Event::SnippetEdit(id, snippet_edits) => {
 1633                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1634                                let focus_handle = editor.focus_handle(cx);
 1635                                if focus_handle.is_focused(window) {
 1636                                    let snapshot = buffer.read(cx).snapshot();
 1637                                    for (range, snippet) in snippet_edits {
 1638                                        let editor_range =
 1639                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1640                                        editor
 1641                                            .insert_snippet(
 1642                                                &[editor_range],
 1643                                                snippet.clone(),
 1644                                                window,
 1645                                                cx,
 1646                                            )
 1647                                            .ok();
 1648                                    }
 1649                                }
 1650                            }
 1651                        }
 1652                        _ => {}
 1653                    },
 1654                ));
 1655                if let Some(task_inventory) = project
 1656                    .read(cx)
 1657                    .task_store()
 1658                    .read(cx)
 1659                    .task_inventory()
 1660                    .cloned()
 1661                {
 1662                    project_subscriptions.push(cx.observe_in(
 1663                        &task_inventory,
 1664                        window,
 1665                        |editor, _, window, cx| {
 1666                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1667                        },
 1668                    ));
 1669                };
 1670
 1671                project_subscriptions.push(cx.subscribe_in(
 1672                    &project.read(cx).breakpoint_store(),
 1673                    window,
 1674                    |editor, _, event, window, cx| match event {
 1675                        BreakpointStoreEvent::ClearDebugLines => {
 1676                            editor.clear_row_highlights::<ActiveDebugLine>();
 1677                            editor.refresh_inline_values(cx);
 1678                        }
 1679                        BreakpointStoreEvent::SetDebugLine => {
 1680                            if editor.go_to_active_debug_line(window, cx) {
 1681                                cx.stop_propagation();
 1682                            }
 1683
 1684                            editor.refresh_inline_values(cx);
 1685                        }
 1686                        _ => {}
 1687                    },
 1688                ));
 1689            }
 1690        }
 1691
 1692        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1693
 1694        let inlay_hint_settings =
 1695            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1696        let focus_handle = cx.focus_handle();
 1697        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1698            .detach();
 1699        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1700            .detach();
 1701        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1702            .detach();
 1703        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1704            .detach();
 1705
 1706        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1707            Some(false)
 1708        } else {
 1709            None
 1710        };
 1711
 1712        let breakpoint_store = match (&mode, project.as_ref()) {
 1713            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1714            _ => None,
 1715        };
 1716
 1717        let mut code_action_providers = Vec::new();
 1718        let mut load_uncommitted_diff = None;
 1719        if let Some(project) = project.clone() {
 1720            load_uncommitted_diff = Some(
 1721                update_uncommitted_diff_for_buffer(
 1722                    cx.entity(),
 1723                    &project,
 1724                    buffer.read(cx).all_buffers(),
 1725                    buffer.clone(),
 1726                    cx,
 1727                )
 1728                .shared(),
 1729            );
 1730            code_action_providers.push(Rc::new(project) as Rc<_>);
 1731        }
 1732
 1733        let mut this = Self {
 1734            focus_handle,
 1735            show_cursor_when_unfocused: false,
 1736            last_focused_descendant: None,
 1737            buffer: buffer.clone(),
 1738            display_map: display_map.clone(),
 1739            selections,
 1740            scroll_manager: ScrollManager::new(cx),
 1741            columnar_selection_tail: None,
 1742            add_selections_state: None,
 1743            select_next_state: None,
 1744            select_prev_state: None,
 1745            selection_history: SelectionHistory::default(),
 1746            autoclose_regions: Vec::new(),
 1747            snippet_stack: InvalidationStack::default(),
 1748            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1749            ime_transaction: None,
 1750            active_diagnostics: ActiveDiagnostic::None,
 1751            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1752            inline_diagnostics_update: Task::ready(()),
 1753            inline_diagnostics: Vec::new(),
 1754            soft_wrap_mode_override,
 1755            diagnostics_max_severity,
 1756            hard_wrap: None,
 1757            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1758            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1759            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1760            project,
 1761            blink_manager: blink_manager.clone(),
 1762            show_local_selections: true,
 1763            show_scrollbars: full_mode,
 1764            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1765            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1766            show_gutter: mode.is_full(),
 1767            show_line_numbers: None,
 1768            use_relative_line_numbers: None,
 1769            disable_expand_excerpt_buttons: false,
 1770            show_git_diff_gutter: None,
 1771            show_code_actions: None,
 1772            show_runnables: None,
 1773            show_breakpoints: None,
 1774            show_wrap_guides: None,
 1775            show_indent_guides,
 1776            placeholder_text: None,
 1777            highlight_order: 0,
 1778            highlighted_rows: HashMap::default(),
 1779            background_highlights: TreeMap::default(),
 1780            gutter_highlights: TreeMap::default(),
 1781            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1782            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1783            nav_history: None,
 1784            context_menu: RefCell::new(None),
 1785            context_menu_options: None,
 1786            mouse_context_menu: None,
 1787            completion_tasks: Vec::new(),
 1788            inline_blame_popover: None,
 1789            signature_help_state: SignatureHelpState::default(),
 1790            auto_signature_help: None,
 1791            find_all_references_task_sources: Vec::new(),
 1792            next_completion_id: 0,
 1793            next_inlay_id: 0,
 1794            code_action_providers,
 1795            available_code_actions: None,
 1796            code_actions_task: None,
 1797            quick_selection_highlight_task: None,
 1798            debounced_selection_highlight_task: None,
 1799            document_highlights_task: None,
 1800            linked_editing_range_task: None,
 1801            pending_rename: None,
 1802            searchable: true,
 1803            cursor_shape: EditorSettings::get_global(cx)
 1804                .cursor_shape
 1805                .unwrap_or_default(),
 1806            current_line_highlight: None,
 1807            autoindent_mode: Some(AutoindentMode::EachLine),
 1808            collapse_matches: false,
 1809            workspace: None,
 1810            input_enabled: true,
 1811            use_modal_editing: mode.is_full(),
 1812            read_only: mode.is_minimap(),
 1813            use_autoclose: true,
 1814            use_auto_surround: true,
 1815            auto_replace_emoji_shortcode: false,
 1816            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1817            leader_id: None,
 1818            remote_id: None,
 1819            hover_state: HoverState::default(),
 1820            pending_mouse_down: None,
 1821            hovered_link_state: None,
 1822            edit_prediction_provider: None,
 1823            active_inline_completion: None,
 1824            stale_inline_completion_in_menu: None,
 1825            edit_prediction_preview: EditPredictionPreview::Inactive {
 1826                released_too_fast: false,
 1827            },
 1828            inline_diagnostics_enabled: mode.is_full(),
 1829            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1830            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1831
 1832            gutter_hovered: false,
 1833            pixel_position_of_newest_cursor: None,
 1834            last_bounds: None,
 1835            last_position_map: None,
 1836            expect_bounds_change: None,
 1837            gutter_dimensions: GutterDimensions::default(),
 1838            style: None,
 1839            show_cursor_names: false,
 1840            hovered_cursors: HashMap::default(),
 1841            next_editor_action_id: EditorActionId::default(),
 1842            editor_actions: Rc::default(),
 1843            inline_completions_hidden_for_vim_mode: false,
 1844            show_inline_completions_override: None,
 1845            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1846            edit_prediction_settings: EditPredictionSettings::Disabled,
 1847            edit_prediction_indent_conflict: false,
 1848            edit_prediction_requires_modifier_in_indent_conflict: true,
 1849            custom_context_menu: None,
 1850            show_git_blame_gutter: false,
 1851            show_git_blame_inline: false,
 1852            show_selection_menu: None,
 1853            show_git_blame_inline_delay_task: None,
 1854            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1855            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1856            serialize_dirty_buffers: !mode.is_minimap()
 1857                && ProjectSettings::get_global(cx)
 1858                    .session
 1859                    .restore_unsaved_buffers,
 1860            blame: None,
 1861            blame_subscription: None,
 1862            tasks: BTreeMap::default(),
 1863
 1864            breakpoint_store,
 1865            gutter_breakpoint_indicator: (None, None),
 1866            _subscriptions: vec![
 1867                cx.observe(&buffer, Self::on_buffer_changed),
 1868                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1869                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1870                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1871                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1872                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1873                cx.observe_window_activation(window, |editor, window, cx| {
 1874                    let active = window.is_window_active();
 1875                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1876                        if active {
 1877                            blink_manager.enable(cx);
 1878                        } else {
 1879                            blink_manager.disable(cx);
 1880                        }
 1881                    });
 1882                }),
 1883            ],
 1884            tasks_update_task: None,
 1885            linked_edit_ranges: Default::default(),
 1886            in_project_search: false,
 1887            previous_search_ranges: None,
 1888            breadcrumb_header: None,
 1889            focused_block: None,
 1890            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1891            addons: HashMap::default(),
 1892            registered_buffers: HashMap::default(),
 1893            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1894            selection_mark_mode: false,
 1895            toggle_fold_multiple_buffers: Task::ready(()),
 1896            serialize_selections: Task::ready(()),
 1897            serialize_folds: Task::ready(()),
 1898            text_style_refinement: None,
 1899            load_diff_task: load_uncommitted_diff,
 1900            temporary_diff_override: false,
 1901            mouse_cursor_hidden: false,
 1902            minimap: None,
 1903            hide_mouse_mode: EditorSettings::get_global(cx)
 1904                .hide_mouse
 1905                .unwrap_or_default(),
 1906            change_list: ChangeList::new(),
 1907            mode,
 1908        };
 1909        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1910            this._subscriptions
 1911                .push(cx.observe(breakpoints, |_, _, cx| {
 1912                    cx.notify();
 1913                }));
 1914        }
 1915        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1916        this._subscriptions.extend(project_subscriptions);
 1917
 1918        this._subscriptions.push(cx.subscribe_in(
 1919            &cx.entity(),
 1920            window,
 1921            |editor, _, e: &EditorEvent, window, cx| match e {
 1922                EditorEvent::ScrollPositionChanged { local, .. } => {
 1923                    if *local {
 1924                        let new_anchor = editor.scroll_manager.anchor();
 1925                        let snapshot = editor.snapshot(window, cx);
 1926                        editor.update_restoration_data(cx, move |data| {
 1927                            data.scroll_position = (
 1928                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1929                                new_anchor.offset,
 1930                            );
 1931                        });
 1932                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1933                        editor.inline_blame_popover.take();
 1934                    }
 1935                }
 1936                EditorEvent::Edited { .. } => {
 1937                    if !vim_enabled(cx) {
 1938                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1939                        let pop_state = editor
 1940                            .change_list
 1941                            .last()
 1942                            .map(|previous| {
 1943                                previous.len() == selections.len()
 1944                                    && previous.iter().enumerate().all(|(ix, p)| {
 1945                                        p.to_display_point(&map).row()
 1946                                            == selections[ix].head().row()
 1947                                    })
 1948                            })
 1949                            .unwrap_or(false);
 1950                        let new_positions = selections
 1951                            .into_iter()
 1952                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1953                            .collect();
 1954                        editor
 1955                            .change_list
 1956                            .push_to_change_list(pop_state, new_positions);
 1957                    }
 1958                }
 1959                _ => (),
 1960            },
 1961        ));
 1962
 1963        if let Some(dap_store) = this
 1964            .project
 1965            .as_ref()
 1966            .map(|project| project.read(cx).dap_store())
 1967        {
 1968            let weak_editor = cx.weak_entity();
 1969
 1970            this._subscriptions
 1971                .push(
 1972                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1973                        let session_entity = cx.entity();
 1974                        weak_editor
 1975                            .update(cx, |editor, cx| {
 1976                                editor._subscriptions.push(
 1977                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1978                                );
 1979                            })
 1980                            .ok();
 1981                    }),
 1982                );
 1983
 1984            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1985                this._subscriptions
 1986                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1987            }
 1988        }
 1989
 1990        this.end_selection(window, cx);
 1991        this.scroll_manager.show_scrollbars(window, cx);
 1992        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1993
 1994        if full_mode {
 1995            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1996            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1997
 1998            if this.git_blame_inline_enabled {
 1999                this.start_git_blame_inline(false, window, cx);
 2000            }
 2001
 2002            this.go_to_active_debug_line(window, cx);
 2003
 2004            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2005                if let Some(project) = this.project.as_ref() {
 2006                    let handle = project.update(cx, |project, cx| {
 2007                        project.register_buffer_with_language_servers(&buffer, cx)
 2008                    });
 2009                    this.registered_buffers
 2010                        .insert(buffer.read(cx).remote_id(), handle);
 2011                }
 2012            }
 2013
 2014            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2015        }
 2016
 2017        this.report_editor_event("Editor Opened", None, cx);
 2018        this
 2019    }
 2020
 2021    pub fn deploy_mouse_context_menu(
 2022        &mut self,
 2023        position: gpui::Point<Pixels>,
 2024        context_menu: Entity<ContextMenu>,
 2025        window: &mut Window,
 2026        cx: &mut Context<Self>,
 2027    ) {
 2028        self.mouse_context_menu = Some(MouseContextMenu::new(
 2029            self,
 2030            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2031            context_menu,
 2032            window,
 2033            cx,
 2034        ));
 2035    }
 2036
 2037    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2038        self.mouse_context_menu
 2039            .as_ref()
 2040            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2041    }
 2042
 2043    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2044        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2045    }
 2046
 2047    fn key_context_internal(
 2048        &self,
 2049        has_active_edit_prediction: bool,
 2050        window: &Window,
 2051        cx: &App,
 2052    ) -> KeyContext {
 2053        let mut key_context = KeyContext::new_with_defaults();
 2054        key_context.add("Editor");
 2055        let mode = match self.mode {
 2056            EditorMode::SingleLine { .. } => "single_line",
 2057            EditorMode::AutoHeight { .. } => "auto_height",
 2058            EditorMode::Minimap { .. } => "minimap",
 2059            EditorMode::Full { .. } => "full",
 2060        };
 2061
 2062        if EditorSettings::jupyter_enabled(cx) {
 2063            key_context.add("jupyter");
 2064        }
 2065
 2066        key_context.set("mode", mode);
 2067        if self.pending_rename.is_some() {
 2068            key_context.add("renaming");
 2069        }
 2070
 2071        match self.context_menu.borrow().as_ref() {
 2072            Some(CodeContextMenu::Completions(_)) => {
 2073                key_context.add("menu");
 2074                key_context.add("showing_completions");
 2075            }
 2076            Some(CodeContextMenu::CodeActions(_)) => {
 2077                key_context.add("menu");
 2078                key_context.add("showing_code_actions")
 2079            }
 2080            None => {}
 2081        }
 2082
 2083        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2084        if !self.focus_handle(cx).contains_focused(window, cx)
 2085            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2086        {
 2087            for addon in self.addons.values() {
 2088                addon.extend_key_context(&mut key_context, cx)
 2089            }
 2090        }
 2091
 2092        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2093            if let Some(extension) = singleton_buffer
 2094                .read(cx)
 2095                .file()
 2096                .and_then(|file| file.path().extension()?.to_str())
 2097            {
 2098                key_context.set("extension", extension.to_string());
 2099            }
 2100        } else {
 2101            key_context.add("multibuffer");
 2102        }
 2103
 2104        if has_active_edit_prediction {
 2105            if self.edit_prediction_in_conflict() {
 2106                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2107            } else {
 2108                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2109                key_context.add("copilot_suggestion");
 2110            }
 2111        }
 2112
 2113        if self.selection_mark_mode {
 2114            key_context.add("selection_mode");
 2115        }
 2116
 2117        key_context
 2118    }
 2119
 2120    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2121        self.mouse_cursor_hidden = match origin {
 2122            HideMouseCursorOrigin::TypingAction => {
 2123                matches!(
 2124                    self.hide_mouse_mode,
 2125                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2126                )
 2127            }
 2128            HideMouseCursorOrigin::MovementAction => {
 2129                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2130            }
 2131        };
 2132    }
 2133
 2134    pub fn edit_prediction_in_conflict(&self) -> bool {
 2135        if !self.show_edit_predictions_in_menu() {
 2136            return false;
 2137        }
 2138
 2139        let showing_completions = self
 2140            .context_menu
 2141            .borrow()
 2142            .as_ref()
 2143            .map_or(false, |context| {
 2144                matches!(context, CodeContextMenu::Completions(_))
 2145            });
 2146
 2147        showing_completions
 2148            || self.edit_prediction_requires_modifier()
 2149            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2150            // bindings to insert tab characters.
 2151            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2152    }
 2153
 2154    pub fn accept_edit_prediction_keybind(
 2155        &self,
 2156        window: &Window,
 2157        cx: &App,
 2158    ) -> AcceptEditPredictionBinding {
 2159        let key_context = self.key_context_internal(true, window, cx);
 2160        let in_conflict = self.edit_prediction_in_conflict();
 2161
 2162        AcceptEditPredictionBinding(
 2163            window
 2164                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2165                .into_iter()
 2166                .filter(|binding| {
 2167                    !in_conflict
 2168                        || binding
 2169                            .keystrokes()
 2170                            .first()
 2171                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2172                })
 2173                .rev()
 2174                .min_by_key(|binding| {
 2175                    binding
 2176                        .keystrokes()
 2177                        .first()
 2178                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2179                }),
 2180        )
 2181    }
 2182
 2183    pub fn new_file(
 2184        workspace: &mut Workspace,
 2185        _: &workspace::NewFile,
 2186        window: &mut Window,
 2187        cx: &mut Context<Workspace>,
 2188    ) {
 2189        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2190            "Failed to create buffer",
 2191            window,
 2192            cx,
 2193            |e, _, _| match e.error_code() {
 2194                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2195                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2196                e.error_tag("required").unwrap_or("the latest version")
 2197            )),
 2198                _ => None,
 2199            },
 2200        );
 2201    }
 2202
 2203    pub fn new_in_workspace(
 2204        workspace: &mut Workspace,
 2205        window: &mut Window,
 2206        cx: &mut Context<Workspace>,
 2207    ) -> Task<Result<Entity<Editor>>> {
 2208        let project = workspace.project().clone();
 2209        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2210
 2211        cx.spawn_in(window, async move |workspace, cx| {
 2212            let buffer = create.await?;
 2213            workspace.update_in(cx, |workspace, window, cx| {
 2214                let editor =
 2215                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2216                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2217                editor
 2218            })
 2219        })
 2220    }
 2221
 2222    fn new_file_vertical(
 2223        workspace: &mut Workspace,
 2224        _: &workspace::NewFileSplitVertical,
 2225        window: &mut Window,
 2226        cx: &mut Context<Workspace>,
 2227    ) {
 2228        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2229    }
 2230
 2231    fn new_file_horizontal(
 2232        workspace: &mut Workspace,
 2233        _: &workspace::NewFileSplitHorizontal,
 2234        window: &mut Window,
 2235        cx: &mut Context<Workspace>,
 2236    ) {
 2237        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2238    }
 2239
 2240    fn new_file_in_direction(
 2241        workspace: &mut Workspace,
 2242        direction: SplitDirection,
 2243        window: &mut Window,
 2244        cx: &mut Context<Workspace>,
 2245    ) {
 2246        let project = workspace.project().clone();
 2247        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2248
 2249        cx.spawn_in(window, async move |workspace, cx| {
 2250            let buffer = create.await?;
 2251            workspace.update_in(cx, move |workspace, window, cx| {
 2252                workspace.split_item(
 2253                    direction,
 2254                    Box::new(
 2255                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2256                    ),
 2257                    window,
 2258                    cx,
 2259                )
 2260            })?;
 2261            anyhow::Ok(())
 2262        })
 2263        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2264            match e.error_code() {
 2265                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2266                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2267                e.error_tag("required").unwrap_or("the latest version")
 2268            )),
 2269                _ => None,
 2270            }
 2271        });
 2272    }
 2273
 2274    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2275        self.leader_id
 2276    }
 2277
 2278    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2279        &self.buffer
 2280    }
 2281
 2282    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2283        self.workspace.as_ref()?.0.upgrade()
 2284    }
 2285
 2286    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2287        self.buffer().read(cx).title(cx)
 2288    }
 2289
 2290    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2291        let git_blame_gutter_max_author_length = self
 2292            .render_git_blame_gutter(cx)
 2293            .then(|| {
 2294                if let Some(blame) = self.blame.as_ref() {
 2295                    let max_author_length =
 2296                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2297                    Some(max_author_length)
 2298                } else {
 2299                    None
 2300                }
 2301            })
 2302            .flatten();
 2303
 2304        EditorSnapshot {
 2305            mode: self.mode.clone(),
 2306            show_gutter: self.show_gutter,
 2307            show_line_numbers: self.show_line_numbers,
 2308            show_git_diff_gutter: self.show_git_diff_gutter,
 2309            show_runnables: self.show_runnables,
 2310            show_breakpoints: self.show_breakpoints,
 2311            git_blame_gutter_max_author_length,
 2312            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2313            scroll_anchor: self.scroll_manager.anchor(),
 2314            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2315            placeholder_text: self.placeholder_text.clone(),
 2316            is_focused: self.focus_handle.is_focused(window),
 2317            current_line_highlight: self
 2318                .current_line_highlight
 2319                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2320            gutter_hovered: self.gutter_hovered,
 2321        }
 2322    }
 2323
 2324    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2325        self.buffer.read(cx).language_at(point, cx)
 2326    }
 2327
 2328    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2329        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2330    }
 2331
 2332    pub fn active_excerpt(
 2333        &self,
 2334        cx: &App,
 2335    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2336        self.buffer
 2337            .read(cx)
 2338            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2339    }
 2340
 2341    pub fn mode(&self) -> &EditorMode {
 2342        &self.mode
 2343    }
 2344
 2345    pub fn set_mode(&mut self, mode: EditorMode) {
 2346        self.mode = mode;
 2347    }
 2348
 2349    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2350        self.collaboration_hub.as_deref()
 2351    }
 2352
 2353    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2354        self.collaboration_hub = Some(hub);
 2355    }
 2356
 2357    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2358        self.in_project_search = in_project_search;
 2359    }
 2360
 2361    pub fn set_custom_context_menu(
 2362        &mut self,
 2363        f: impl 'static
 2364        + Fn(
 2365            &mut Self,
 2366            DisplayPoint,
 2367            &mut Window,
 2368            &mut Context<Self>,
 2369        ) -> Option<Entity<ui::ContextMenu>>,
 2370    ) {
 2371        self.custom_context_menu = Some(Box::new(f))
 2372    }
 2373
 2374    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2375        self.completion_provider = provider;
 2376    }
 2377
 2378    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2379        self.semantics_provider.clone()
 2380    }
 2381
 2382    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2383        self.semantics_provider = provider;
 2384    }
 2385
 2386    pub fn set_edit_prediction_provider<T>(
 2387        &mut self,
 2388        provider: Option<Entity<T>>,
 2389        window: &mut Window,
 2390        cx: &mut Context<Self>,
 2391    ) where
 2392        T: EditPredictionProvider,
 2393    {
 2394        self.edit_prediction_provider =
 2395            provider.map(|provider| RegisteredInlineCompletionProvider {
 2396                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2397                    if this.focus_handle.is_focused(window) {
 2398                        this.update_visible_inline_completion(window, cx);
 2399                    }
 2400                }),
 2401                provider: Arc::new(provider),
 2402            });
 2403        self.update_edit_prediction_settings(cx);
 2404        self.refresh_inline_completion(false, false, window, cx);
 2405    }
 2406
 2407    pub fn placeholder_text(&self) -> Option<&str> {
 2408        self.placeholder_text.as_deref()
 2409    }
 2410
 2411    pub fn set_placeholder_text(
 2412        &mut self,
 2413        placeholder_text: impl Into<Arc<str>>,
 2414        cx: &mut Context<Self>,
 2415    ) {
 2416        let placeholder_text = Some(placeholder_text.into());
 2417        if self.placeholder_text != placeholder_text {
 2418            self.placeholder_text = placeholder_text;
 2419            cx.notify();
 2420        }
 2421    }
 2422
 2423    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2424        self.cursor_shape = cursor_shape;
 2425
 2426        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2427        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2428
 2429        cx.notify();
 2430    }
 2431
 2432    pub fn set_current_line_highlight(
 2433        &mut self,
 2434        current_line_highlight: Option<CurrentLineHighlight>,
 2435    ) {
 2436        self.current_line_highlight = current_line_highlight;
 2437    }
 2438
 2439    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2440        self.collapse_matches = collapse_matches;
 2441    }
 2442
 2443    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2444        let buffers = self.buffer.read(cx).all_buffers();
 2445        let Some(project) = self.project.as_ref() else {
 2446            return;
 2447        };
 2448        project.update(cx, |project, cx| {
 2449            for buffer in buffers {
 2450                self.registered_buffers
 2451                    .entry(buffer.read(cx).remote_id())
 2452                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2453            }
 2454        })
 2455    }
 2456
 2457    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2458        if self.collapse_matches {
 2459            return range.start..range.start;
 2460        }
 2461        range.clone()
 2462    }
 2463
 2464    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2465        if self.display_map.read(cx).clip_at_line_ends != clip {
 2466            self.display_map
 2467                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2468        }
 2469    }
 2470
 2471    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2472        self.input_enabled = input_enabled;
 2473    }
 2474
 2475    pub fn set_inline_completions_hidden_for_vim_mode(
 2476        &mut self,
 2477        hidden: bool,
 2478        window: &mut Window,
 2479        cx: &mut Context<Self>,
 2480    ) {
 2481        if hidden != self.inline_completions_hidden_for_vim_mode {
 2482            self.inline_completions_hidden_for_vim_mode = hidden;
 2483            if hidden {
 2484                self.update_visible_inline_completion(window, cx);
 2485            } else {
 2486                self.refresh_inline_completion(true, false, window, cx);
 2487            }
 2488        }
 2489    }
 2490
 2491    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2492        self.menu_inline_completions_policy = value;
 2493    }
 2494
 2495    pub fn set_autoindent(&mut self, autoindent: bool) {
 2496        if autoindent {
 2497            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2498        } else {
 2499            self.autoindent_mode = None;
 2500        }
 2501    }
 2502
 2503    pub fn read_only(&self, cx: &App) -> bool {
 2504        self.read_only || self.buffer.read(cx).read_only()
 2505    }
 2506
 2507    pub fn set_read_only(&mut self, read_only: bool) {
 2508        self.read_only = read_only;
 2509    }
 2510
 2511    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2512        self.use_autoclose = autoclose;
 2513    }
 2514
 2515    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2516        self.use_auto_surround = auto_surround;
 2517    }
 2518
 2519    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2520        self.auto_replace_emoji_shortcode = auto_replace;
 2521    }
 2522
 2523    pub fn toggle_edit_predictions(
 2524        &mut self,
 2525        _: &ToggleEditPrediction,
 2526        window: &mut Window,
 2527        cx: &mut Context<Self>,
 2528    ) {
 2529        if self.show_inline_completions_override.is_some() {
 2530            self.set_show_edit_predictions(None, window, cx);
 2531        } else {
 2532            let show_edit_predictions = !self.edit_predictions_enabled();
 2533            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2534        }
 2535    }
 2536
 2537    pub fn set_show_edit_predictions(
 2538        &mut self,
 2539        show_edit_predictions: Option<bool>,
 2540        window: &mut Window,
 2541        cx: &mut Context<Self>,
 2542    ) {
 2543        self.show_inline_completions_override = show_edit_predictions;
 2544        self.update_edit_prediction_settings(cx);
 2545
 2546        if let Some(false) = show_edit_predictions {
 2547            self.discard_inline_completion(false, cx);
 2548        } else {
 2549            self.refresh_inline_completion(false, true, window, cx);
 2550        }
 2551    }
 2552
 2553    fn inline_completions_disabled_in_scope(
 2554        &self,
 2555        buffer: &Entity<Buffer>,
 2556        buffer_position: language::Anchor,
 2557        cx: &App,
 2558    ) -> bool {
 2559        let snapshot = buffer.read(cx).snapshot();
 2560        let settings = snapshot.settings_at(buffer_position, cx);
 2561
 2562        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2563            return false;
 2564        };
 2565
 2566        scope.override_name().map_or(false, |scope_name| {
 2567            settings
 2568                .edit_predictions_disabled_in
 2569                .iter()
 2570                .any(|s| s == scope_name)
 2571        })
 2572    }
 2573
 2574    pub fn set_use_modal_editing(&mut self, to: bool) {
 2575        self.use_modal_editing = to;
 2576    }
 2577
 2578    pub fn use_modal_editing(&self) -> bool {
 2579        self.use_modal_editing
 2580    }
 2581
 2582    fn selections_did_change(
 2583        &mut self,
 2584        local: bool,
 2585        old_cursor_position: &Anchor,
 2586        show_completions: bool,
 2587        window: &mut Window,
 2588        cx: &mut Context<Self>,
 2589    ) {
 2590        window.invalidate_character_coordinates();
 2591
 2592        // Copy selections to primary selection buffer
 2593        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2594        if local {
 2595            let selections = self.selections.all::<usize>(cx);
 2596            let buffer_handle = self.buffer.read(cx).read(cx);
 2597
 2598            let mut text = String::new();
 2599            for (index, selection) in selections.iter().enumerate() {
 2600                let text_for_selection = buffer_handle
 2601                    .text_for_range(selection.start..selection.end)
 2602                    .collect::<String>();
 2603
 2604                text.push_str(&text_for_selection);
 2605                if index != selections.len() - 1 {
 2606                    text.push('\n');
 2607                }
 2608            }
 2609
 2610            if !text.is_empty() {
 2611                cx.write_to_primary(ClipboardItem::new_string(text));
 2612            }
 2613        }
 2614
 2615        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2616            self.buffer.update(cx, |buffer, cx| {
 2617                buffer.set_active_selections(
 2618                    &self.selections.disjoint_anchors(),
 2619                    self.selections.line_mode,
 2620                    self.cursor_shape,
 2621                    cx,
 2622                )
 2623            });
 2624        }
 2625        let display_map = self
 2626            .display_map
 2627            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2628        let buffer = &display_map.buffer_snapshot;
 2629        self.add_selections_state = None;
 2630        self.select_next_state = None;
 2631        self.select_prev_state = None;
 2632        self.select_syntax_node_history.try_clear();
 2633        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2634        self.snippet_stack
 2635            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2636        self.take_rename(false, window, cx);
 2637
 2638        let new_cursor_position = self.selections.newest_anchor().head();
 2639
 2640        self.push_to_nav_history(
 2641            *old_cursor_position,
 2642            Some(new_cursor_position.to_point(buffer)),
 2643            false,
 2644            cx,
 2645        );
 2646
 2647        if local {
 2648            let new_cursor_position = self.selections.newest_anchor().head();
 2649            let mut context_menu = self.context_menu.borrow_mut();
 2650            let completion_menu = match context_menu.as_ref() {
 2651                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2652                _ => {
 2653                    *context_menu = None;
 2654                    None
 2655                }
 2656            };
 2657            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2658                if !self.registered_buffers.contains_key(&buffer_id) {
 2659                    if let Some(project) = self.project.as_ref() {
 2660                        project.update(cx, |project, cx| {
 2661                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2662                                return;
 2663                            };
 2664                            self.registered_buffers.insert(
 2665                                buffer_id,
 2666                                project.register_buffer_with_language_servers(&buffer, cx),
 2667                            );
 2668                        })
 2669                    }
 2670                }
 2671            }
 2672
 2673            if let Some(completion_menu) = completion_menu {
 2674                let cursor_position = new_cursor_position.to_offset(buffer);
 2675                let (word_range, kind) =
 2676                    buffer.surrounding_word(completion_menu.initial_position, true);
 2677                if kind == Some(CharKind::Word)
 2678                    && word_range.to_inclusive().contains(&cursor_position)
 2679                {
 2680                    let mut completion_menu = completion_menu.clone();
 2681                    drop(context_menu);
 2682
 2683                    let query = Self::completion_query(buffer, cursor_position);
 2684                    cx.spawn(async move |this, cx| {
 2685                        completion_menu
 2686                            .filter(query.as_deref(), cx.background_executor().clone())
 2687                            .await;
 2688
 2689                        this.update(cx, |this, cx| {
 2690                            let mut context_menu = this.context_menu.borrow_mut();
 2691                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2692                            else {
 2693                                return;
 2694                            };
 2695
 2696                            if menu.id > completion_menu.id {
 2697                                return;
 2698                            }
 2699
 2700                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2701                            drop(context_menu);
 2702                            cx.notify();
 2703                        })
 2704                    })
 2705                    .detach();
 2706
 2707                    if show_completions {
 2708                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2709                    }
 2710                } else {
 2711                    drop(context_menu);
 2712                    self.hide_context_menu(window, cx);
 2713                }
 2714            } else {
 2715                drop(context_menu);
 2716            }
 2717
 2718            hide_hover(self, cx);
 2719
 2720            if old_cursor_position.to_display_point(&display_map).row()
 2721                != new_cursor_position.to_display_point(&display_map).row()
 2722            {
 2723                self.available_code_actions.take();
 2724            }
 2725            self.refresh_code_actions(window, cx);
 2726            self.refresh_document_highlights(cx);
 2727            self.refresh_selected_text_highlights(false, window, cx);
 2728            refresh_matching_bracket_highlights(self, window, cx);
 2729            self.update_visible_inline_completion(window, cx);
 2730            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2731            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2732            self.inline_blame_popover.take();
 2733            if self.git_blame_inline_enabled {
 2734                self.start_inline_blame_timer(window, cx);
 2735            }
 2736        }
 2737
 2738        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2739        cx.emit(EditorEvent::SelectionsChanged { local });
 2740
 2741        let selections = &self.selections.disjoint;
 2742        if selections.len() == 1 {
 2743            cx.emit(SearchEvent::ActiveMatchChanged)
 2744        }
 2745        if local {
 2746            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2747                let inmemory_selections = selections
 2748                    .iter()
 2749                    .map(|s| {
 2750                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2751                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2752                    })
 2753                    .collect();
 2754                self.update_restoration_data(cx, |data| {
 2755                    data.selections = inmemory_selections;
 2756                });
 2757
 2758                if WorkspaceSettings::get(None, cx).restore_on_startup
 2759                    != RestoreOnStartupBehavior::None
 2760                {
 2761                    if let Some(workspace_id) =
 2762                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2763                    {
 2764                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2765                        let selections = selections.clone();
 2766                        let background_executor = cx.background_executor().clone();
 2767                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2768                        self.serialize_selections = cx.background_spawn(async move {
 2769                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2770                    let db_selections = selections
 2771                        .iter()
 2772                        .map(|selection| {
 2773                            (
 2774                                selection.start.to_offset(&snapshot),
 2775                                selection.end.to_offset(&snapshot),
 2776                            )
 2777                        })
 2778                        .collect();
 2779
 2780                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2781                        .await
 2782                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2783                        .log_err();
 2784                });
 2785                    }
 2786                }
 2787            }
 2788        }
 2789
 2790        cx.notify();
 2791    }
 2792
 2793    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2794        use text::ToOffset as _;
 2795        use text::ToPoint as _;
 2796
 2797        if self.mode.is_minimap()
 2798            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2799        {
 2800            return;
 2801        }
 2802
 2803        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2804            return;
 2805        };
 2806
 2807        let snapshot = singleton.read(cx).snapshot();
 2808        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2809            let display_snapshot = display_map.snapshot(cx);
 2810
 2811            display_snapshot
 2812                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2813                .map(|fold| {
 2814                    fold.range.start.text_anchor.to_point(&snapshot)
 2815                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2816                })
 2817                .collect()
 2818        });
 2819        self.update_restoration_data(cx, |data| {
 2820            data.folds = inmemory_folds;
 2821        });
 2822
 2823        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2824            return;
 2825        };
 2826        let background_executor = cx.background_executor().clone();
 2827        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2828        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2829            display_map
 2830                .snapshot(cx)
 2831                .folds_in_range(0..snapshot.len())
 2832                .map(|fold| {
 2833                    (
 2834                        fold.range.start.text_anchor.to_offset(&snapshot),
 2835                        fold.range.end.text_anchor.to_offset(&snapshot),
 2836                    )
 2837                })
 2838                .collect()
 2839        });
 2840        self.serialize_folds = cx.background_spawn(async move {
 2841            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2842            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2843                .await
 2844                .with_context(|| {
 2845                    format!(
 2846                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2847                    )
 2848                })
 2849                .log_err();
 2850        });
 2851    }
 2852
 2853    pub fn sync_selections(
 2854        &mut self,
 2855        other: Entity<Editor>,
 2856        cx: &mut Context<Self>,
 2857    ) -> gpui::Subscription {
 2858        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2859        self.selections.change_with(cx, |selections| {
 2860            selections.select_anchors(other_selections);
 2861        });
 2862
 2863        let other_subscription =
 2864            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2865                EditorEvent::SelectionsChanged { local: true } => {
 2866                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2867                    if other_selections.is_empty() {
 2868                        return;
 2869                    }
 2870                    this.selections.change_with(cx, |selections| {
 2871                        selections.select_anchors(other_selections);
 2872                    });
 2873                }
 2874                _ => {}
 2875            });
 2876
 2877        let this_subscription =
 2878            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2879                EditorEvent::SelectionsChanged { local: true } => {
 2880                    let these_selections = this.selections.disjoint.to_vec();
 2881                    if these_selections.is_empty() {
 2882                        return;
 2883                    }
 2884                    other.update(cx, |other_editor, cx| {
 2885                        other_editor.selections.change_with(cx, |selections| {
 2886                            selections.select_anchors(these_selections);
 2887                        })
 2888                    });
 2889                }
 2890                _ => {}
 2891            });
 2892
 2893        Subscription::join(other_subscription, this_subscription)
 2894    }
 2895
 2896    pub fn change_selections<R>(
 2897        &mut self,
 2898        autoscroll: Option<Autoscroll>,
 2899        window: &mut Window,
 2900        cx: &mut Context<Self>,
 2901        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2902    ) -> R {
 2903        self.change_selections_inner(autoscroll, true, window, cx, change)
 2904    }
 2905
 2906    fn change_selections_inner<R>(
 2907        &mut self,
 2908        autoscroll: Option<Autoscroll>,
 2909        request_completions: bool,
 2910        window: &mut Window,
 2911        cx: &mut Context<Self>,
 2912        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2913    ) -> R {
 2914        let old_cursor_position = self.selections.newest_anchor().head();
 2915        self.push_to_selection_history();
 2916
 2917        let (changed, result) = self.selections.change_with(cx, change);
 2918
 2919        if changed {
 2920            if let Some(autoscroll) = autoscroll {
 2921                self.request_autoscroll(autoscroll, cx);
 2922            }
 2923            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2924
 2925            if self.should_open_signature_help_automatically(
 2926                &old_cursor_position,
 2927                self.signature_help_state.backspace_pressed(),
 2928                cx,
 2929            ) {
 2930                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2931            }
 2932            self.signature_help_state.set_backspace_pressed(false);
 2933        }
 2934
 2935        result
 2936    }
 2937
 2938    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2939    where
 2940        I: IntoIterator<Item = (Range<S>, T)>,
 2941        S: ToOffset,
 2942        T: Into<Arc<str>>,
 2943    {
 2944        if self.read_only(cx) {
 2945            return;
 2946        }
 2947
 2948        self.buffer
 2949            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2950    }
 2951
 2952    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2953    where
 2954        I: IntoIterator<Item = (Range<S>, T)>,
 2955        S: ToOffset,
 2956        T: Into<Arc<str>>,
 2957    {
 2958        if self.read_only(cx) {
 2959            return;
 2960        }
 2961
 2962        self.buffer.update(cx, |buffer, cx| {
 2963            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2964        });
 2965    }
 2966
 2967    pub fn edit_with_block_indent<I, S, T>(
 2968        &mut self,
 2969        edits: I,
 2970        original_indent_columns: Vec<Option<u32>>,
 2971        cx: &mut Context<Self>,
 2972    ) where
 2973        I: IntoIterator<Item = (Range<S>, T)>,
 2974        S: ToOffset,
 2975        T: Into<Arc<str>>,
 2976    {
 2977        if self.read_only(cx) {
 2978            return;
 2979        }
 2980
 2981        self.buffer.update(cx, |buffer, cx| {
 2982            buffer.edit(
 2983                edits,
 2984                Some(AutoindentMode::Block {
 2985                    original_indent_columns,
 2986                }),
 2987                cx,
 2988            )
 2989        });
 2990    }
 2991
 2992    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2993        self.hide_context_menu(window, cx);
 2994
 2995        match phase {
 2996            SelectPhase::Begin {
 2997                position,
 2998                add,
 2999                click_count,
 3000            } => self.begin_selection(position, add, click_count, window, cx),
 3001            SelectPhase::BeginColumnar {
 3002                position,
 3003                goal_column,
 3004                reset,
 3005            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3006            SelectPhase::Extend {
 3007                position,
 3008                click_count,
 3009            } => self.extend_selection(position, click_count, window, cx),
 3010            SelectPhase::Update {
 3011                position,
 3012                goal_column,
 3013                scroll_delta,
 3014            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3015            SelectPhase::End => self.end_selection(window, cx),
 3016        }
 3017    }
 3018
 3019    fn extend_selection(
 3020        &mut self,
 3021        position: DisplayPoint,
 3022        click_count: usize,
 3023        window: &mut Window,
 3024        cx: &mut Context<Self>,
 3025    ) {
 3026        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3027        let tail = self.selections.newest::<usize>(cx).tail();
 3028        self.begin_selection(position, false, click_count, window, cx);
 3029
 3030        let position = position.to_offset(&display_map, Bias::Left);
 3031        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3032
 3033        let mut pending_selection = self
 3034            .selections
 3035            .pending_anchor()
 3036            .expect("extend_selection not called with pending selection");
 3037        if position >= tail {
 3038            pending_selection.start = tail_anchor;
 3039        } else {
 3040            pending_selection.end = tail_anchor;
 3041            pending_selection.reversed = true;
 3042        }
 3043
 3044        let mut pending_mode = self.selections.pending_mode().unwrap();
 3045        match &mut pending_mode {
 3046            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3047            _ => {}
 3048        }
 3049
 3050        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3051
 3052        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3053            s.set_pending(pending_selection, pending_mode)
 3054        });
 3055    }
 3056
 3057    fn begin_selection(
 3058        &mut self,
 3059        position: DisplayPoint,
 3060        add: bool,
 3061        click_count: usize,
 3062        window: &mut Window,
 3063        cx: &mut Context<Self>,
 3064    ) {
 3065        if !self.focus_handle.is_focused(window) {
 3066            self.last_focused_descendant = None;
 3067            window.focus(&self.focus_handle);
 3068        }
 3069
 3070        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3071        let buffer = &display_map.buffer_snapshot;
 3072        let position = display_map.clip_point(position, Bias::Left);
 3073
 3074        let start;
 3075        let end;
 3076        let mode;
 3077        let mut auto_scroll;
 3078        match click_count {
 3079            1 => {
 3080                start = buffer.anchor_before(position.to_point(&display_map));
 3081                end = start;
 3082                mode = SelectMode::Character;
 3083                auto_scroll = true;
 3084            }
 3085            2 => {
 3086                let range = movement::surrounding_word(&display_map, position);
 3087                start = buffer.anchor_before(range.start.to_point(&display_map));
 3088                end = buffer.anchor_before(range.end.to_point(&display_map));
 3089                mode = SelectMode::Word(start..end);
 3090                auto_scroll = true;
 3091            }
 3092            3 => {
 3093                let position = display_map
 3094                    .clip_point(position, Bias::Left)
 3095                    .to_point(&display_map);
 3096                let line_start = display_map.prev_line_boundary(position).0;
 3097                let next_line_start = buffer.clip_point(
 3098                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3099                    Bias::Left,
 3100                );
 3101                start = buffer.anchor_before(line_start);
 3102                end = buffer.anchor_before(next_line_start);
 3103                mode = SelectMode::Line(start..end);
 3104                auto_scroll = true;
 3105            }
 3106            _ => {
 3107                start = buffer.anchor_before(0);
 3108                end = buffer.anchor_before(buffer.len());
 3109                mode = SelectMode::All;
 3110                auto_scroll = false;
 3111            }
 3112        }
 3113        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3114
 3115        let point_to_delete: Option<usize> = {
 3116            let selected_points: Vec<Selection<Point>> =
 3117                self.selections.disjoint_in_range(start..end, cx);
 3118
 3119            if !add || click_count > 1 {
 3120                None
 3121            } else if !selected_points.is_empty() {
 3122                Some(selected_points[0].id)
 3123            } else {
 3124                let clicked_point_already_selected =
 3125                    self.selections.disjoint.iter().find(|selection| {
 3126                        selection.start.to_point(buffer) == start.to_point(buffer)
 3127                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3128                    });
 3129
 3130                clicked_point_already_selected.map(|selection| selection.id)
 3131            }
 3132        };
 3133
 3134        let selections_count = self.selections.count();
 3135
 3136        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3137            if let Some(point_to_delete) = point_to_delete {
 3138                s.delete(point_to_delete);
 3139
 3140                if selections_count == 1 {
 3141                    s.set_pending_anchor_range(start..end, mode);
 3142                }
 3143            } else {
 3144                if !add {
 3145                    s.clear_disjoint();
 3146                }
 3147
 3148                s.set_pending_anchor_range(start..end, mode);
 3149            }
 3150        });
 3151    }
 3152
 3153    fn begin_columnar_selection(
 3154        &mut self,
 3155        position: DisplayPoint,
 3156        goal_column: u32,
 3157        reset: bool,
 3158        window: &mut Window,
 3159        cx: &mut Context<Self>,
 3160    ) {
 3161        if !self.focus_handle.is_focused(window) {
 3162            self.last_focused_descendant = None;
 3163            window.focus(&self.focus_handle);
 3164        }
 3165
 3166        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3167
 3168        if reset {
 3169            let pointer_position = display_map
 3170                .buffer_snapshot
 3171                .anchor_before(position.to_point(&display_map));
 3172
 3173            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3174                s.clear_disjoint();
 3175                s.set_pending_anchor_range(
 3176                    pointer_position..pointer_position,
 3177                    SelectMode::Character,
 3178                );
 3179            });
 3180        }
 3181
 3182        let tail = self.selections.newest::<Point>(cx).tail();
 3183        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3184
 3185        if !reset {
 3186            self.select_columns(
 3187                tail.to_display_point(&display_map),
 3188                position,
 3189                goal_column,
 3190                &display_map,
 3191                window,
 3192                cx,
 3193            );
 3194        }
 3195    }
 3196
 3197    fn update_selection(
 3198        &mut self,
 3199        position: DisplayPoint,
 3200        goal_column: u32,
 3201        scroll_delta: gpui::Point<f32>,
 3202        window: &mut Window,
 3203        cx: &mut Context<Self>,
 3204    ) {
 3205        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3206
 3207        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3208            let tail = tail.to_display_point(&display_map);
 3209            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3210        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3211            let buffer = self.buffer.read(cx).snapshot(cx);
 3212            let head;
 3213            let tail;
 3214            let mode = self.selections.pending_mode().unwrap();
 3215            match &mode {
 3216                SelectMode::Character => {
 3217                    head = position.to_point(&display_map);
 3218                    tail = pending.tail().to_point(&buffer);
 3219                }
 3220                SelectMode::Word(original_range) => {
 3221                    let original_display_range = original_range.start.to_display_point(&display_map)
 3222                        ..original_range.end.to_display_point(&display_map);
 3223                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3224                        ..original_display_range.end.to_point(&display_map);
 3225                    if movement::is_inside_word(&display_map, position)
 3226                        || original_display_range.contains(&position)
 3227                    {
 3228                        let word_range = movement::surrounding_word(&display_map, position);
 3229                        if word_range.start < original_display_range.start {
 3230                            head = word_range.start.to_point(&display_map);
 3231                        } else {
 3232                            head = word_range.end.to_point(&display_map);
 3233                        }
 3234                    } else {
 3235                        head = position.to_point(&display_map);
 3236                    }
 3237
 3238                    if head <= original_buffer_range.start {
 3239                        tail = original_buffer_range.end;
 3240                    } else {
 3241                        tail = original_buffer_range.start;
 3242                    }
 3243                }
 3244                SelectMode::Line(original_range) => {
 3245                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3246
 3247                    let position = display_map
 3248                        .clip_point(position, Bias::Left)
 3249                        .to_point(&display_map);
 3250                    let line_start = display_map.prev_line_boundary(position).0;
 3251                    let next_line_start = buffer.clip_point(
 3252                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3253                        Bias::Left,
 3254                    );
 3255
 3256                    if line_start < original_range.start {
 3257                        head = line_start
 3258                    } else {
 3259                        head = next_line_start
 3260                    }
 3261
 3262                    if head <= original_range.start {
 3263                        tail = original_range.end;
 3264                    } else {
 3265                        tail = original_range.start;
 3266                    }
 3267                }
 3268                SelectMode::All => {
 3269                    return;
 3270                }
 3271            };
 3272
 3273            if head < tail {
 3274                pending.start = buffer.anchor_before(head);
 3275                pending.end = buffer.anchor_before(tail);
 3276                pending.reversed = true;
 3277            } else {
 3278                pending.start = buffer.anchor_before(tail);
 3279                pending.end = buffer.anchor_before(head);
 3280                pending.reversed = false;
 3281            }
 3282
 3283            self.change_selections(None, window, cx, |s| {
 3284                s.set_pending(pending, mode);
 3285            });
 3286        } else {
 3287            log::error!("update_selection dispatched with no pending selection");
 3288            return;
 3289        }
 3290
 3291        self.apply_scroll_delta(scroll_delta, window, cx);
 3292        cx.notify();
 3293    }
 3294
 3295    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3296        self.columnar_selection_tail.take();
 3297        if self.selections.pending_anchor().is_some() {
 3298            let selections = self.selections.all::<usize>(cx);
 3299            self.change_selections(None, window, cx, |s| {
 3300                s.select(selections);
 3301                s.clear_pending();
 3302            });
 3303        }
 3304    }
 3305
 3306    fn select_columns(
 3307        &mut self,
 3308        tail: DisplayPoint,
 3309        head: DisplayPoint,
 3310        goal_column: u32,
 3311        display_map: &DisplaySnapshot,
 3312        window: &mut Window,
 3313        cx: &mut Context<Self>,
 3314    ) {
 3315        let start_row = cmp::min(tail.row(), head.row());
 3316        let end_row = cmp::max(tail.row(), head.row());
 3317        let start_column = cmp::min(tail.column(), goal_column);
 3318        let end_column = cmp::max(tail.column(), goal_column);
 3319        let reversed = start_column < tail.column();
 3320
 3321        let selection_ranges = (start_row.0..=end_row.0)
 3322            .map(DisplayRow)
 3323            .filter_map(|row| {
 3324                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3325                    let start = display_map
 3326                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3327                        .to_point(display_map);
 3328                    let end = display_map
 3329                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3330                        .to_point(display_map);
 3331                    if reversed {
 3332                        Some(end..start)
 3333                    } else {
 3334                        Some(start..end)
 3335                    }
 3336                } else {
 3337                    None
 3338                }
 3339            })
 3340            .collect::<Vec<_>>();
 3341
 3342        self.change_selections(None, window, cx, |s| {
 3343            s.select_ranges(selection_ranges);
 3344        });
 3345        cx.notify();
 3346    }
 3347
 3348    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3349        self.selections
 3350            .all_adjusted(cx)
 3351            .iter()
 3352            .any(|selection| !selection.is_empty())
 3353    }
 3354
 3355    pub fn has_pending_nonempty_selection(&self) -> bool {
 3356        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3357            Some(Selection { start, end, .. }) => start != end,
 3358            None => false,
 3359        };
 3360
 3361        pending_nonempty_selection
 3362            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3363    }
 3364
 3365    pub fn has_pending_selection(&self) -> bool {
 3366        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3367    }
 3368
 3369    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3370        self.selection_mark_mode = false;
 3371
 3372        if self.clear_expanded_diff_hunks(cx) {
 3373            cx.notify();
 3374            return;
 3375        }
 3376        if self.dismiss_menus_and_popups(true, window, cx) {
 3377            return;
 3378        }
 3379
 3380        if self.mode.is_full()
 3381            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3382        {
 3383            return;
 3384        }
 3385
 3386        cx.propagate();
 3387    }
 3388
 3389    pub fn dismiss_menus_and_popups(
 3390        &mut self,
 3391        is_user_requested: bool,
 3392        window: &mut Window,
 3393        cx: &mut Context<Self>,
 3394    ) -> bool {
 3395        if self.take_rename(false, window, cx).is_some() {
 3396            return true;
 3397        }
 3398
 3399        if hide_hover(self, cx) {
 3400            return true;
 3401        }
 3402
 3403        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3404            return true;
 3405        }
 3406
 3407        if self.hide_context_menu(window, cx).is_some() {
 3408            return true;
 3409        }
 3410
 3411        if self.mouse_context_menu.take().is_some() {
 3412            return true;
 3413        }
 3414
 3415        if is_user_requested && self.discard_inline_completion(true, cx) {
 3416            return true;
 3417        }
 3418
 3419        if self.snippet_stack.pop().is_some() {
 3420            return true;
 3421        }
 3422
 3423        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3424            self.dismiss_diagnostics(cx);
 3425            return true;
 3426        }
 3427
 3428        false
 3429    }
 3430
 3431    fn linked_editing_ranges_for(
 3432        &self,
 3433        selection: Range<text::Anchor>,
 3434        cx: &App,
 3435    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3436        if self.linked_edit_ranges.is_empty() {
 3437            return None;
 3438        }
 3439        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3440            selection.end.buffer_id.and_then(|end_buffer_id| {
 3441                if selection.start.buffer_id != Some(end_buffer_id) {
 3442                    return None;
 3443                }
 3444                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3445                let snapshot = buffer.read(cx).snapshot();
 3446                self.linked_edit_ranges
 3447                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3448                    .map(|ranges| (ranges, snapshot, buffer))
 3449            })?;
 3450        use text::ToOffset as TO;
 3451        // find offset from the start of current range to current cursor position
 3452        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3453
 3454        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3455        let start_difference = start_offset - start_byte_offset;
 3456        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3457        let end_difference = end_offset - start_byte_offset;
 3458        // Current range has associated linked ranges.
 3459        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3460        for range in linked_ranges.iter() {
 3461            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3462            let end_offset = start_offset + end_difference;
 3463            let start_offset = start_offset + start_difference;
 3464            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3465                continue;
 3466            }
 3467            if self.selections.disjoint_anchor_ranges().any(|s| {
 3468                if s.start.buffer_id != selection.start.buffer_id
 3469                    || s.end.buffer_id != selection.end.buffer_id
 3470                {
 3471                    return false;
 3472                }
 3473                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3474                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3475            }) {
 3476                continue;
 3477            }
 3478            let start = buffer_snapshot.anchor_after(start_offset);
 3479            let end = buffer_snapshot.anchor_after(end_offset);
 3480            linked_edits
 3481                .entry(buffer.clone())
 3482                .or_default()
 3483                .push(start..end);
 3484        }
 3485        Some(linked_edits)
 3486    }
 3487
 3488    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3489        let text: Arc<str> = text.into();
 3490
 3491        if self.read_only(cx) {
 3492            return;
 3493        }
 3494
 3495        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3496
 3497        let selections = self.selections.all_adjusted(cx);
 3498        let mut bracket_inserted = false;
 3499        let mut edits = Vec::new();
 3500        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3501        let mut new_selections = Vec::with_capacity(selections.len());
 3502        let mut new_autoclose_regions = Vec::new();
 3503        let snapshot = self.buffer.read(cx).read(cx);
 3504        let mut clear_linked_edit_ranges = false;
 3505
 3506        for (selection, autoclose_region) in
 3507            self.selections_with_autoclose_regions(selections, &snapshot)
 3508        {
 3509            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3510                // Determine if the inserted text matches the opening or closing
 3511                // bracket of any of this language's bracket pairs.
 3512                let mut bracket_pair = None;
 3513                let mut is_bracket_pair_start = false;
 3514                let mut is_bracket_pair_end = false;
 3515                if !text.is_empty() {
 3516                    let mut bracket_pair_matching_end = None;
 3517                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3518                    //  and they are removing the character that triggered IME popup.
 3519                    for (pair, enabled) in scope.brackets() {
 3520                        if !pair.close && !pair.surround {
 3521                            continue;
 3522                        }
 3523
 3524                        if enabled && pair.start.ends_with(text.as_ref()) {
 3525                            let prefix_len = pair.start.len() - text.len();
 3526                            let preceding_text_matches_prefix = prefix_len == 0
 3527                                || (selection.start.column >= (prefix_len as u32)
 3528                                    && snapshot.contains_str_at(
 3529                                        Point::new(
 3530                                            selection.start.row,
 3531                                            selection.start.column - (prefix_len as u32),
 3532                                        ),
 3533                                        &pair.start[..prefix_len],
 3534                                    ));
 3535                            if preceding_text_matches_prefix {
 3536                                bracket_pair = Some(pair.clone());
 3537                                is_bracket_pair_start = true;
 3538                                break;
 3539                            }
 3540                        }
 3541                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3542                        {
 3543                            // take first bracket pair matching end, but don't break in case a later bracket
 3544                            // pair matches start
 3545                            bracket_pair_matching_end = Some(pair.clone());
 3546                        }
 3547                    }
 3548                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3549                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3550                        is_bracket_pair_end = true;
 3551                    }
 3552                }
 3553
 3554                if let Some(bracket_pair) = bracket_pair {
 3555                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3556                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3557                    let auto_surround =
 3558                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3559                    if selection.is_empty() {
 3560                        if is_bracket_pair_start {
 3561                            // If the inserted text is a suffix of an opening bracket and the
 3562                            // selection is preceded by the rest of the opening bracket, then
 3563                            // insert the closing bracket.
 3564                            let following_text_allows_autoclose = snapshot
 3565                                .chars_at(selection.start)
 3566                                .next()
 3567                                .map_or(true, |c| scope.should_autoclose_before(c));
 3568
 3569                            let preceding_text_allows_autoclose = selection.start.column == 0
 3570                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3571                                    true,
 3572                                    |c| {
 3573                                        bracket_pair.start != bracket_pair.end
 3574                                            || !snapshot
 3575                                                .char_classifier_at(selection.start)
 3576                                                .is_word(c)
 3577                                    },
 3578                                );
 3579
 3580                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3581                                && bracket_pair.start.len() == 1
 3582                            {
 3583                                let target = bracket_pair.start.chars().next().unwrap();
 3584                                let current_line_count = snapshot
 3585                                    .reversed_chars_at(selection.start)
 3586                                    .take_while(|&c| c != '\n')
 3587                                    .filter(|&c| c == target)
 3588                                    .count();
 3589                                current_line_count % 2 == 1
 3590                            } else {
 3591                                false
 3592                            };
 3593
 3594                            if autoclose
 3595                                && bracket_pair.close
 3596                                && following_text_allows_autoclose
 3597                                && preceding_text_allows_autoclose
 3598                                && !is_closing_quote
 3599                            {
 3600                                let anchor = snapshot.anchor_before(selection.end);
 3601                                new_selections.push((selection.map(|_| anchor), text.len()));
 3602                                new_autoclose_regions.push((
 3603                                    anchor,
 3604                                    text.len(),
 3605                                    selection.id,
 3606                                    bracket_pair.clone(),
 3607                                ));
 3608                                edits.push((
 3609                                    selection.range(),
 3610                                    format!("{}{}", text, bracket_pair.end).into(),
 3611                                ));
 3612                                bracket_inserted = true;
 3613                                continue;
 3614                            }
 3615                        }
 3616
 3617                        if let Some(region) = autoclose_region {
 3618                            // If the selection is followed by an auto-inserted closing bracket,
 3619                            // then don't insert that closing bracket again; just move the selection
 3620                            // past the closing bracket.
 3621                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3622                                && text.as_ref() == region.pair.end.as_str();
 3623                            if should_skip {
 3624                                let anchor = snapshot.anchor_after(selection.end);
 3625                                new_selections
 3626                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3627                                continue;
 3628                            }
 3629                        }
 3630
 3631                        let always_treat_brackets_as_autoclosed = snapshot
 3632                            .language_settings_at(selection.start, cx)
 3633                            .always_treat_brackets_as_autoclosed;
 3634                        if always_treat_brackets_as_autoclosed
 3635                            && is_bracket_pair_end
 3636                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3637                        {
 3638                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3639                            // and the inserted text is a closing bracket and the selection is followed
 3640                            // by the closing bracket then move the selection past the closing bracket.
 3641                            let anchor = snapshot.anchor_after(selection.end);
 3642                            new_selections.push((selection.map(|_| anchor), text.len()));
 3643                            continue;
 3644                        }
 3645                    }
 3646                    // If an opening bracket is 1 character long and is typed while
 3647                    // text is selected, then surround that text with the bracket pair.
 3648                    else if auto_surround
 3649                        && bracket_pair.surround
 3650                        && is_bracket_pair_start
 3651                        && bracket_pair.start.chars().count() == 1
 3652                    {
 3653                        edits.push((selection.start..selection.start, text.clone()));
 3654                        edits.push((
 3655                            selection.end..selection.end,
 3656                            bracket_pair.end.as_str().into(),
 3657                        ));
 3658                        bracket_inserted = true;
 3659                        new_selections.push((
 3660                            Selection {
 3661                                id: selection.id,
 3662                                start: snapshot.anchor_after(selection.start),
 3663                                end: snapshot.anchor_before(selection.end),
 3664                                reversed: selection.reversed,
 3665                                goal: selection.goal,
 3666                            },
 3667                            0,
 3668                        ));
 3669                        continue;
 3670                    }
 3671                }
 3672            }
 3673
 3674            if self.auto_replace_emoji_shortcode
 3675                && selection.is_empty()
 3676                && text.as_ref().ends_with(':')
 3677            {
 3678                if let Some(possible_emoji_short_code) =
 3679                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3680                {
 3681                    if !possible_emoji_short_code.is_empty() {
 3682                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3683                            let emoji_shortcode_start = Point::new(
 3684                                selection.start.row,
 3685                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3686                            );
 3687
 3688                            // Remove shortcode from buffer
 3689                            edits.push((
 3690                                emoji_shortcode_start..selection.start,
 3691                                "".to_string().into(),
 3692                            ));
 3693                            new_selections.push((
 3694                                Selection {
 3695                                    id: selection.id,
 3696                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3697                                    end: snapshot.anchor_before(selection.start),
 3698                                    reversed: selection.reversed,
 3699                                    goal: selection.goal,
 3700                                },
 3701                                0,
 3702                            ));
 3703
 3704                            // Insert emoji
 3705                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3706                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3707                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3708
 3709                            continue;
 3710                        }
 3711                    }
 3712                }
 3713            }
 3714
 3715            // If not handling any auto-close operation, then just replace the selected
 3716            // text with the given input and move the selection to the end of the
 3717            // newly inserted text.
 3718            let anchor = snapshot.anchor_after(selection.end);
 3719            if !self.linked_edit_ranges.is_empty() {
 3720                let start_anchor = snapshot.anchor_before(selection.start);
 3721
 3722                let is_word_char = text.chars().next().map_or(true, |char| {
 3723                    let classifier = snapshot
 3724                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3725                        .ignore_punctuation(true);
 3726                    classifier.is_word(char)
 3727                });
 3728
 3729                if is_word_char {
 3730                    if let Some(ranges) = self
 3731                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3732                    {
 3733                        for (buffer, edits) in ranges {
 3734                            linked_edits
 3735                                .entry(buffer.clone())
 3736                                .or_default()
 3737                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3738                        }
 3739                    }
 3740                } else {
 3741                    clear_linked_edit_ranges = true;
 3742                }
 3743            }
 3744
 3745            new_selections.push((selection.map(|_| anchor), 0));
 3746            edits.push((selection.start..selection.end, text.clone()));
 3747        }
 3748
 3749        drop(snapshot);
 3750
 3751        self.transact(window, cx, |this, window, cx| {
 3752            if clear_linked_edit_ranges {
 3753                this.linked_edit_ranges.clear();
 3754            }
 3755            let initial_buffer_versions =
 3756                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3757
 3758            this.buffer.update(cx, |buffer, cx| {
 3759                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3760            });
 3761            for (buffer, edits) in linked_edits {
 3762                buffer.update(cx, |buffer, cx| {
 3763                    let snapshot = buffer.snapshot();
 3764                    let edits = edits
 3765                        .into_iter()
 3766                        .map(|(range, text)| {
 3767                            use text::ToPoint as TP;
 3768                            let end_point = TP::to_point(&range.end, &snapshot);
 3769                            let start_point = TP::to_point(&range.start, &snapshot);
 3770                            (start_point..end_point, text)
 3771                        })
 3772                        .sorted_by_key(|(range, _)| range.start);
 3773                    buffer.edit(edits, None, cx);
 3774                })
 3775            }
 3776            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3777            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3778            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3779            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3780                .zip(new_selection_deltas)
 3781                .map(|(selection, delta)| Selection {
 3782                    id: selection.id,
 3783                    start: selection.start + delta,
 3784                    end: selection.end + delta,
 3785                    reversed: selection.reversed,
 3786                    goal: SelectionGoal::None,
 3787                })
 3788                .collect::<Vec<_>>();
 3789
 3790            let mut i = 0;
 3791            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3792                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3793                let start = map.buffer_snapshot.anchor_before(position);
 3794                let end = map.buffer_snapshot.anchor_after(position);
 3795                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3796                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3797                        Ordering::Less => i += 1,
 3798                        Ordering::Greater => break,
 3799                        Ordering::Equal => {
 3800                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3801                                Ordering::Less => i += 1,
 3802                                Ordering::Equal => break,
 3803                                Ordering::Greater => break,
 3804                            }
 3805                        }
 3806                    }
 3807                }
 3808                this.autoclose_regions.insert(
 3809                    i,
 3810                    AutocloseRegion {
 3811                        selection_id,
 3812                        range: start..end,
 3813                        pair,
 3814                    },
 3815                );
 3816            }
 3817
 3818            let had_active_inline_completion = this.has_active_inline_completion();
 3819            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3820                s.select(new_selections)
 3821            });
 3822
 3823            if !bracket_inserted {
 3824                if let Some(on_type_format_task) =
 3825                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3826                {
 3827                    on_type_format_task.detach_and_log_err(cx);
 3828                }
 3829            }
 3830
 3831            let editor_settings = EditorSettings::get_global(cx);
 3832            if bracket_inserted
 3833                && (editor_settings.auto_signature_help
 3834                    || editor_settings.show_signature_help_after_edits)
 3835            {
 3836                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3837            }
 3838
 3839            let trigger_in_words =
 3840                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3841            if this.hard_wrap.is_some() {
 3842                let latest: Range<Point> = this.selections.newest(cx).range();
 3843                if latest.is_empty()
 3844                    && this
 3845                        .buffer()
 3846                        .read(cx)
 3847                        .snapshot(cx)
 3848                        .line_len(MultiBufferRow(latest.start.row))
 3849                        == latest.start.column
 3850                {
 3851                    this.rewrap_impl(
 3852                        RewrapOptions {
 3853                            override_language_settings: true,
 3854                            preserve_existing_whitespace: true,
 3855                        },
 3856                        cx,
 3857                    )
 3858                }
 3859            }
 3860            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3861            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3862            this.refresh_inline_completion(true, false, window, cx);
 3863            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3864        });
 3865    }
 3866
 3867    fn find_possible_emoji_shortcode_at_position(
 3868        snapshot: &MultiBufferSnapshot,
 3869        position: Point,
 3870    ) -> Option<String> {
 3871        let mut chars = Vec::new();
 3872        let mut found_colon = false;
 3873        for char in snapshot.reversed_chars_at(position).take(100) {
 3874            // Found a possible emoji shortcode in the middle of the buffer
 3875            if found_colon {
 3876                if char.is_whitespace() {
 3877                    chars.reverse();
 3878                    return Some(chars.iter().collect());
 3879                }
 3880                // If the previous character is not a whitespace, we are in the middle of a word
 3881                // and we only want to complete the shortcode if the word is made up of other emojis
 3882                let mut containing_word = String::new();
 3883                for ch in snapshot
 3884                    .reversed_chars_at(position)
 3885                    .skip(chars.len() + 1)
 3886                    .take(100)
 3887                {
 3888                    if ch.is_whitespace() {
 3889                        break;
 3890                    }
 3891                    containing_word.push(ch);
 3892                }
 3893                let containing_word = containing_word.chars().rev().collect::<String>();
 3894                if util::word_consists_of_emojis(containing_word.as_str()) {
 3895                    chars.reverse();
 3896                    return Some(chars.iter().collect());
 3897                }
 3898            }
 3899
 3900            if char.is_whitespace() || !char.is_ascii() {
 3901                return None;
 3902            }
 3903            if char == ':' {
 3904                found_colon = true;
 3905            } else {
 3906                chars.push(char);
 3907            }
 3908        }
 3909        // Found a possible emoji shortcode at the beginning of the buffer
 3910        chars.reverse();
 3911        Some(chars.iter().collect())
 3912    }
 3913
 3914    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3915        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3916        self.transact(window, cx, |this, window, cx| {
 3917            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3918                let selections = this.selections.all::<usize>(cx);
 3919                let multi_buffer = this.buffer.read(cx);
 3920                let buffer = multi_buffer.snapshot(cx);
 3921                selections
 3922                    .iter()
 3923                    .map(|selection| {
 3924                        let start_point = selection.start.to_point(&buffer);
 3925                        let mut existing_indent =
 3926                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3927                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3928                        let start = selection.start;
 3929                        let end = selection.end;
 3930                        let selection_is_empty = start == end;
 3931                        let language_scope = buffer.language_scope_at(start);
 3932                        let (
 3933                            comment_delimiter,
 3934                            doc_delimiter,
 3935                            insert_extra_newline,
 3936                            indent_on_newline,
 3937                            indent_on_extra_newline,
 3938                        ) = if let Some(language) = &language_scope {
 3939                            let mut insert_extra_newline =
 3940                                insert_extra_newline_brackets(&buffer, start..end, language)
 3941                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3942
 3943                            // Comment extension on newline is allowed only for cursor selections
 3944                            let comment_delimiter = maybe!({
 3945                                if !selection_is_empty {
 3946                                    return None;
 3947                                }
 3948
 3949                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3950                                    return None;
 3951                                }
 3952
 3953                                let delimiters = language.line_comment_prefixes();
 3954                                let max_len_of_delimiter =
 3955                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3956                                let (snapshot, range) =
 3957                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3958
 3959                                let num_of_whitespaces = snapshot
 3960                                    .chars_for_range(range.clone())
 3961                                    .take_while(|c| c.is_whitespace())
 3962                                    .count();
 3963                                let comment_candidate = snapshot
 3964                                    .chars_for_range(range)
 3965                                    .skip(num_of_whitespaces)
 3966                                    .take(max_len_of_delimiter)
 3967                                    .collect::<String>();
 3968                                let (delimiter, trimmed_len) = delimiters
 3969                                    .iter()
 3970                                    .filter_map(|delimiter| {
 3971                                        let prefix = delimiter.trim_end();
 3972                                        if comment_candidate.starts_with(prefix) {
 3973                                            Some((delimiter, prefix.len()))
 3974                                        } else {
 3975                                            None
 3976                                        }
 3977                                    })
 3978                                    .max_by_key(|(_, len)| *len)?;
 3979
 3980                                let cursor_is_placed_after_comment_marker =
 3981                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 3982                                if cursor_is_placed_after_comment_marker {
 3983                                    Some(delimiter.clone())
 3984                                } else {
 3985                                    None
 3986                                }
 3987                            });
 3988
 3989                            let mut indent_on_newline = IndentSize::spaces(0);
 3990                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 3991
 3992                            let doc_delimiter = maybe!({
 3993                                if !selection_is_empty {
 3994                                    return None;
 3995                                }
 3996
 3997                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3998                                    return None;
 3999                                }
 4000
 4001                                let DocumentationConfig {
 4002                                    start: start_tag,
 4003                                    end: end_tag,
 4004                                    prefix: delimiter,
 4005                                    tab_size: len,
 4006                                } = language.documentation()?;
 4007
 4008                                let is_within_block_comment = buffer
 4009                                    .language_scope_at(start_point)
 4010                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4011                                if !is_within_block_comment {
 4012                                    return None;
 4013                                }
 4014
 4015                                let (snapshot, range) =
 4016                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4017
 4018                                let num_of_whitespaces = snapshot
 4019                                    .chars_for_range(range.clone())
 4020                                    .take_while(|c| c.is_whitespace())
 4021                                    .count();
 4022
 4023                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4024                                let column = start_point.column;
 4025                                let cursor_is_after_start_tag = {
 4026                                    let start_tag_len = start_tag.len();
 4027                                    let start_tag_line = snapshot
 4028                                        .chars_for_range(range.clone())
 4029                                        .skip(num_of_whitespaces)
 4030                                        .take(start_tag_len)
 4031                                        .collect::<String>();
 4032                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4033                                        num_of_whitespaces + start_tag_len <= column as usize
 4034                                    } else {
 4035                                        false
 4036                                    }
 4037                                };
 4038
 4039                                let cursor_is_after_delimiter = {
 4040                                    let delimiter_trim = delimiter.trim_end();
 4041                                    let delimiter_line = snapshot
 4042                                        .chars_for_range(range.clone())
 4043                                        .skip(num_of_whitespaces)
 4044                                        .take(delimiter_trim.len())
 4045                                        .collect::<String>();
 4046                                    if delimiter_line.starts_with(delimiter_trim) {
 4047                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4048                                    } else {
 4049                                        false
 4050                                    }
 4051                                };
 4052
 4053                                let cursor_is_before_end_tag_if_exists = {
 4054                                    let mut char_position = 0u32;
 4055                                    let mut end_tag_offset = None;
 4056
 4057                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4058                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4059                                            let chars_before_match =
 4060                                                chunk[..byte_pos].chars().count() as u32;
 4061                                            end_tag_offset =
 4062                                                Some(char_position + chars_before_match);
 4063                                            break 'outer;
 4064                                        }
 4065                                        char_position += chunk.chars().count() as u32;
 4066                                    }
 4067
 4068                                    if let Some(end_tag_offset) = end_tag_offset {
 4069                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4070                                        if cursor_is_after_start_tag {
 4071                                            if cursor_is_before_end_tag {
 4072                                                insert_extra_newline = true;
 4073                                            }
 4074                                            let cursor_is_at_start_of_end_tag =
 4075                                                column == end_tag_offset;
 4076                                            if cursor_is_at_start_of_end_tag {
 4077                                                indent_on_extra_newline.len = (*len).into();
 4078                                            }
 4079                                        }
 4080                                        cursor_is_before_end_tag
 4081                                    } else {
 4082                                        true
 4083                                    }
 4084                                };
 4085
 4086                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4087                                    && cursor_is_before_end_tag_if_exists
 4088                                {
 4089                                    if cursor_is_after_start_tag {
 4090                                        indent_on_newline.len = (*len).into();
 4091                                    }
 4092                                    Some(delimiter.clone())
 4093                                } else {
 4094                                    None
 4095                                }
 4096                            });
 4097
 4098                            (
 4099                                comment_delimiter,
 4100                                doc_delimiter,
 4101                                insert_extra_newline,
 4102                                indent_on_newline,
 4103                                indent_on_extra_newline,
 4104                            )
 4105                        } else {
 4106                            (
 4107                                None,
 4108                                None,
 4109                                false,
 4110                                IndentSize::default(),
 4111                                IndentSize::default(),
 4112                            )
 4113                        };
 4114
 4115                        let prevent_auto_indent = doc_delimiter.is_some();
 4116                        let delimiter = comment_delimiter.or(doc_delimiter);
 4117
 4118                        let capacity_for_delimiter =
 4119                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4120                        let mut new_text = String::with_capacity(
 4121                            1 + capacity_for_delimiter
 4122                                + existing_indent.len as usize
 4123                                + indent_on_newline.len as usize
 4124                                + indent_on_extra_newline.len as usize,
 4125                        );
 4126                        new_text.push('\n');
 4127                        new_text.extend(existing_indent.chars());
 4128                        new_text.extend(indent_on_newline.chars());
 4129
 4130                        if let Some(delimiter) = &delimiter {
 4131                            new_text.push_str(delimiter);
 4132                        }
 4133
 4134                        if insert_extra_newline {
 4135                            new_text.push('\n');
 4136                            new_text.extend(existing_indent.chars());
 4137                            new_text.extend(indent_on_extra_newline.chars());
 4138                        }
 4139
 4140                        let anchor = buffer.anchor_after(end);
 4141                        let new_selection = selection.map(|_| anchor);
 4142                        (
 4143                            ((start..end, new_text), prevent_auto_indent),
 4144                            (insert_extra_newline, new_selection),
 4145                        )
 4146                    })
 4147                    .unzip()
 4148            };
 4149
 4150            let mut auto_indent_edits = Vec::new();
 4151            let mut edits = Vec::new();
 4152            for (edit, prevent_auto_indent) in edits_with_flags {
 4153                if prevent_auto_indent {
 4154                    edits.push(edit);
 4155                } else {
 4156                    auto_indent_edits.push(edit);
 4157                }
 4158            }
 4159            if !edits.is_empty() {
 4160                this.edit(edits, cx);
 4161            }
 4162            if !auto_indent_edits.is_empty() {
 4163                this.edit_with_autoindent(auto_indent_edits, cx);
 4164            }
 4165
 4166            let buffer = this.buffer.read(cx).snapshot(cx);
 4167            let new_selections = selection_info
 4168                .into_iter()
 4169                .map(|(extra_newline_inserted, new_selection)| {
 4170                    let mut cursor = new_selection.end.to_point(&buffer);
 4171                    if extra_newline_inserted {
 4172                        cursor.row -= 1;
 4173                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4174                    }
 4175                    new_selection.map(|_| cursor)
 4176                })
 4177                .collect();
 4178
 4179            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4180                s.select(new_selections)
 4181            });
 4182            this.refresh_inline_completion(true, false, window, cx);
 4183        });
 4184    }
 4185
 4186    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4187        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4188
 4189        let buffer = self.buffer.read(cx);
 4190        let snapshot = buffer.snapshot(cx);
 4191
 4192        let mut edits = Vec::new();
 4193        let mut rows = Vec::new();
 4194
 4195        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4196            let cursor = selection.head();
 4197            let row = cursor.row;
 4198
 4199            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4200
 4201            let newline = "\n".to_string();
 4202            edits.push((start_of_line..start_of_line, newline));
 4203
 4204            rows.push(row + rows_inserted as u32);
 4205        }
 4206
 4207        self.transact(window, cx, |editor, window, cx| {
 4208            editor.edit(edits, cx);
 4209
 4210            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4211                let mut index = 0;
 4212                s.move_cursors_with(|map, _, _| {
 4213                    let row = rows[index];
 4214                    index += 1;
 4215
 4216                    let point = Point::new(row, 0);
 4217                    let boundary = map.next_line_boundary(point).1;
 4218                    let clipped = map.clip_point(boundary, Bias::Left);
 4219
 4220                    (clipped, SelectionGoal::None)
 4221                });
 4222            });
 4223
 4224            let mut indent_edits = Vec::new();
 4225            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4226            for row in rows {
 4227                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4228                for (row, indent) in indents {
 4229                    if indent.len == 0 {
 4230                        continue;
 4231                    }
 4232
 4233                    let text = match indent.kind {
 4234                        IndentKind::Space => " ".repeat(indent.len as usize),
 4235                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4236                    };
 4237                    let point = Point::new(row.0, 0);
 4238                    indent_edits.push((point..point, text));
 4239                }
 4240            }
 4241            editor.edit(indent_edits, cx);
 4242        });
 4243    }
 4244
 4245    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4246        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4247
 4248        let buffer = self.buffer.read(cx);
 4249        let snapshot = buffer.snapshot(cx);
 4250
 4251        let mut edits = Vec::new();
 4252        let mut rows = Vec::new();
 4253        let mut rows_inserted = 0;
 4254
 4255        for selection in self.selections.all_adjusted(cx) {
 4256            let cursor = selection.head();
 4257            let row = cursor.row;
 4258
 4259            let point = Point::new(row + 1, 0);
 4260            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4261
 4262            let newline = "\n".to_string();
 4263            edits.push((start_of_line..start_of_line, newline));
 4264
 4265            rows_inserted += 1;
 4266            rows.push(row + rows_inserted);
 4267        }
 4268
 4269        self.transact(window, cx, |editor, window, cx| {
 4270            editor.edit(edits, cx);
 4271
 4272            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4273                let mut index = 0;
 4274                s.move_cursors_with(|map, _, _| {
 4275                    let row = rows[index];
 4276                    index += 1;
 4277
 4278                    let point = Point::new(row, 0);
 4279                    let boundary = map.next_line_boundary(point).1;
 4280                    let clipped = map.clip_point(boundary, Bias::Left);
 4281
 4282                    (clipped, SelectionGoal::None)
 4283                });
 4284            });
 4285
 4286            let mut indent_edits = Vec::new();
 4287            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4288            for row in rows {
 4289                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4290                for (row, indent) in indents {
 4291                    if indent.len == 0 {
 4292                        continue;
 4293                    }
 4294
 4295                    let text = match indent.kind {
 4296                        IndentKind::Space => " ".repeat(indent.len as usize),
 4297                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4298                    };
 4299                    let point = Point::new(row.0, 0);
 4300                    indent_edits.push((point..point, text));
 4301                }
 4302            }
 4303            editor.edit(indent_edits, cx);
 4304        });
 4305    }
 4306
 4307    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4308        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4309            original_indent_columns: Vec::new(),
 4310        });
 4311        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4312    }
 4313
 4314    fn insert_with_autoindent_mode(
 4315        &mut self,
 4316        text: &str,
 4317        autoindent_mode: Option<AutoindentMode>,
 4318        window: &mut Window,
 4319        cx: &mut Context<Self>,
 4320    ) {
 4321        if self.read_only(cx) {
 4322            return;
 4323        }
 4324
 4325        let text: Arc<str> = text.into();
 4326        self.transact(window, cx, |this, window, cx| {
 4327            let old_selections = this.selections.all_adjusted(cx);
 4328            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4329                let anchors = {
 4330                    let snapshot = buffer.read(cx);
 4331                    old_selections
 4332                        .iter()
 4333                        .map(|s| {
 4334                            let anchor = snapshot.anchor_after(s.head());
 4335                            s.map(|_| anchor)
 4336                        })
 4337                        .collect::<Vec<_>>()
 4338                };
 4339                buffer.edit(
 4340                    old_selections
 4341                        .iter()
 4342                        .map(|s| (s.start..s.end, text.clone())),
 4343                    autoindent_mode,
 4344                    cx,
 4345                );
 4346                anchors
 4347            });
 4348
 4349            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4350                s.select_anchors(selection_anchors);
 4351            });
 4352
 4353            cx.notify();
 4354        });
 4355    }
 4356
 4357    fn trigger_completion_on_input(
 4358        &mut self,
 4359        text: &str,
 4360        trigger_in_words: bool,
 4361        window: &mut Window,
 4362        cx: &mut Context<Self>,
 4363    ) {
 4364        let ignore_completion_provider = self
 4365            .context_menu
 4366            .borrow()
 4367            .as_ref()
 4368            .map(|menu| match menu {
 4369                CodeContextMenu::Completions(completions_menu) => {
 4370                    completions_menu.ignore_completion_provider
 4371                }
 4372                CodeContextMenu::CodeActions(_) => false,
 4373            })
 4374            .unwrap_or(false);
 4375
 4376        if ignore_completion_provider {
 4377            self.show_word_completions(&ShowWordCompletions, window, cx);
 4378        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4379            self.show_completions(
 4380                &ShowCompletions {
 4381                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4382                },
 4383                window,
 4384                cx,
 4385            );
 4386        } else {
 4387            self.hide_context_menu(window, cx);
 4388        }
 4389    }
 4390
 4391    fn is_completion_trigger(
 4392        &self,
 4393        text: &str,
 4394        trigger_in_words: bool,
 4395        cx: &mut Context<Self>,
 4396    ) -> bool {
 4397        let position = self.selections.newest_anchor().head();
 4398        let multibuffer = self.buffer.read(cx);
 4399        let Some(buffer) = position
 4400            .buffer_id
 4401            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4402        else {
 4403            return false;
 4404        };
 4405
 4406        if let Some(completion_provider) = &self.completion_provider {
 4407            completion_provider.is_completion_trigger(
 4408                &buffer,
 4409                position.text_anchor,
 4410                text,
 4411                trigger_in_words,
 4412                cx,
 4413            )
 4414        } else {
 4415            false
 4416        }
 4417    }
 4418
 4419    /// If any empty selections is touching the start of its innermost containing autoclose
 4420    /// region, expand it to select the brackets.
 4421    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4422        let selections = self.selections.all::<usize>(cx);
 4423        let buffer = self.buffer.read(cx).read(cx);
 4424        let new_selections = self
 4425            .selections_with_autoclose_regions(selections, &buffer)
 4426            .map(|(mut selection, region)| {
 4427                if !selection.is_empty() {
 4428                    return selection;
 4429                }
 4430
 4431                if let Some(region) = region {
 4432                    let mut range = region.range.to_offset(&buffer);
 4433                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4434                        range.start -= region.pair.start.len();
 4435                        if buffer.contains_str_at(range.start, &region.pair.start)
 4436                            && buffer.contains_str_at(range.end, &region.pair.end)
 4437                        {
 4438                            range.end += region.pair.end.len();
 4439                            selection.start = range.start;
 4440                            selection.end = range.end;
 4441
 4442                            return selection;
 4443                        }
 4444                    }
 4445                }
 4446
 4447                let always_treat_brackets_as_autoclosed = buffer
 4448                    .language_settings_at(selection.start, cx)
 4449                    .always_treat_brackets_as_autoclosed;
 4450
 4451                if !always_treat_brackets_as_autoclosed {
 4452                    return selection;
 4453                }
 4454
 4455                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4456                    for (pair, enabled) in scope.brackets() {
 4457                        if !enabled || !pair.close {
 4458                            continue;
 4459                        }
 4460
 4461                        if buffer.contains_str_at(selection.start, &pair.end) {
 4462                            let pair_start_len = pair.start.len();
 4463                            if buffer.contains_str_at(
 4464                                selection.start.saturating_sub(pair_start_len),
 4465                                &pair.start,
 4466                            ) {
 4467                                selection.start -= pair_start_len;
 4468                                selection.end += pair.end.len();
 4469
 4470                                return selection;
 4471                            }
 4472                        }
 4473                    }
 4474                }
 4475
 4476                selection
 4477            })
 4478            .collect();
 4479
 4480        drop(buffer);
 4481        self.change_selections(None, window, cx, |selections| {
 4482            selections.select(new_selections)
 4483        });
 4484    }
 4485
 4486    /// Iterate the given selections, and for each one, find the smallest surrounding
 4487    /// autoclose region. This uses the ordering of the selections and the autoclose
 4488    /// regions to avoid repeated comparisons.
 4489    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4490        &'a self,
 4491        selections: impl IntoIterator<Item = Selection<D>>,
 4492        buffer: &'a MultiBufferSnapshot,
 4493    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4494        let mut i = 0;
 4495        let mut regions = self.autoclose_regions.as_slice();
 4496        selections.into_iter().map(move |selection| {
 4497            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4498
 4499            let mut enclosing = None;
 4500            while let Some(pair_state) = regions.get(i) {
 4501                if pair_state.range.end.to_offset(buffer) < range.start {
 4502                    regions = &regions[i + 1..];
 4503                    i = 0;
 4504                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4505                    break;
 4506                } else {
 4507                    if pair_state.selection_id == selection.id {
 4508                        enclosing = Some(pair_state);
 4509                    }
 4510                    i += 1;
 4511                }
 4512            }
 4513
 4514            (selection, enclosing)
 4515        })
 4516    }
 4517
 4518    /// Remove any autoclose regions that no longer contain their selection.
 4519    fn invalidate_autoclose_regions(
 4520        &mut self,
 4521        mut selections: &[Selection<Anchor>],
 4522        buffer: &MultiBufferSnapshot,
 4523    ) {
 4524        self.autoclose_regions.retain(|state| {
 4525            let mut i = 0;
 4526            while let Some(selection) = selections.get(i) {
 4527                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4528                    selections = &selections[1..];
 4529                    continue;
 4530                }
 4531                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4532                    break;
 4533                }
 4534                if selection.id == state.selection_id {
 4535                    return true;
 4536                } else {
 4537                    i += 1;
 4538                }
 4539            }
 4540            false
 4541        });
 4542    }
 4543
 4544    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4545        let offset = position.to_offset(buffer);
 4546        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4547        if offset > word_range.start && kind == Some(CharKind::Word) {
 4548            Some(
 4549                buffer
 4550                    .text_for_range(word_range.start..offset)
 4551                    .collect::<String>(),
 4552            )
 4553        } else {
 4554            None
 4555        }
 4556    }
 4557
 4558    pub fn toggle_inline_values(
 4559        &mut self,
 4560        _: &ToggleInlineValues,
 4561        _: &mut Window,
 4562        cx: &mut Context<Self>,
 4563    ) {
 4564        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4565
 4566        self.refresh_inline_values(cx);
 4567    }
 4568
 4569    pub fn toggle_inlay_hints(
 4570        &mut self,
 4571        _: &ToggleInlayHints,
 4572        _: &mut Window,
 4573        cx: &mut Context<Self>,
 4574    ) {
 4575        self.refresh_inlay_hints(
 4576            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4577            cx,
 4578        );
 4579    }
 4580
 4581    pub fn inlay_hints_enabled(&self) -> bool {
 4582        self.inlay_hint_cache.enabled
 4583    }
 4584
 4585    pub fn inline_values_enabled(&self) -> bool {
 4586        self.inline_value_cache.enabled
 4587    }
 4588
 4589    #[cfg(any(test, feature = "test-support"))]
 4590    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4591        self.display_map
 4592            .read(cx)
 4593            .current_inlays()
 4594            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4595            .cloned()
 4596            .collect()
 4597    }
 4598
 4599    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4600        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4601            return;
 4602        }
 4603
 4604        let reason_description = reason.description();
 4605        let ignore_debounce = matches!(
 4606            reason,
 4607            InlayHintRefreshReason::SettingsChange(_)
 4608                | InlayHintRefreshReason::Toggle(_)
 4609                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4610                | InlayHintRefreshReason::ModifiersChanged(_)
 4611        );
 4612        let (invalidate_cache, required_languages) = match reason {
 4613            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4614                match self.inlay_hint_cache.modifiers_override(enabled) {
 4615                    Some(enabled) => {
 4616                        if enabled {
 4617                            (InvalidationStrategy::RefreshRequested, None)
 4618                        } else {
 4619                            self.splice_inlays(
 4620                                &self
 4621                                    .visible_inlay_hints(cx)
 4622                                    .iter()
 4623                                    .map(|inlay| inlay.id)
 4624                                    .collect::<Vec<InlayId>>(),
 4625                                Vec::new(),
 4626                                cx,
 4627                            );
 4628                            return;
 4629                        }
 4630                    }
 4631                    None => return,
 4632                }
 4633            }
 4634            InlayHintRefreshReason::Toggle(enabled) => {
 4635                if self.inlay_hint_cache.toggle(enabled) {
 4636                    if enabled {
 4637                        (InvalidationStrategy::RefreshRequested, None)
 4638                    } else {
 4639                        self.splice_inlays(
 4640                            &self
 4641                                .visible_inlay_hints(cx)
 4642                                .iter()
 4643                                .map(|inlay| inlay.id)
 4644                                .collect::<Vec<InlayId>>(),
 4645                            Vec::new(),
 4646                            cx,
 4647                        );
 4648                        return;
 4649                    }
 4650                } else {
 4651                    return;
 4652                }
 4653            }
 4654            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4655                match self.inlay_hint_cache.update_settings(
 4656                    &self.buffer,
 4657                    new_settings,
 4658                    self.visible_inlay_hints(cx),
 4659                    cx,
 4660                ) {
 4661                    ControlFlow::Break(Some(InlaySplice {
 4662                        to_remove,
 4663                        to_insert,
 4664                    })) => {
 4665                        self.splice_inlays(&to_remove, to_insert, cx);
 4666                        return;
 4667                    }
 4668                    ControlFlow::Break(None) => return,
 4669                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4670                }
 4671            }
 4672            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4673                if let Some(InlaySplice {
 4674                    to_remove,
 4675                    to_insert,
 4676                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4677                {
 4678                    self.splice_inlays(&to_remove, to_insert, cx);
 4679                }
 4680                self.display_map.update(cx, |display_map, _| {
 4681                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4682                });
 4683                return;
 4684            }
 4685            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4686            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4687                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4688            }
 4689            InlayHintRefreshReason::RefreshRequested => {
 4690                (InvalidationStrategy::RefreshRequested, None)
 4691            }
 4692        };
 4693
 4694        if let Some(InlaySplice {
 4695            to_remove,
 4696            to_insert,
 4697        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4698            reason_description,
 4699            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4700            invalidate_cache,
 4701            ignore_debounce,
 4702            cx,
 4703        ) {
 4704            self.splice_inlays(&to_remove, to_insert, cx);
 4705        }
 4706    }
 4707
 4708    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4709        self.display_map
 4710            .read(cx)
 4711            .current_inlays()
 4712            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4713            .cloned()
 4714            .collect()
 4715    }
 4716
 4717    pub fn excerpts_for_inlay_hints_query(
 4718        &self,
 4719        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4720        cx: &mut Context<Editor>,
 4721    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4722        let Some(project) = self.project.as_ref() else {
 4723            return HashMap::default();
 4724        };
 4725        let project = project.read(cx);
 4726        let multi_buffer = self.buffer().read(cx);
 4727        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4728        let multi_buffer_visible_start = self
 4729            .scroll_manager
 4730            .anchor()
 4731            .anchor
 4732            .to_point(&multi_buffer_snapshot);
 4733        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4734            multi_buffer_visible_start
 4735                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4736            Bias::Left,
 4737        );
 4738        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4739        multi_buffer_snapshot
 4740            .range_to_buffer_ranges(multi_buffer_visible_range)
 4741            .into_iter()
 4742            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4743            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4744                let buffer_file = project::File::from_dyn(buffer.file())?;
 4745                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4746                let worktree_entry = buffer_worktree
 4747                    .read(cx)
 4748                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4749                if worktree_entry.is_ignored {
 4750                    return None;
 4751                }
 4752
 4753                let language = buffer.language()?;
 4754                if let Some(restrict_to_languages) = restrict_to_languages {
 4755                    if !restrict_to_languages.contains(language) {
 4756                        return None;
 4757                    }
 4758                }
 4759                Some((
 4760                    excerpt_id,
 4761                    (
 4762                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4763                        buffer.version().clone(),
 4764                        excerpt_visible_range,
 4765                    ),
 4766                ))
 4767            })
 4768            .collect()
 4769    }
 4770
 4771    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4772        TextLayoutDetails {
 4773            text_system: window.text_system().clone(),
 4774            editor_style: self.style.clone().unwrap(),
 4775            rem_size: window.rem_size(),
 4776            scroll_anchor: self.scroll_manager.anchor(),
 4777            visible_rows: self.visible_line_count(),
 4778            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4779        }
 4780    }
 4781
 4782    pub fn splice_inlays(
 4783        &self,
 4784        to_remove: &[InlayId],
 4785        to_insert: Vec<Inlay>,
 4786        cx: &mut Context<Self>,
 4787    ) {
 4788        self.display_map.update(cx, |display_map, cx| {
 4789            display_map.splice_inlays(to_remove, to_insert, cx)
 4790        });
 4791        cx.notify();
 4792    }
 4793
 4794    fn trigger_on_type_formatting(
 4795        &self,
 4796        input: String,
 4797        window: &mut Window,
 4798        cx: &mut Context<Self>,
 4799    ) -> Option<Task<Result<()>>> {
 4800        if input.len() != 1 {
 4801            return None;
 4802        }
 4803
 4804        let project = self.project.as_ref()?;
 4805        let position = self.selections.newest_anchor().head();
 4806        let (buffer, buffer_position) = self
 4807            .buffer
 4808            .read(cx)
 4809            .text_anchor_for_position(position, cx)?;
 4810
 4811        let settings = language_settings::language_settings(
 4812            buffer
 4813                .read(cx)
 4814                .language_at(buffer_position)
 4815                .map(|l| l.name()),
 4816            buffer.read(cx).file(),
 4817            cx,
 4818        );
 4819        if !settings.use_on_type_format {
 4820            return None;
 4821        }
 4822
 4823        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4824        // hence we do LSP request & edit on host side only — add formats to host's history.
 4825        let push_to_lsp_host_history = true;
 4826        // If this is not the host, append its history with new edits.
 4827        let push_to_client_history = project.read(cx).is_via_collab();
 4828
 4829        let on_type_formatting = project.update(cx, |project, cx| {
 4830            project.on_type_format(
 4831                buffer.clone(),
 4832                buffer_position,
 4833                input,
 4834                push_to_lsp_host_history,
 4835                cx,
 4836            )
 4837        });
 4838        Some(cx.spawn_in(window, async move |editor, cx| {
 4839            if let Some(transaction) = on_type_formatting.await? {
 4840                if push_to_client_history {
 4841                    buffer
 4842                        .update(cx, |buffer, _| {
 4843                            buffer.push_transaction(transaction, Instant::now());
 4844                            buffer.finalize_last_transaction();
 4845                        })
 4846                        .ok();
 4847                }
 4848                editor.update(cx, |editor, cx| {
 4849                    editor.refresh_document_highlights(cx);
 4850                })?;
 4851            }
 4852            Ok(())
 4853        }))
 4854    }
 4855
 4856    pub fn show_word_completions(
 4857        &mut self,
 4858        _: &ShowWordCompletions,
 4859        window: &mut Window,
 4860        cx: &mut Context<Self>,
 4861    ) {
 4862        self.open_completions_menu(true, None, window, cx);
 4863    }
 4864
 4865    pub fn show_completions(
 4866        &mut self,
 4867        options: &ShowCompletions,
 4868        window: &mut Window,
 4869        cx: &mut Context<Self>,
 4870    ) {
 4871        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4872    }
 4873
 4874    fn open_completions_menu(
 4875        &mut self,
 4876        ignore_completion_provider: bool,
 4877        trigger: Option<&str>,
 4878        window: &mut Window,
 4879        cx: &mut Context<Self>,
 4880    ) {
 4881        if self.pending_rename.is_some() {
 4882            return;
 4883        }
 4884        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4885            return;
 4886        }
 4887
 4888        let position = self.selections.newest_anchor().head();
 4889        if position.diff_base_anchor.is_some() {
 4890            return;
 4891        }
 4892        let (buffer, buffer_position) =
 4893            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4894                output
 4895            } else {
 4896                return;
 4897            };
 4898        let buffer_snapshot = buffer.read(cx).snapshot();
 4899        let show_completion_documentation = buffer_snapshot
 4900            .settings_at(buffer_position, cx)
 4901            .show_completion_documentation;
 4902
 4903        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4904
 4905        let trigger_kind = match trigger {
 4906            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4907                CompletionTriggerKind::TRIGGER_CHARACTER
 4908            }
 4909            _ => CompletionTriggerKind::INVOKED,
 4910        };
 4911        let completion_context = CompletionContext {
 4912            trigger_character: trigger.and_then(|trigger| {
 4913                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4914                    Some(String::from(trigger))
 4915                } else {
 4916                    None
 4917                }
 4918            }),
 4919            trigger_kind,
 4920        };
 4921
 4922        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4923        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4924            let word_to_exclude = buffer_snapshot
 4925                .text_for_range(old_range.clone())
 4926                .collect::<String>();
 4927            (
 4928                buffer_snapshot.anchor_before(old_range.start)
 4929                    ..buffer_snapshot.anchor_after(old_range.end),
 4930                Some(word_to_exclude),
 4931            )
 4932        } else {
 4933            (buffer_position..buffer_position, None)
 4934        };
 4935
 4936        let completion_settings = language_settings(
 4937            buffer_snapshot
 4938                .language_at(buffer_position)
 4939                .map(|language| language.name()),
 4940            buffer_snapshot.file(),
 4941            cx,
 4942        )
 4943        .completions;
 4944
 4945        // The document can be large, so stay in reasonable bounds when searching for words,
 4946        // otherwise completion pop-up might be slow to appear.
 4947        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4948        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4949        let min_word_search = buffer_snapshot.clip_point(
 4950            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4951            Bias::Left,
 4952        );
 4953        let max_word_search = buffer_snapshot.clip_point(
 4954            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4955            Bias::Right,
 4956        );
 4957        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4958            ..buffer_snapshot.point_to_offset(max_word_search);
 4959
 4960        let provider = self
 4961            .completion_provider
 4962            .as_ref()
 4963            .filter(|_| !ignore_completion_provider);
 4964        let skip_digits = query
 4965            .as_ref()
 4966            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4967
 4968        let (mut words, provided_completions) = match provider {
 4969            Some(provider) => {
 4970                let completions = provider.completions(
 4971                    position.excerpt_id,
 4972                    &buffer,
 4973                    buffer_position,
 4974                    completion_context,
 4975                    window,
 4976                    cx,
 4977                );
 4978
 4979                let words = match completion_settings.words {
 4980                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4981                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4982                        .background_spawn(async move {
 4983                            buffer_snapshot.words_in_range(WordsQuery {
 4984                                fuzzy_contents: None,
 4985                                range: word_search_range,
 4986                                skip_digits,
 4987                            })
 4988                        }),
 4989                };
 4990
 4991                (words, completions)
 4992            }
 4993            None => (
 4994                cx.background_spawn(async move {
 4995                    buffer_snapshot.words_in_range(WordsQuery {
 4996                        fuzzy_contents: None,
 4997                        range: word_search_range,
 4998                        skip_digits,
 4999                    })
 5000                }),
 5001                Task::ready(Ok(None)),
 5002            ),
 5003        };
 5004
 5005        let sort_completions = provider
 5006            .as_ref()
 5007            .map_or(false, |provider| provider.sort_completions());
 5008
 5009        let filter_completions = provider
 5010            .as_ref()
 5011            .map_or(true, |provider| provider.filter_completions());
 5012
 5013        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5014
 5015        let id = post_inc(&mut self.next_completion_id);
 5016        let task = cx.spawn_in(window, async move |editor, cx| {
 5017            async move {
 5018                editor.update(cx, |this, _| {
 5019                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5020                })?;
 5021
 5022                let mut completions = Vec::new();
 5023                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5024                    completions.extend(provided_completions);
 5025                    if completion_settings.words == WordsCompletionMode::Fallback {
 5026                        words = Task::ready(BTreeMap::default());
 5027                    }
 5028                }
 5029
 5030                let mut words = words.await;
 5031                if let Some(word_to_exclude) = &word_to_exclude {
 5032                    words.remove(word_to_exclude);
 5033                }
 5034                for lsp_completion in &completions {
 5035                    words.remove(&lsp_completion.new_text);
 5036                }
 5037                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5038                    replace_range: old_range.clone(),
 5039                    new_text: word.clone(),
 5040                    label: CodeLabel::plain(word, None),
 5041                    icon_path: None,
 5042                    documentation: None,
 5043                    source: CompletionSource::BufferWord {
 5044                        word_range,
 5045                        resolved: false,
 5046                    },
 5047                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5048                    confirm: None,
 5049                }));
 5050
 5051                let menu = if completions.is_empty() {
 5052                    None
 5053                } else {
 5054                    let mut menu = CompletionsMenu::new(
 5055                        id,
 5056                        sort_completions,
 5057                        show_completion_documentation,
 5058                        ignore_completion_provider,
 5059                        position,
 5060                        buffer.clone(),
 5061                        completions.into(),
 5062                        snippet_sort_order,
 5063                    );
 5064
 5065                    menu.filter(
 5066                        if filter_completions {
 5067                            query.as_deref()
 5068                        } else {
 5069                            None
 5070                        },
 5071                        cx.background_executor().clone(),
 5072                    )
 5073                    .await;
 5074
 5075                    menu.visible().then_some(menu)
 5076                };
 5077
 5078                editor.update_in(cx, |editor, window, cx| {
 5079                    match editor.context_menu.borrow().as_ref() {
 5080                        None => {}
 5081                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5082                            if prev_menu.id > id {
 5083                                return;
 5084                            }
 5085                        }
 5086                        _ => return,
 5087                    }
 5088
 5089                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5090                        let mut menu = menu.unwrap();
 5091                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5092                        crate::hover_popover::hide_hover(editor, cx);
 5093                        *editor.context_menu.borrow_mut() =
 5094                            Some(CodeContextMenu::Completions(menu));
 5095
 5096                        if editor.show_edit_predictions_in_menu() {
 5097                            editor.update_visible_inline_completion(window, cx);
 5098                        } else {
 5099                            editor.discard_inline_completion(false, cx);
 5100                        }
 5101
 5102                        cx.notify();
 5103                    } else if editor.completion_tasks.len() <= 1 {
 5104                        // If there are no more completion tasks and the last menu was
 5105                        // empty, we should hide it.
 5106                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5107                        // If it was already hidden and we don't show inline
 5108                        // completions in the menu, we should also show the
 5109                        // inline-completion when available.
 5110                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5111                            editor.update_visible_inline_completion(window, cx);
 5112                        }
 5113                    }
 5114                })?;
 5115
 5116                anyhow::Ok(())
 5117            }
 5118            .log_err()
 5119            .await
 5120        });
 5121
 5122        self.completion_tasks.push((id, task));
 5123    }
 5124
 5125    #[cfg(feature = "test-support")]
 5126    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5127        let menu = self.context_menu.borrow();
 5128        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5129            let completions = menu.completions.borrow();
 5130            Some(completions.to_vec())
 5131        } else {
 5132            None
 5133        }
 5134    }
 5135
 5136    pub fn confirm_completion(
 5137        &mut self,
 5138        action: &ConfirmCompletion,
 5139        window: &mut Window,
 5140        cx: &mut Context<Self>,
 5141    ) -> Option<Task<Result<()>>> {
 5142        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5143        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5144    }
 5145
 5146    pub fn confirm_completion_insert(
 5147        &mut self,
 5148        _: &ConfirmCompletionInsert,
 5149        window: &mut Window,
 5150        cx: &mut Context<Self>,
 5151    ) -> Option<Task<Result<()>>> {
 5152        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5153        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5154    }
 5155
 5156    pub fn confirm_completion_replace(
 5157        &mut self,
 5158        _: &ConfirmCompletionReplace,
 5159        window: &mut Window,
 5160        cx: &mut Context<Self>,
 5161    ) -> Option<Task<Result<()>>> {
 5162        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5163        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5164    }
 5165
 5166    pub fn compose_completion(
 5167        &mut self,
 5168        action: &ComposeCompletion,
 5169        window: &mut Window,
 5170        cx: &mut Context<Self>,
 5171    ) -> Option<Task<Result<()>>> {
 5172        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5173        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5174    }
 5175
 5176    fn do_completion(
 5177        &mut self,
 5178        item_ix: Option<usize>,
 5179        intent: CompletionIntent,
 5180        window: &mut Window,
 5181        cx: &mut Context<Editor>,
 5182    ) -> Option<Task<Result<()>>> {
 5183        use language::ToOffset as _;
 5184
 5185        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5186        else {
 5187            return None;
 5188        };
 5189
 5190        let candidate_id = {
 5191            let entries = completions_menu.entries.borrow();
 5192            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5193            if self.show_edit_predictions_in_menu() {
 5194                self.discard_inline_completion(true, cx);
 5195            }
 5196            mat.candidate_id
 5197        };
 5198
 5199        let buffer_handle = completions_menu.buffer;
 5200        let completion = completions_menu
 5201            .completions
 5202            .borrow()
 5203            .get(candidate_id)?
 5204            .clone();
 5205        cx.stop_propagation();
 5206
 5207        let snapshot = self.buffer.read(cx).snapshot(cx);
 5208        let newest_anchor = self.selections.newest_anchor();
 5209
 5210        let snippet;
 5211        let new_text;
 5212        if completion.is_snippet() {
 5213            let mut snippet_source = completion.new_text.clone();
 5214            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5215                if scope.prefers_label_for_snippet_in_completion() {
 5216                    if let Some(label) = completion.label() {
 5217                        if matches!(
 5218                            completion.kind(),
 5219                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5220                        ) {
 5221                            snippet_source = label;
 5222                        }
 5223                    }
 5224                }
 5225            }
 5226            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5227            new_text = snippet.as_ref().unwrap().text.clone();
 5228        } else {
 5229            snippet = None;
 5230            new_text = completion.new_text.clone();
 5231        };
 5232
 5233        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5234        let buffer = buffer_handle.read(cx);
 5235        let replace_range_multibuffer = {
 5236            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5237            let multibuffer_anchor = snapshot
 5238                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5239                .unwrap()
 5240                ..snapshot
 5241                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5242                    .unwrap();
 5243            multibuffer_anchor.start.to_offset(&snapshot)
 5244                ..multibuffer_anchor.end.to_offset(&snapshot)
 5245        };
 5246        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5247            return None;
 5248        }
 5249
 5250        let old_text = buffer
 5251            .text_for_range(replace_range.clone())
 5252            .collect::<String>();
 5253        let lookbehind = newest_anchor
 5254            .start
 5255            .text_anchor
 5256            .to_offset(buffer)
 5257            .saturating_sub(replace_range.start);
 5258        let lookahead = replace_range
 5259            .end
 5260            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5261        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5262        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5263
 5264        let selections = self.selections.all::<usize>(cx);
 5265        let mut ranges = Vec::new();
 5266        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5267
 5268        for selection in &selections {
 5269            let range = if selection.id == newest_anchor.id {
 5270                replace_range_multibuffer.clone()
 5271            } else {
 5272                let mut range = selection.range();
 5273
 5274                // if prefix is present, don't duplicate it
 5275                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5276                    range.start = range.start.saturating_sub(lookbehind);
 5277
 5278                    // if suffix is also present, mimic the newest cursor and replace it
 5279                    if selection.id != newest_anchor.id
 5280                        && snapshot.contains_str_at(range.end, suffix)
 5281                    {
 5282                        range.end += lookahead;
 5283                    }
 5284                }
 5285                range
 5286            };
 5287
 5288            ranges.push(range.clone());
 5289
 5290            if !self.linked_edit_ranges.is_empty() {
 5291                let start_anchor = snapshot.anchor_before(range.start);
 5292                let end_anchor = snapshot.anchor_after(range.end);
 5293                if let Some(ranges) = self
 5294                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5295                {
 5296                    for (buffer, edits) in ranges {
 5297                        linked_edits
 5298                            .entry(buffer.clone())
 5299                            .or_default()
 5300                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5301                    }
 5302                }
 5303            }
 5304        }
 5305
 5306        cx.emit(EditorEvent::InputHandled {
 5307            utf16_range_to_replace: None,
 5308            text: new_text.clone().into(),
 5309        });
 5310
 5311        self.transact(window, cx, |this, window, cx| {
 5312            if let Some(mut snippet) = snippet {
 5313                snippet.text = new_text.to_string();
 5314                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5315            } else {
 5316                this.buffer.update(cx, |buffer, cx| {
 5317                    let auto_indent = match completion.insert_text_mode {
 5318                        Some(InsertTextMode::AS_IS) => None,
 5319                        _ => this.autoindent_mode.clone(),
 5320                    };
 5321                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5322                    buffer.edit(edits, auto_indent, cx);
 5323                });
 5324            }
 5325            for (buffer, edits) in linked_edits {
 5326                buffer.update(cx, |buffer, cx| {
 5327                    let snapshot = buffer.snapshot();
 5328                    let edits = edits
 5329                        .into_iter()
 5330                        .map(|(range, text)| {
 5331                            use text::ToPoint as TP;
 5332                            let end_point = TP::to_point(&range.end, &snapshot);
 5333                            let start_point = TP::to_point(&range.start, &snapshot);
 5334                            (start_point..end_point, text)
 5335                        })
 5336                        .sorted_by_key(|(range, _)| range.start);
 5337                    buffer.edit(edits, None, cx);
 5338                })
 5339            }
 5340
 5341            this.refresh_inline_completion(true, false, window, cx);
 5342        });
 5343
 5344        let show_new_completions_on_confirm = completion
 5345            .confirm
 5346            .as_ref()
 5347            .map_or(false, |confirm| confirm(intent, window, cx));
 5348        if show_new_completions_on_confirm {
 5349            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5350        }
 5351
 5352        let provider = self.completion_provider.as_ref()?;
 5353        drop(completion);
 5354        let apply_edits = provider.apply_additional_edits_for_completion(
 5355            buffer_handle,
 5356            completions_menu.completions.clone(),
 5357            candidate_id,
 5358            true,
 5359            cx,
 5360        );
 5361
 5362        let editor_settings = EditorSettings::get_global(cx);
 5363        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5364            // After the code completion is finished, users often want to know what signatures are needed.
 5365            // so we should automatically call signature_help
 5366            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5367        }
 5368
 5369        Some(cx.foreground_executor().spawn(async move {
 5370            apply_edits.await?;
 5371            Ok(())
 5372        }))
 5373    }
 5374
 5375    pub fn toggle_code_actions(
 5376        &mut self,
 5377        action: &ToggleCodeActions,
 5378        window: &mut Window,
 5379        cx: &mut Context<Self>,
 5380    ) {
 5381        let quick_launch = action.quick_launch;
 5382        let mut context_menu = self.context_menu.borrow_mut();
 5383        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5384            if code_actions.deployed_from == action.deployed_from {
 5385                // Toggle if we're selecting the same one
 5386                *context_menu = None;
 5387                cx.notify();
 5388                return;
 5389            } else {
 5390                // Otherwise, clear it and start a new one
 5391                *context_menu = None;
 5392                cx.notify();
 5393            }
 5394        }
 5395        drop(context_menu);
 5396        let snapshot = self.snapshot(window, cx);
 5397        let deployed_from = action.deployed_from.clone();
 5398        let mut task = self.code_actions_task.take();
 5399        let action = action.clone();
 5400        cx.spawn_in(window, async move |editor, cx| {
 5401            while let Some(prev_task) = task {
 5402                prev_task.await.log_err();
 5403                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5404            }
 5405
 5406            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5407                if editor.focus_handle.is_focused(window) {
 5408                    let multibuffer_point = match &action.deployed_from {
 5409                        Some(CodeActionSource::Indicator(row)) => {
 5410                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5411                        }
 5412                        _ => editor.selections.newest::<Point>(cx).head(),
 5413                    };
 5414                    let (buffer, buffer_row) = snapshot
 5415                        .buffer_snapshot
 5416                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5417                        .and_then(|(buffer_snapshot, range)| {
 5418                            editor
 5419                                .buffer
 5420                                .read(cx)
 5421                                .buffer(buffer_snapshot.remote_id())
 5422                                .map(|buffer| (buffer, range.start.row))
 5423                        })?;
 5424                    let (_, code_actions) = editor
 5425                        .available_code_actions
 5426                        .clone()
 5427                        .and_then(|(location, code_actions)| {
 5428                            let snapshot = location.buffer.read(cx).snapshot();
 5429                            let point_range = location.range.to_point(&snapshot);
 5430                            let point_range = point_range.start.row..=point_range.end.row;
 5431                            if point_range.contains(&buffer_row) {
 5432                                Some((location, code_actions))
 5433                            } else {
 5434                                None
 5435                            }
 5436                        })
 5437                        .unzip();
 5438                    let buffer_id = buffer.read(cx).remote_id();
 5439                    let tasks = editor
 5440                        .tasks
 5441                        .get(&(buffer_id, buffer_row))
 5442                        .map(|t| Arc::new(t.to_owned()));
 5443                    if tasks.is_none() && code_actions.is_none() {
 5444                        return None;
 5445                    }
 5446
 5447                    editor.completion_tasks.clear();
 5448                    editor.discard_inline_completion(false, cx);
 5449                    let task_context =
 5450                        tasks
 5451                            .as_ref()
 5452                            .zip(editor.project.clone())
 5453                            .map(|(tasks, project)| {
 5454                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5455                            });
 5456
 5457                    Some(cx.spawn_in(window, async move |editor, cx| {
 5458                        let task_context = match task_context {
 5459                            Some(task_context) => task_context.await,
 5460                            None => None,
 5461                        };
 5462                        let resolved_tasks =
 5463                            tasks
 5464                                .zip(task_context.clone())
 5465                                .map(|(tasks, task_context)| ResolvedTasks {
 5466                                    templates: tasks.resolve(&task_context).collect(),
 5467                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5468                                        multibuffer_point.row,
 5469                                        tasks.column,
 5470                                    )),
 5471                                });
 5472                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5473                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5474                                maybe!({
 5475                                    let project = editor.project.as_ref()?;
 5476                                    let dap_store = project.read(cx).dap_store();
 5477                                    let mut scenarios = vec![];
 5478                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5479                                    let buffer = buffer.read(cx);
 5480                                    let language = buffer.language()?;
 5481                                    let file = buffer.file();
 5482                                    let debug_adapter =
 5483                                        language_settings(language.name().into(), file, cx)
 5484                                            .debuggers
 5485                                            .first()
 5486                                            .map(SharedString::from)
 5487                                            .or_else(|| {
 5488                                                language
 5489                                                    .config()
 5490                                                    .debuggers
 5491                                                    .first()
 5492                                                    .map(SharedString::from)
 5493                                            })?;
 5494
 5495                                    dap_store.update(cx, |dap_store, cx| {
 5496                                        for (_, task) in &resolved_tasks.templates {
 5497                                            if let Some(scenario) = dap_store
 5498                                                .debug_scenario_for_build_task(
 5499                                                    task.original_task().clone(),
 5500                                                    debug_adapter.clone().into(),
 5501                                                    task.display_label().to_owned().into(),
 5502                                                    cx,
 5503                                                )
 5504                                            {
 5505                                                scenarios.push(scenario);
 5506                                            }
 5507                                        }
 5508                                    });
 5509                                    Some(scenarios)
 5510                                })
 5511                                .unwrap_or_default()
 5512                            } else {
 5513                                vec![]
 5514                            }
 5515                        })?;
 5516                        let spawn_straight_away = quick_launch
 5517                            && resolved_tasks
 5518                                .as_ref()
 5519                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5520                            && code_actions
 5521                                .as_ref()
 5522                                .map_or(true, |actions| actions.is_empty())
 5523                            && debug_scenarios.is_empty();
 5524                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5525                            crate::hover_popover::hide_hover(editor, cx);
 5526                            *editor.context_menu.borrow_mut() =
 5527                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5528                                    buffer,
 5529                                    actions: CodeActionContents::new(
 5530                                        resolved_tasks,
 5531                                        code_actions,
 5532                                        debug_scenarios,
 5533                                        task_context.unwrap_or_default(),
 5534                                    ),
 5535                                    selected_item: Default::default(),
 5536                                    scroll_handle: UniformListScrollHandle::default(),
 5537                                    deployed_from,
 5538                                }));
 5539                            if spawn_straight_away {
 5540                                if let Some(task) = editor.confirm_code_action(
 5541                                    &ConfirmCodeAction { item_ix: Some(0) },
 5542                                    window,
 5543                                    cx,
 5544                                ) {
 5545                                    cx.notify();
 5546                                    return task;
 5547                                }
 5548                            }
 5549                            cx.notify();
 5550                            Task::ready(Ok(()))
 5551                        }) {
 5552                            task.await
 5553                        } else {
 5554                            Ok(())
 5555                        }
 5556                    }))
 5557                } else {
 5558                    Some(Task::ready(Ok(())))
 5559                }
 5560            })?;
 5561            if let Some(task) = spawned_test_task {
 5562                task.await?;
 5563            }
 5564
 5565            anyhow::Ok(())
 5566        })
 5567        .detach_and_log_err(cx);
 5568    }
 5569
 5570    pub fn confirm_code_action(
 5571        &mut self,
 5572        action: &ConfirmCodeAction,
 5573        window: &mut Window,
 5574        cx: &mut Context<Self>,
 5575    ) -> Option<Task<Result<()>>> {
 5576        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5577
 5578        let actions_menu =
 5579            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5580                menu
 5581            } else {
 5582                return None;
 5583            };
 5584
 5585        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5586        let action = actions_menu.actions.get(action_ix)?;
 5587        let title = action.label();
 5588        let buffer = actions_menu.buffer;
 5589        let workspace = self.workspace()?;
 5590
 5591        match action {
 5592            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5593                workspace.update(cx, |workspace, cx| {
 5594                    workspace.schedule_resolved_task(
 5595                        task_source_kind,
 5596                        resolved_task,
 5597                        false,
 5598                        window,
 5599                        cx,
 5600                    );
 5601
 5602                    Some(Task::ready(Ok(())))
 5603                })
 5604            }
 5605            CodeActionsItem::CodeAction {
 5606                excerpt_id,
 5607                action,
 5608                provider,
 5609            } => {
 5610                let apply_code_action =
 5611                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5612                let workspace = workspace.downgrade();
 5613                Some(cx.spawn_in(window, async move |editor, cx| {
 5614                    let project_transaction = apply_code_action.await?;
 5615                    Self::open_project_transaction(
 5616                        &editor,
 5617                        workspace,
 5618                        project_transaction,
 5619                        title,
 5620                        cx,
 5621                    )
 5622                    .await
 5623                }))
 5624            }
 5625            CodeActionsItem::DebugScenario(scenario) => {
 5626                let context = actions_menu.actions.context.clone();
 5627
 5628                workspace.update(cx, |workspace, cx| {
 5629                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5630                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5631                });
 5632                Some(Task::ready(Ok(())))
 5633            }
 5634        }
 5635    }
 5636
 5637    pub async fn open_project_transaction(
 5638        this: &WeakEntity<Editor>,
 5639        workspace: WeakEntity<Workspace>,
 5640        transaction: ProjectTransaction,
 5641        title: String,
 5642        cx: &mut AsyncWindowContext,
 5643    ) -> Result<()> {
 5644        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5645        cx.update(|_, cx| {
 5646            entries.sort_unstable_by_key(|(buffer, _)| {
 5647                buffer.read(cx).file().map(|f| f.path().clone())
 5648            });
 5649        })?;
 5650
 5651        // If the project transaction's edits are all contained within this editor, then
 5652        // avoid opening a new editor to display them.
 5653
 5654        if let Some((buffer, transaction)) = entries.first() {
 5655            if entries.len() == 1 {
 5656                let excerpt = this.update(cx, |editor, cx| {
 5657                    editor
 5658                        .buffer()
 5659                        .read(cx)
 5660                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5661                })?;
 5662                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5663                    if excerpted_buffer == *buffer {
 5664                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5665                            let excerpt_range = excerpt_range.to_offset(buffer);
 5666                            buffer
 5667                                .edited_ranges_for_transaction::<usize>(transaction)
 5668                                .all(|range| {
 5669                                    excerpt_range.start <= range.start
 5670                                        && excerpt_range.end >= range.end
 5671                                })
 5672                        })?;
 5673
 5674                        if all_edits_within_excerpt {
 5675                            return Ok(());
 5676                        }
 5677                    }
 5678                }
 5679            }
 5680        } else {
 5681            return Ok(());
 5682        }
 5683
 5684        let mut ranges_to_highlight = Vec::new();
 5685        let excerpt_buffer = cx.new(|cx| {
 5686            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5687            for (buffer_handle, transaction) in &entries {
 5688                let edited_ranges = buffer_handle
 5689                    .read(cx)
 5690                    .edited_ranges_for_transaction::<Point>(transaction)
 5691                    .collect::<Vec<_>>();
 5692                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5693                    PathKey::for_buffer(buffer_handle, cx),
 5694                    buffer_handle.clone(),
 5695                    edited_ranges,
 5696                    DEFAULT_MULTIBUFFER_CONTEXT,
 5697                    cx,
 5698                );
 5699
 5700                ranges_to_highlight.extend(ranges);
 5701            }
 5702            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5703            multibuffer
 5704        })?;
 5705
 5706        workspace.update_in(cx, |workspace, window, cx| {
 5707            let project = workspace.project().clone();
 5708            let editor =
 5709                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5710            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5711            editor.update(cx, |editor, cx| {
 5712                editor.highlight_background::<Self>(
 5713                    &ranges_to_highlight,
 5714                    |theme| theme.editor_highlighted_line_background,
 5715                    cx,
 5716                );
 5717            });
 5718        })?;
 5719
 5720        Ok(())
 5721    }
 5722
 5723    pub fn clear_code_action_providers(&mut self) {
 5724        self.code_action_providers.clear();
 5725        self.available_code_actions.take();
 5726    }
 5727
 5728    pub fn add_code_action_provider(
 5729        &mut self,
 5730        provider: Rc<dyn CodeActionProvider>,
 5731        window: &mut Window,
 5732        cx: &mut Context<Self>,
 5733    ) {
 5734        if self
 5735            .code_action_providers
 5736            .iter()
 5737            .any(|existing_provider| existing_provider.id() == provider.id())
 5738        {
 5739            return;
 5740        }
 5741
 5742        self.code_action_providers.push(provider);
 5743        self.refresh_code_actions(window, cx);
 5744    }
 5745
 5746    pub fn remove_code_action_provider(
 5747        &mut self,
 5748        id: Arc<str>,
 5749        window: &mut Window,
 5750        cx: &mut Context<Self>,
 5751    ) {
 5752        self.code_action_providers
 5753            .retain(|provider| provider.id() != id);
 5754        self.refresh_code_actions(window, cx);
 5755    }
 5756
 5757    pub fn code_actions_enabled(&self, cx: &App) -> bool {
 5758        !self.code_action_providers.is_empty()
 5759            && EditorSettings::get_global(cx).toolbar.code_actions
 5760    }
 5761
 5762    pub fn has_available_code_actions(&self) -> bool {
 5763        self.available_code_actions
 5764            .as_ref()
 5765            .is_some_and(|(_, actions)| !actions.is_empty())
 5766    }
 5767
 5768    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 5769        &self.context_menu
 5770    }
 5771
 5772    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5773        let newest_selection = self.selections.newest_anchor().clone();
 5774        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5775        let buffer = self.buffer.read(cx);
 5776        if newest_selection.head().diff_base_anchor.is_some() {
 5777            return None;
 5778        }
 5779        let (start_buffer, start) =
 5780            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5781        let (end_buffer, end) =
 5782            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5783        if start_buffer != end_buffer {
 5784            return None;
 5785        }
 5786
 5787        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5788            cx.background_executor()
 5789                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5790                .await;
 5791
 5792            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5793                let providers = this.code_action_providers.clone();
 5794                let tasks = this
 5795                    .code_action_providers
 5796                    .iter()
 5797                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5798                    .collect::<Vec<_>>();
 5799                (providers, tasks)
 5800            })?;
 5801
 5802            let mut actions = Vec::new();
 5803            for (provider, provider_actions) in
 5804                providers.into_iter().zip(future::join_all(tasks).await)
 5805            {
 5806                if let Some(provider_actions) = provider_actions.log_err() {
 5807                    actions.extend(provider_actions.into_iter().map(|action| {
 5808                        AvailableCodeAction {
 5809                            excerpt_id: newest_selection.start.excerpt_id,
 5810                            action,
 5811                            provider: provider.clone(),
 5812                        }
 5813                    }));
 5814                }
 5815            }
 5816
 5817            this.update(cx, |this, cx| {
 5818                this.available_code_actions = if actions.is_empty() {
 5819                    None
 5820                } else {
 5821                    Some((
 5822                        Location {
 5823                            buffer: start_buffer,
 5824                            range: start..end,
 5825                        },
 5826                        actions.into(),
 5827                    ))
 5828                };
 5829                cx.notify();
 5830            })
 5831        }));
 5832        None
 5833    }
 5834
 5835    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5836        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5837            self.show_git_blame_inline = false;
 5838
 5839            self.show_git_blame_inline_delay_task =
 5840                Some(cx.spawn_in(window, async move |this, cx| {
 5841                    cx.background_executor().timer(delay).await;
 5842
 5843                    this.update(cx, |this, cx| {
 5844                        this.show_git_blame_inline = true;
 5845                        cx.notify();
 5846                    })
 5847                    .log_err();
 5848                }));
 5849        }
 5850    }
 5851
 5852    fn show_blame_popover(
 5853        &mut self,
 5854        blame_entry: &BlameEntry,
 5855        position: gpui::Point<Pixels>,
 5856        cx: &mut Context<Self>,
 5857    ) {
 5858        if let Some(state) = &mut self.inline_blame_popover {
 5859            state.hide_task.take();
 5860            cx.notify();
 5861        } else {
 5862            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5863            let show_task = cx.spawn(async move |editor, cx| {
 5864                cx.background_executor()
 5865                    .timer(std::time::Duration::from_millis(delay))
 5866                    .await;
 5867                editor
 5868                    .update(cx, |editor, cx| {
 5869                        if let Some(state) = &mut editor.inline_blame_popover {
 5870                            state.show_task = None;
 5871                            cx.notify();
 5872                        }
 5873                    })
 5874                    .ok();
 5875            });
 5876            let Some(blame) = self.blame.as_ref() else {
 5877                return;
 5878            };
 5879            let blame = blame.read(cx);
 5880            let details = blame.details_for_entry(&blame_entry);
 5881            let markdown = cx.new(|cx| {
 5882                Markdown::new(
 5883                    details
 5884                        .as_ref()
 5885                        .map(|message| message.message.clone())
 5886                        .unwrap_or_default(),
 5887                    None,
 5888                    None,
 5889                    cx,
 5890                )
 5891            });
 5892            self.inline_blame_popover = Some(InlineBlamePopover {
 5893                position,
 5894                show_task: Some(show_task),
 5895                hide_task: None,
 5896                popover_bounds: None,
 5897                popover_state: InlineBlamePopoverState {
 5898                    scroll_handle: ScrollHandle::new(),
 5899                    commit_message: details,
 5900                    markdown,
 5901                },
 5902            });
 5903        }
 5904    }
 5905
 5906    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5907        if let Some(state) = &mut self.inline_blame_popover {
 5908            if state.show_task.is_some() {
 5909                self.inline_blame_popover.take();
 5910                cx.notify();
 5911            } else {
 5912                let hide_task = cx.spawn(async move |editor, cx| {
 5913                    cx.background_executor()
 5914                        .timer(std::time::Duration::from_millis(100))
 5915                        .await;
 5916                    editor
 5917                        .update(cx, |editor, cx| {
 5918                            editor.inline_blame_popover.take();
 5919                            cx.notify();
 5920                        })
 5921                        .ok();
 5922                });
 5923                state.hide_task = Some(hide_task);
 5924            }
 5925        }
 5926    }
 5927
 5928    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5929        if self.pending_rename.is_some() {
 5930            return None;
 5931        }
 5932
 5933        let provider = self.semantics_provider.clone()?;
 5934        let buffer = self.buffer.read(cx);
 5935        let newest_selection = self.selections.newest_anchor().clone();
 5936        let cursor_position = newest_selection.head();
 5937        let (cursor_buffer, cursor_buffer_position) =
 5938            buffer.text_anchor_for_position(cursor_position, cx)?;
 5939        let (tail_buffer, tail_buffer_position) =
 5940            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5941        if cursor_buffer != tail_buffer {
 5942            return None;
 5943        }
 5944
 5945        let snapshot = cursor_buffer.read(cx).snapshot();
 5946        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5947        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5948        if start_word_range != end_word_range {
 5949            self.document_highlights_task.take();
 5950            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5951            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5952            return None;
 5953        }
 5954
 5955        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5956        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5957            cx.background_executor()
 5958                .timer(Duration::from_millis(debounce))
 5959                .await;
 5960
 5961            let highlights = if let Some(highlights) = cx
 5962                .update(|cx| {
 5963                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5964                })
 5965                .ok()
 5966                .flatten()
 5967            {
 5968                highlights.await.log_err()
 5969            } else {
 5970                None
 5971            };
 5972
 5973            if let Some(highlights) = highlights {
 5974                this.update(cx, |this, cx| {
 5975                    if this.pending_rename.is_some() {
 5976                        return;
 5977                    }
 5978
 5979                    let buffer_id = cursor_position.buffer_id;
 5980                    let buffer = this.buffer.read(cx);
 5981                    if !buffer
 5982                        .text_anchor_for_position(cursor_position, cx)
 5983                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5984                    {
 5985                        return;
 5986                    }
 5987
 5988                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5989                    let mut write_ranges = Vec::new();
 5990                    let mut read_ranges = Vec::new();
 5991                    for highlight in highlights {
 5992                        for (excerpt_id, excerpt_range) in
 5993                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5994                        {
 5995                            let start = highlight
 5996                                .range
 5997                                .start
 5998                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5999                            let end = highlight
 6000                                .range
 6001                                .end
 6002                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6003                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6004                                continue;
 6005                            }
 6006
 6007                            let range = Anchor {
 6008                                buffer_id,
 6009                                excerpt_id,
 6010                                text_anchor: start,
 6011                                diff_base_anchor: None,
 6012                            }..Anchor {
 6013                                buffer_id,
 6014                                excerpt_id,
 6015                                text_anchor: end,
 6016                                diff_base_anchor: None,
 6017                            };
 6018                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6019                                write_ranges.push(range);
 6020                            } else {
 6021                                read_ranges.push(range);
 6022                            }
 6023                        }
 6024                    }
 6025
 6026                    this.highlight_background::<DocumentHighlightRead>(
 6027                        &read_ranges,
 6028                        |theme| theme.editor_document_highlight_read_background,
 6029                        cx,
 6030                    );
 6031                    this.highlight_background::<DocumentHighlightWrite>(
 6032                        &write_ranges,
 6033                        |theme| theme.editor_document_highlight_write_background,
 6034                        cx,
 6035                    );
 6036                    cx.notify();
 6037                })
 6038                .log_err();
 6039            }
 6040        }));
 6041        None
 6042    }
 6043
 6044    fn prepare_highlight_query_from_selection(
 6045        &mut self,
 6046        cx: &mut Context<Editor>,
 6047    ) -> Option<(String, Range<Anchor>)> {
 6048        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6049            return None;
 6050        }
 6051        if !EditorSettings::get_global(cx).selection_highlight {
 6052            return None;
 6053        }
 6054        if self.selections.count() != 1 || self.selections.line_mode {
 6055            return None;
 6056        }
 6057        let selection = self.selections.newest::<Point>(cx);
 6058        if selection.is_empty() || selection.start.row != selection.end.row {
 6059            return None;
 6060        }
 6061        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6062        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6063        let query = multi_buffer_snapshot
 6064            .text_for_range(selection_anchor_range.clone())
 6065            .collect::<String>();
 6066        if query.trim().is_empty() {
 6067            return None;
 6068        }
 6069        Some((query, selection_anchor_range))
 6070    }
 6071
 6072    fn update_selection_occurrence_highlights(
 6073        &mut self,
 6074        query_text: String,
 6075        query_range: Range<Anchor>,
 6076        multi_buffer_range_to_query: Range<Point>,
 6077        use_debounce: bool,
 6078        window: &mut Window,
 6079        cx: &mut Context<Editor>,
 6080    ) -> Task<()> {
 6081        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6082        cx.spawn_in(window, async move |editor, cx| {
 6083            if use_debounce {
 6084                cx.background_executor()
 6085                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6086                    .await;
 6087            }
 6088            let match_task = cx.background_spawn(async move {
 6089                let buffer_ranges = multi_buffer_snapshot
 6090                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6091                    .into_iter()
 6092                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6093                let mut match_ranges = Vec::new();
 6094                let Ok(regex) = project::search::SearchQuery::text(
 6095                    query_text.clone(),
 6096                    false,
 6097                    false,
 6098                    false,
 6099                    Default::default(),
 6100                    Default::default(),
 6101                    false,
 6102                    None,
 6103                ) else {
 6104                    return Vec::default();
 6105                };
 6106                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6107                    match_ranges.extend(
 6108                        regex
 6109                            .search(&buffer_snapshot, Some(search_range.clone()))
 6110                            .await
 6111                            .into_iter()
 6112                            .filter_map(|match_range| {
 6113                                let match_start = buffer_snapshot
 6114                                    .anchor_after(search_range.start + match_range.start);
 6115                                let match_end = buffer_snapshot
 6116                                    .anchor_before(search_range.start + match_range.end);
 6117                                let match_anchor_range = Anchor::range_in_buffer(
 6118                                    excerpt_id,
 6119                                    buffer_snapshot.remote_id(),
 6120                                    match_start..match_end,
 6121                                );
 6122                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6123                            }),
 6124                    );
 6125                }
 6126                match_ranges
 6127            });
 6128            let match_ranges = match_task.await;
 6129            editor
 6130                .update_in(cx, |editor, _, cx| {
 6131                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6132                    if !match_ranges.is_empty() {
 6133                        editor.highlight_background::<SelectedTextHighlight>(
 6134                            &match_ranges,
 6135                            |theme| theme.editor_document_highlight_bracket_background,
 6136                            cx,
 6137                        )
 6138                    }
 6139                })
 6140                .log_err();
 6141        })
 6142    }
 6143
 6144    fn refresh_selected_text_highlights(
 6145        &mut self,
 6146        on_buffer_edit: bool,
 6147        window: &mut Window,
 6148        cx: &mut Context<Editor>,
 6149    ) {
 6150        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6151        else {
 6152            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6153            self.quick_selection_highlight_task.take();
 6154            self.debounced_selection_highlight_task.take();
 6155            return;
 6156        };
 6157        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6158        if on_buffer_edit
 6159            || self
 6160                .quick_selection_highlight_task
 6161                .as_ref()
 6162                .map_or(true, |(prev_anchor_range, _)| {
 6163                    prev_anchor_range != &query_range
 6164                })
 6165        {
 6166            let multi_buffer_visible_start = self
 6167                .scroll_manager
 6168                .anchor()
 6169                .anchor
 6170                .to_point(&multi_buffer_snapshot);
 6171            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6172                multi_buffer_visible_start
 6173                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6174                Bias::Left,
 6175            );
 6176            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6177            self.quick_selection_highlight_task = Some((
 6178                query_range.clone(),
 6179                self.update_selection_occurrence_highlights(
 6180                    query_text.clone(),
 6181                    query_range.clone(),
 6182                    multi_buffer_visible_range,
 6183                    false,
 6184                    window,
 6185                    cx,
 6186                ),
 6187            ));
 6188        }
 6189        if on_buffer_edit
 6190            || self
 6191                .debounced_selection_highlight_task
 6192                .as_ref()
 6193                .map_or(true, |(prev_anchor_range, _)| {
 6194                    prev_anchor_range != &query_range
 6195                })
 6196        {
 6197            let multi_buffer_start = multi_buffer_snapshot
 6198                .anchor_before(0)
 6199                .to_point(&multi_buffer_snapshot);
 6200            let multi_buffer_end = multi_buffer_snapshot
 6201                .anchor_after(multi_buffer_snapshot.len())
 6202                .to_point(&multi_buffer_snapshot);
 6203            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6204            self.debounced_selection_highlight_task = Some((
 6205                query_range.clone(),
 6206                self.update_selection_occurrence_highlights(
 6207                    query_text,
 6208                    query_range,
 6209                    multi_buffer_full_range,
 6210                    true,
 6211                    window,
 6212                    cx,
 6213                ),
 6214            ));
 6215        }
 6216    }
 6217
 6218    pub fn refresh_inline_completion(
 6219        &mut self,
 6220        debounce: bool,
 6221        user_requested: bool,
 6222        window: &mut Window,
 6223        cx: &mut Context<Self>,
 6224    ) -> Option<()> {
 6225        let provider = self.edit_prediction_provider()?;
 6226        let cursor = self.selections.newest_anchor().head();
 6227        let (buffer, cursor_buffer_position) =
 6228            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6229
 6230        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6231            self.discard_inline_completion(false, cx);
 6232            return None;
 6233        }
 6234
 6235        if !user_requested
 6236            && (!self.should_show_edit_predictions()
 6237                || !self.is_focused(window)
 6238                || buffer.read(cx).is_empty())
 6239        {
 6240            self.discard_inline_completion(false, cx);
 6241            return None;
 6242        }
 6243
 6244        self.update_visible_inline_completion(window, cx);
 6245        provider.refresh(
 6246            self.project.clone(),
 6247            buffer,
 6248            cursor_buffer_position,
 6249            debounce,
 6250            cx,
 6251        );
 6252        Some(())
 6253    }
 6254
 6255    fn show_edit_predictions_in_menu(&self) -> bool {
 6256        match self.edit_prediction_settings {
 6257            EditPredictionSettings::Disabled => false,
 6258            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6259        }
 6260    }
 6261
 6262    pub fn edit_predictions_enabled(&self) -> bool {
 6263        match self.edit_prediction_settings {
 6264            EditPredictionSettings::Disabled => false,
 6265            EditPredictionSettings::Enabled { .. } => true,
 6266        }
 6267    }
 6268
 6269    fn edit_prediction_requires_modifier(&self) -> bool {
 6270        match self.edit_prediction_settings {
 6271            EditPredictionSettings::Disabled => false,
 6272            EditPredictionSettings::Enabled {
 6273                preview_requires_modifier,
 6274                ..
 6275            } => preview_requires_modifier,
 6276        }
 6277    }
 6278
 6279    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6280        if self.edit_prediction_provider.is_none() {
 6281            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6282        } else {
 6283            let selection = self.selections.newest_anchor();
 6284            let cursor = selection.head();
 6285
 6286            if let Some((buffer, cursor_buffer_position)) =
 6287                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6288            {
 6289                self.edit_prediction_settings =
 6290                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6291            }
 6292        }
 6293    }
 6294
 6295    fn edit_prediction_settings_at_position(
 6296        &self,
 6297        buffer: &Entity<Buffer>,
 6298        buffer_position: language::Anchor,
 6299        cx: &App,
 6300    ) -> EditPredictionSettings {
 6301        if !self.mode.is_full()
 6302            || !self.show_inline_completions_override.unwrap_or(true)
 6303            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6304        {
 6305            return EditPredictionSettings::Disabled;
 6306        }
 6307
 6308        let buffer = buffer.read(cx);
 6309
 6310        let file = buffer.file();
 6311
 6312        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6313            return EditPredictionSettings::Disabled;
 6314        };
 6315
 6316        let by_provider = matches!(
 6317            self.menu_inline_completions_policy,
 6318            MenuInlineCompletionsPolicy::ByProvider
 6319        );
 6320
 6321        let show_in_menu = by_provider
 6322            && self
 6323                .edit_prediction_provider
 6324                .as_ref()
 6325                .map_or(false, |provider| {
 6326                    provider.provider.show_completions_in_menu()
 6327                });
 6328
 6329        let preview_requires_modifier =
 6330            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6331
 6332        EditPredictionSettings::Enabled {
 6333            show_in_menu,
 6334            preview_requires_modifier,
 6335        }
 6336    }
 6337
 6338    fn should_show_edit_predictions(&self) -> bool {
 6339        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6340    }
 6341
 6342    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6343        matches!(
 6344            self.edit_prediction_preview,
 6345            EditPredictionPreview::Active { .. }
 6346        )
 6347    }
 6348
 6349    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6350        let cursor = self.selections.newest_anchor().head();
 6351        if let Some((buffer, cursor_position)) =
 6352            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6353        {
 6354            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6355        } else {
 6356            false
 6357        }
 6358    }
 6359
 6360    pub fn supports_minimap(&self, cx: &App) -> bool {
 6361        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6362    }
 6363
 6364    fn edit_predictions_enabled_in_buffer(
 6365        &self,
 6366        buffer: &Entity<Buffer>,
 6367        buffer_position: language::Anchor,
 6368        cx: &App,
 6369    ) -> bool {
 6370        maybe!({
 6371            if self.read_only(cx) {
 6372                return Some(false);
 6373            }
 6374            let provider = self.edit_prediction_provider()?;
 6375            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6376                return Some(false);
 6377            }
 6378            let buffer = buffer.read(cx);
 6379            let Some(file) = buffer.file() else {
 6380                return Some(true);
 6381            };
 6382            let settings = all_language_settings(Some(file), cx);
 6383            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6384        })
 6385        .unwrap_or(false)
 6386    }
 6387
 6388    fn cycle_inline_completion(
 6389        &mut self,
 6390        direction: Direction,
 6391        window: &mut Window,
 6392        cx: &mut Context<Self>,
 6393    ) -> Option<()> {
 6394        let provider = self.edit_prediction_provider()?;
 6395        let cursor = self.selections.newest_anchor().head();
 6396        let (buffer, cursor_buffer_position) =
 6397            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6398        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6399            return None;
 6400        }
 6401
 6402        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6403        self.update_visible_inline_completion(window, cx);
 6404
 6405        Some(())
 6406    }
 6407
 6408    pub fn show_inline_completion(
 6409        &mut self,
 6410        _: &ShowEditPrediction,
 6411        window: &mut Window,
 6412        cx: &mut Context<Self>,
 6413    ) {
 6414        if !self.has_active_inline_completion() {
 6415            self.refresh_inline_completion(false, true, window, cx);
 6416            return;
 6417        }
 6418
 6419        self.update_visible_inline_completion(window, cx);
 6420    }
 6421
 6422    pub fn display_cursor_names(
 6423        &mut self,
 6424        _: &DisplayCursorNames,
 6425        window: &mut Window,
 6426        cx: &mut Context<Self>,
 6427    ) {
 6428        self.show_cursor_names(window, cx);
 6429    }
 6430
 6431    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6432        self.show_cursor_names = true;
 6433        cx.notify();
 6434        cx.spawn_in(window, async move |this, cx| {
 6435            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6436            this.update(cx, |this, cx| {
 6437                this.show_cursor_names = false;
 6438                cx.notify()
 6439            })
 6440            .ok()
 6441        })
 6442        .detach();
 6443    }
 6444
 6445    pub fn next_edit_prediction(
 6446        &mut self,
 6447        _: &NextEditPrediction,
 6448        window: &mut Window,
 6449        cx: &mut Context<Self>,
 6450    ) {
 6451        if self.has_active_inline_completion() {
 6452            self.cycle_inline_completion(Direction::Next, window, cx);
 6453        } else {
 6454            let is_copilot_disabled = self
 6455                .refresh_inline_completion(false, true, window, cx)
 6456                .is_none();
 6457            if is_copilot_disabled {
 6458                cx.propagate();
 6459            }
 6460        }
 6461    }
 6462
 6463    pub fn previous_edit_prediction(
 6464        &mut self,
 6465        _: &PreviousEditPrediction,
 6466        window: &mut Window,
 6467        cx: &mut Context<Self>,
 6468    ) {
 6469        if self.has_active_inline_completion() {
 6470            self.cycle_inline_completion(Direction::Prev, window, cx);
 6471        } else {
 6472            let is_copilot_disabled = self
 6473                .refresh_inline_completion(false, true, window, cx)
 6474                .is_none();
 6475            if is_copilot_disabled {
 6476                cx.propagate();
 6477            }
 6478        }
 6479    }
 6480
 6481    pub fn accept_edit_prediction(
 6482        &mut self,
 6483        _: &AcceptEditPrediction,
 6484        window: &mut Window,
 6485        cx: &mut Context<Self>,
 6486    ) {
 6487        if self.show_edit_predictions_in_menu() {
 6488            self.hide_context_menu(window, cx);
 6489        }
 6490
 6491        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6492            return;
 6493        };
 6494
 6495        self.report_inline_completion_event(
 6496            active_inline_completion.completion_id.clone(),
 6497            true,
 6498            cx,
 6499        );
 6500
 6501        match &active_inline_completion.completion {
 6502            InlineCompletion::Move { target, .. } => {
 6503                let target = *target;
 6504
 6505                if let Some(position_map) = &self.last_position_map {
 6506                    if position_map
 6507                        .visible_row_range
 6508                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6509                        || !self.edit_prediction_requires_modifier()
 6510                    {
 6511                        self.unfold_ranges(&[target..target], true, false, cx);
 6512                        // Note that this is also done in vim's handler of the Tab action.
 6513                        self.change_selections(
 6514                            Some(Autoscroll::newest()),
 6515                            window,
 6516                            cx,
 6517                            |selections| {
 6518                                selections.select_anchor_ranges([target..target]);
 6519                            },
 6520                        );
 6521                        self.clear_row_highlights::<EditPredictionPreview>();
 6522
 6523                        self.edit_prediction_preview
 6524                            .set_previous_scroll_position(None);
 6525                    } else {
 6526                        self.edit_prediction_preview
 6527                            .set_previous_scroll_position(Some(
 6528                                position_map.snapshot.scroll_anchor,
 6529                            ));
 6530
 6531                        self.highlight_rows::<EditPredictionPreview>(
 6532                            target..target,
 6533                            cx.theme().colors().editor_highlighted_line_background,
 6534                            RowHighlightOptions {
 6535                                autoscroll: true,
 6536                                ..Default::default()
 6537                            },
 6538                            cx,
 6539                        );
 6540                        self.request_autoscroll(Autoscroll::fit(), cx);
 6541                    }
 6542                }
 6543            }
 6544            InlineCompletion::Edit { edits, .. } => {
 6545                if let Some(provider) = self.edit_prediction_provider() {
 6546                    provider.accept(cx);
 6547                }
 6548
 6549                // Store the transaction ID and selections before applying the edit
 6550                let transaction_id_prev =
 6551                    self.buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
 6552
 6553                let snapshot = self.buffer.read(cx).snapshot(cx);
 6554                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6555
 6556                self.buffer.update(cx, |buffer, cx| {
 6557                    buffer.edit(edits.iter().cloned(), None, cx)
 6558                });
 6559
 6560                self.change_selections(None, window, cx, |s| {
 6561                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6562                });
 6563
 6564                let selections = self.selections.disjoint_anchors();
 6565                if let Some(transaction_id_now) =
 6566                    self.buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
 6567                {
 6568                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6569                    if has_new_transaction {
 6570                        self.selection_history
 6571                            .insert_transaction(transaction_id_now, selections);
 6572                    }
 6573                }
 6574
 6575                self.update_visible_inline_completion(window, cx);
 6576                if self.active_inline_completion.is_none() {
 6577                    self.refresh_inline_completion(true, true, window, cx);
 6578                }
 6579
 6580                cx.notify();
 6581            }
 6582        }
 6583
 6584        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6585    }
 6586
 6587    pub fn accept_partial_inline_completion(
 6588        &mut self,
 6589        _: &AcceptPartialEditPrediction,
 6590        window: &mut Window,
 6591        cx: &mut Context<Self>,
 6592    ) {
 6593        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6594            return;
 6595        };
 6596        if self.selections.count() != 1 {
 6597            return;
 6598        }
 6599
 6600        self.report_inline_completion_event(
 6601            active_inline_completion.completion_id.clone(),
 6602            true,
 6603            cx,
 6604        );
 6605
 6606        match &active_inline_completion.completion {
 6607            InlineCompletion::Move { target, .. } => {
 6608                let target = *target;
 6609                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6610                    selections.select_anchor_ranges([target..target]);
 6611                });
 6612            }
 6613            InlineCompletion::Edit { edits, .. } => {
 6614                // Find an insertion that starts at the cursor position.
 6615                let snapshot = self.buffer.read(cx).snapshot(cx);
 6616                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6617                let insertion = edits.iter().find_map(|(range, text)| {
 6618                    let range = range.to_offset(&snapshot);
 6619                    if range.is_empty() && range.start == cursor_offset {
 6620                        Some(text)
 6621                    } else {
 6622                        None
 6623                    }
 6624                });
 6625
 6626                if let Some(text) = insertion {
 6627                    let mut partial_completion = text
 6628                        .chars()
 6629                        .by_ref()
 6630                        .take_while(|c| c.is_alphabetic())
 6631                        .collect::<String>();
 6632                    if partial_completion.is_empty() {
 6633                        partial_completion = text
 6634                            .chars()
 6635                            .by_ref()
 6636                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6637                            .collect::<String>();
 6638                    }
 6639
 6640                    cx.emit(EditorEvent::InputHandled {
 6641                        utf16_range_to_replace: None,
 6642                        text: partial_completion.clone().into(),
 6643                    });
 6644
 6645                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6646
 6647                    self.refresh_inline_completion(true, true, window, cx);
 6648                    cx.notify();
 6649                } else {
 6650                    self.accept_edit_prediction(&Default::default(), window, cx);
 6651                }
 6652            }
 6653        }
 6654    }
 6655
 6656    fn discard_inline_completion(
 6657        &mut self,
 6658        should_report_inline_completion_event: bool,
 6659        cx: &mut Context<Self>,
 6660    ) -> bool {
 6661        if should_report_inline_completion_event {
 6662            let completion_id = self
 6663                .active_inline_completion
 6664                .as_ref()
 6665                .and_then(|active_completion| active_completion.completion_id.clone());
 6666
 6667            self.report_inline_completion_event(completion_id, false, cx);
 6668        }
 6669
 6670        if let Some(provider) = self.edit_prediction_provider() {
 6671            provider.discard(cx);
 6672        }
 6673
 6674        self.take_active_inline_completion(cx)
 6675    }
 6676
 6677    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6678        let Some(provider) = self.edit_prediction_provider() else {
 6679            return;
 6680        };
 6681
 6682        let Some((_, buffer, _)) = self
 6683            .buffer
 6684            .read(cx)
 6685            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6686        else {
 6687            return;
 6688        };
 6689
 6690        let extension = buffer
 6691            .read(cx)
 6692            .file()
 6693            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6694
 6695        let event_type = match accepted {
 6696            true => "Edit Prediction Accepted",
 6697            false => "Edit Prediction Discarded",
 6698        };
 6699        telemetry::event!(
 6700            event_type,
 6701            provider = provider.name(),
 6702            prediction_id = id,
 6703            suggestion_accepted = accepted,
 6704            file_extension = extension,
 6705        );
 6706    }
 6707
 6708    pub fn has_active_inline_completion(&self) -> bool {
 6709        self.active_inline_completion.is_some()
 6710    }
 6711
 6712    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6713        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6714            return false;
 6715        };
 6716
 6717        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6718        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6719        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6720        true
 6721    }
 6722
 6723    /// Returns true when we're displaying the edit prediction popover below the cursor
 6724    /// like we are not previewing and the LSP autocomplete menu is visible
 6725    /// or we are in `when_holding_modifier` mode.
 6726    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6727        if self.edit_prediction_preview_is_active()
 6728            || !self.show_edit_predictions_in_menu()
 6729            || !self.edit_predictions_enabled()
 6730        {
 6731            return false;
 6732        }
 6733
 6734        if self.has_visible_completions_menu() {
 6735            return true;
 6736        }
 6737
 6738        has_completion && self.edit_prediction_requires_modifier()
 6739    }
 6740
 6741    fn handle_modifiers_changed(
 6742        &mut self,
 6743        modifiers: Modifiers,
 6744        position_map: &PositionMap,
 6745        window: &mut Window,
 6746        cx: &mut Context<Self>,
 6747    ) {
 6748        if self.show_edit_predictions_in_menu() {
 6749            self.update_edit_prediction_preview(&modifiers, window, cx);
 6750        }
 6751
 6752        self.update_selection_mode(&modifiers, position_map, window, cx);
 6753
 6754        let mouse_position = window.mouse_position();
 6755        if !position_map.text_hitbox.is_hovered(window) {
 6756            return;
 6757        }
 6758
 6759        self.update_hovered_link(
 6760            position_map.point_for_position(mouse_position),
 6761            &position_map.snapshot,
 6762            modifiers,
 6763            window,
 6764            cx,
 6765        )
 6766    }
 6767
 6768    fn update_selection_mode(
 6769        &mut self,
 6770        modifiers: &Modifiers,
 6771        position_map: &PositionMap,
 6772        window: &mut Window,
 6773        cx: &mut Context<Self>,
 6774    ) {
 6775        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6776            return;
 6777        }
 6778
 6779        let mouse_position = window.mouse_position();
 6780        let point_for_position = position_map.point_for_position(mouse_position);
 6781        let position = point_for_position.previous_valid;
 6782
 6783        self.select(
 6784            SelectPhase::BeginColumnar {
 6785                position,
 6786                reset: false,
 6787                goal_column: point_for_position.exact_unclipped.column(),
 6788            },
 6789            window,
 6790            cx,
 6791        );
 6792    }
 6793
 6794    fn update_edit_prediction_preview(
 6795        &mut self,
 6796        modifiers: &Modifiers,
 6797        window: &mut Window,
 6798        cx: &mut Context<Self>,
 6799    ) {
 6800        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6801        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6802            return;
 6803        };
 6804
 6805        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6806            if matches!(
 6807                self.edit_prediction_preview,
 6808                EditPredictionPreview::Inactive { .. }
 6809            ) {
 6810                self.edit_prediction_preview = EditPredictionPreview::Active {
 6811                    previous_scroll_position: None,
 6812                    since: Instant::now(),
 6813                };
 6814
 6815                self.update_visible_inline_completion(window, cx);
 6816                cx.notify();
 6817            }
 6818        } else if let EditPredictionPreview::Active {
 6819            previous_scroll_position,
 6820            since,
 6821        } = self.edit_prediction_preview
 6822        {
 6823            if let (Some(previous_scroll_position), Some(position_map)) =
 6824                (previous_scroll_position, self.last_position_map.as_ref())
 6825            {
 6826                self.set_scroll_position(
 6827                    previous_scroll_position
 6828                        .scroll_position(&position_map.snapshot.display_snapshot),
 6829                    window,
 6830                    cx,
 6831                );
 6832            }
 6833
 6834            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6835                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6836            };
 6837            self.clear_row_highlights::<EditPredictionPreview>();
 6838            self.update_visible_inline_completion(window, cx);
 6839            cx.notify();
 6840        }
 6841    }
 6842
 6843    fn update_visible_inline_completion(
 6844        &mut self,
 6845        _window: &mut Window,
 6846        cx: &mut Context<Self>,
 6847    ) -> Option<()> {
 6848        let selection = self.selections.newest_anchor();
 6849        let cursor = selection.head();
 6850        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6851        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6852        let excerpt_id = cursor.excerpt_id;
 6853
 6854        let show_in_menu = self.show_edit_predictions_in_menu();
 6855        let completions_menu_has_precedence = !show_in_menu
 6856            && (self.context_menu.borrow().is_some()
 6857                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6858
 6859        if completions_menu_has_precedence
 6860            || !offset_selection.is_empty()
 6861            || self
 6862                .active_inline_completion
 6863                .as_ref()
 6864                .map_or(false, |completion| {
 6865                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6866                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6867                    !invalidation_range.contains(&offset_selection.head())
 6868                })
 6869        {
 6870            self.discard_inline_completion(false, cx);
 6871            return None;
 6872        }
 6873
 6874        self.take_active_inline_completion(cx);
 6875        let Some(provider) = self.edit_prediction_provider() else {
 6876            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6877            return None;
 6878        };
 6879
 6880        let (buffer, cursor_buffer_position) =
 6881            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6882
 6883        self.edit_prediction_settings =
 6884            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6885
 6886        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6887
 6888        if self.edit_prediction_indent_conflict {
 6889            let cursor_point = cursor.to_point(&multibuffer);
 6890
 6891            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6892
 6893            if let Some((_, indent)) = indents.iter().next() {
 6894                if indent.len == cursor_point.column {
 6895                    self.edit_prediction_indent_conflict = false;
 6896                }
 6897            }
 6898        }
 6899
 6900        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6901        let edits = inline_completion
 6902            .edits
 6903            .into_iter()
 6904            .flat_map(|(range, new_text)| {
 6905                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6906                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6907                Some((start..end, new_text))
 6908            })
 6909            .collect::<Vec<_>>();
 6910        if edits.is_empty() {
 6911            return None;
 6912        }
 6913
 6914        let first_edit_start = edits.first().unwrap().0.start;
 6915        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6916        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6917
 6918        let last_edit_end = edits.last().unwrap().0.end;
 6919        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6920        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6921
 6922        let cursor_row = cursor.to_point(&multibuffer).row;
 6923
 6924        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6925
 6926        let mut inlay_ids = Vec::new();
 6927        let invalidation_row_range;
 6928        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6929            Some(cursor_row..edit_end_row)
 6930        } else if cursor_row > edit_end_row {
 6931            Some(edit_start_row..cursor_row)
 6932        } else {
 6933            None
 6934        };
 6935        let is_move =
 6936            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6937        let completion = if is_move {
 6938            invalidation_row_range =
 6939                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6940            let target = first_edit_start;
 6941            InlineCompletion::Move { target, snapshot }
 6942        } else {
 6943            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6944                && !self.inline_completions_hidden_for_vim_mode;
 6945
 6946            if show_completions_in_buffer {
 6947                if edits
 6948                    .iter()
 6949                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6950                {
 6951                    let mut inlays = Vec::new();
 6952                    for (range, new_text) in &edits {
 6953                        let inlay = Inlay::inline_completion(
 6954                            post_inc(&mut self.next_inlay_id),
 6955                            range.start,
 6956                            new_text.as_str(),
 6957                        );
 6958                        inlay_ids.push(inlay.id);
 6959                        inlays.push(inlay);
 6960                    }
 6961
 6962                    self.splice_inlays(&[], inlays, cx);
 6963                } else {
 6964                    let background_color = cx.theme().status().deleted_background;
 6965                    self.highlight_text::<InlineCompletionHighlight>(
 6966                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6967                        HighlightStyle {
 6968                            background_color: Some(background_color),
 6969                            ..Default::default()
 6970                        },
 6971                        cx,
 6972                    );
 6973                }
 6974            }
 6975
 6976            invalidation_row_range = edit_start_row..edit_end_row;
 6977
 6978            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6979                if provider.show_tab_accept_marker() {
 6980                    EditDisplayMode::TabAccept
 6981                } else {
 6982                    EditDisplayMode::Inline
 6983                }
 6984            } else {
 6985                EditDisplayMode::DiffPopover
 6986            };
 6987
 6988            InlineCompletion::Edit {
 6989                edits,
 6990                edit_preview: inline_completion.edit_preview,
 6991                display_mode,
 6992                snapshot,
 6993            }
 6994        };
 6995
 6996        let invalidation_range = multibuffer
 6997            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6998            ..multibuffer.anchor_after(Point::new(
 6999                invalidation_row_range.end,
 7000                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7001            ));
 7002
 7003        self.stale_inline_completion_in_menu = None;
 7004        self.active_inline_completion = Some(InlineCompletionState {
 7005            inlay_ids,
 7006            completion,
 7007            completion_id: inline_completion.id,
 7008            invalidation_range,
 7009        });
 7010
 7011        cx.notify();
 7012
 7013        Some(())
 7014    }
 7015
 7016    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7017        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7018    }
 7019
 7020    fn clear_tasks(&mut self) {
 7021        self.tasks.clear()
 7022    }
 7023
 7024    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7025        if self.tasks.insert(key, value).is_some() {
 7026            // This case should hopefully be rare, but just in case...
 7027            log::error!(
 7028                "multiple different run targets found on a single line, only the last target will be rendered"
 7029            )
 7030        }
 7031    }
 7032
 7033    /// Get all display points of breakpoints that will be rendered within editor
 7034    ///
 7035    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7036    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7037    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7038    fn active_breakpoints(
 7039        &self,
 7040        range: Range<DisplayRow>,
 7041        window: &mut Window,
 7042        cx: &mut Context<Self>,
 7043    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7044        let mut breakpoint_display_points = HashMap::default();
 7045
 7046        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7047            return breakpoint_display_points;
 7048        };
 7049
 7050        let snapshot = self.snapshot(window, cx);
 7051
 7052        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7053        let Some(project) = self.project.as_ref() else {
 7054            return breakpoint_display_points;
 7055        };
 7056
 7057        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7058            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7059
 7060        for (buffer_snapshot, range, excerpt_id) in
 7061            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7062        {
 7063            let Some(buffer) = project.read_with(cx, |this, cx| {
 7064                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7065            }) else {
 7066                continue;
 7067            };
 7068            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7069                &buffer,
 7070                Some(
 7071                    buffer_snapshot.anchor_before(range.start)
 7072                        ..buffer_snapshot.anchor_after(range.end),
 7073                ),
 7074                buffer_snapshot,
 7075                cx,
 7076            );
 7077            for (breakpoint, state) in breakpoints {
 7078                let multi_buffer_anchor =
 7079                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7080                let position = multi_buffer_anchor
 7081                    .to_point(&multi_buffer_snapshot)
 7082                    .to_display_point(&snapshot);
 7083
 7084                breakpoint_display_points.insert(
 7085                    position.row(),
 7086                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7087                );
 7088            }
 7089        }
 7090
 7091        breakpoint_display_points
 7092    }
 7093
 7094    fn breakpoint_context_menu(
 7095        &self,
 7096        anchor: Anchor,
 7097        window: &mut Window,
 7098        cx: &mut Context<Self>,
 7099    ) -> Entity<ui::ContextMenu> {
 7100        let weak_editor = cx.weak_entity();
 7101        let focus_handle = self.focus_handle(cx);
 7102
 7103        let row = self
 7104            .buffer
 7105            .read(cx)
 7106            .snapshot(cx)
 7107            .summary_for_anchor::<Point>(&anchor)
 7108            .row;
 7109
 7110        let breakpoint = self
 7111            .breakpoint_at_row(row, window, cx)
 7112            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7113
 7114        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7115            "Edit Log Breakpoint"
 7116        } else {
 7117            "Set Log Breakpoint"
 7118        };
 7119
 7120        let condition_breakpoint_msg = if breakpoint
 7121            .as_ref()
 7122            .is_some_and(|bp| bp.1.condition.is_some())
 7123        {
 7124            "Edit Condition Breakpoint"
 7125        } else {
 7126            "Set Condition Breakpoint"
 7127        };
 7128
 7129        let hit_condition_breakpoint_msg = if breakpoint
 7130            .as_ref()
 7131            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7132        {
 7133            "Edit Hit Condition Breakpoint"
 7134        } else {
 7135            "Set Hit Condition Breakpoint"
 7136        };
 7137
 7138        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7139            "Unset Breakpoint"
 7140        } else {
 7141            "Set Breakpoint"
 7142        };
 7143
 7144        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7145            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7146
 7147        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7148            BreakpointState::Enabled => Some("Disable"),
 7149            BreakpointState::Disabled => Some("Enable"),
 7150        });
 7151
 7152        let (anchor, breakpoint) =
 7153            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7154
 7155        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7156            menu.on_blur_subscription(Subscription::new(|| {}))
 7157                .context(focus_handle)
 7158                .when(run_to_cursor, |this| {
 7159                    let weak_editor = weak_editor.clone();
 7160                    this.entry("Run to cursor", None, move |window, cx| {
 7161                        weak_editor
 7162                            .update(cx, |editor, cx| {
 7163                                editor.change_selections(None, window, cx, |s| {
 7164                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7165                                });
 7166                            })
 7167                            .ok();
 7168
 7169                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7170                    })
 7171                    .separator()
 7172                })
 7173                .when_some(toggle_state_msg, |this, msg| {
 7174                    this.entry(msg, None, {
 7175                        let weak_editor = weak_editor.clone();
 7176                        let breakpoint = breakpoint.clone();
 7177                        move |_window, cx| {
 7178                            weak_editor
 7179                                .update(cx, |this, cx| {
 7180                                    this.edit_breakpoint_at_anchor(
 7181                                        anchor,
 7182                                        breakpoint.as_ref().clone(),
 7183                                        BreakpointEditAction::InvertState,
 7184                                        cx,
 7185                                    );
 7186                                })
 7187                                .log_err();
 7188                        }
 7189                    })
 7190                })
 7191                .entry(set_breakpoint_msg, None, {
 7192                    let weak_editor = weak_editor.clone();
 7193                    let breakpoint = breakpoint.clone();
 7194                    move |_window, cx| {
 7195                        weak_editor
 7196                            .update(cx, |this, cx| {
 7197                                this.edit_breakpoint_at_anchor(
 7198                                    anchor,
 7199                                    breakpoint.as_ref().clone(),
 7200                                    BreakpointEditAction::Toggle,
 7201                                    cx,
 7202                                );
 7203                            })
 7204                            .log_err();
 7205                    }
 7206                })
 7207                .entry(log_breakpoint_msg, None, {
 7208                    let breakpoint = breakpoint.clone();
 7209                    let weak_editor = weak_editor.clone();
 7210                    move |window, cx| {
 7211                        weak_editor
 7212                            .update(cx, |this, cx| {
 7213                                this.add_edit_breakpoint_block(
 7214                                    anchor,
 7215                                    breakpoint.as_ref(),
 7216                                    BreakpointPromptEditAction::Log,
 7217                                    window,
 7218                                    cx,
 7219                                );
 7220                            })
 7221                            .log_err();
 7222                    }
 7223                })
 7224                .entry(condition_breakpoint_msg, None, {
 7225                    let breakpoint = breakpoint.clone();
 7226                    let weak_editor = weak_editor.clone();
 7227                    move |window, cx| {
 7228                        weak_editor
 7229                            .update(cx, |this, cx| {
 7230                                this.add_edit_breakpoint_block(
 7231                                    anchor,
 7232                                    breakpoint.as_ref(),
 7233                                    BreakpointPromptEditAction::Condition,
 7234                                    window,
 7235                                    cx,
 7236                                );
 7237                            })
 7238                            .log_err();
 7239                    }
 7240                })
 7241                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7242                    weak_editor
 7243                        .update(cx, |this, cx| {
 7244                            this.add_edit_breakpoint_block(
 7245                                anchor,
 7246                                breakpoint.as_ref(),
 7247                                BreakpointPromptEditAction::HitCondition,
 7248                                window,
 7249                                cx,
 7250                            );
 7251                        })
 7252                        .log_err();
 7253                })
 7254        })
 7255    }
 7256
 7257    fn render_breakpoint(
 7258        &self,
 7259        position: Anchor,
 7260        row: DisplayRow,
 7261        breakpoint: &Breakpoint,
 7262        state: Option<BreakpointSessionState>,
 7263        cx: &mut Context<Self>,
 7264    ) -> IconButton {
 7265        let is_rejected = state.is_some_and(|s| !s.verified);
 7266        // Is it a breakpoint that shows up when hovering over gutter?
 7267        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7268            (false, false),
 7269            |PhantomBreakpointIndicator {
 7270                 is_active,
 7271                 display_row,
 7272                 collides_with_existing_breakpoint,
 7273             }| {
 7274                (
 7275                    is_active && display_row == row,
 7276                    collides_with_existing_breakpoint,
 7277                )
 7278            },
 7279        );
 7280
 7281        let (color, icon) = {
 7282            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7283                (false, false) => ui::IconName::DebugBreakpoint,
 7284                (true, false) => ui::IconName::DebugLogBreakpoint,
 7285                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7286                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7287            };
 7288
 7289            let color = if is_phantom {
 7290                Color::Hint
 7291            } else if is_rejected {
 7292                Color::Disabled
 7293            } else {
 7294                Color::Debugger
 7295            };
 7296
 7297            (color, icon)
 7298        };
 7299
 7300        let breakpoint = Arc::from(breakpoint.clone());
 7301
 7302        let alt_as_text = gpui::Keystroke {
 7303            modifiers: Modifiers::secondary_key(),
 7304            ..Default::default()
 7305        };
 7306        let primary_action_text = if breakpoint.is_disabled() {
 7307            "Enable breakpoint"
 7308        } else if is_phantom && !collides_with_existing {
 7309            "Set breakpoint"
 7310        } else {
 7311            "Unset breakpoint"
 7312        };
 7313        let focus_handle = self.focus_handle.clone();
 7314
 7315        let meta = if is_rejected {
 7316            SharedString::from("No executable code is associated with this line.")
 7317        } else if collides_with_existing && !breakpoint.is_disabled() {
 7318            SharedString::from(format!(
 7319                "{alt_as_text}-click to disable,\nright-click for more options."
 7320            ))
 7321        } else {
 7322            SharedString::from("Right-click for more options.")
 7323        };
 7324        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7325            .icon_size(IconSize::XSmall)
 7326            .size(ui::ButtonSize::None)
 7327            .when(is_rejected, |this| {
 7328                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7329            })
 7330            .icon_color(color)
 7331            .style(ButtonStyle::Transparent)
 7332            .on_click(cx.listener({
 7333                let breakpoint = breakpoint.clone();
 7334
 7335                move |editor, event: &ClickEvent, window, cx| {
 7336                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7337                        BreakpointEditAction::InvertState
 7338                    } else {
 7339                        BreakpointEditAction::Toggle
 7340                    };
 7341
 7342                    window.focus(&editor.focus_handle(cx));
 7343                    editor.edit_breakpoint_at_anchor(
 7344                        position,
 7345                        breakpoint.as_ref().clone(),
 7346                        edit_action,
 7347                        cx,
 7348                    );
 7349                }
 7350            }))
 7351            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7352                editor.set_breakpoint_context_menu(
 7353                    row,
 7354                    Some(position),
 7355                    event.down.position,
 7356                    window,
 7357                    cx,
 7358                );
 7359            }))
 7360            .tooltip(move |window, cx| {
 7361                Tooltip::with_meta_in(
 7362                    primary_action_text,
 7363                    Some(&ToggleBreakpoint),
 7364                    meta.clone(),
 7365                    &focus_handle,
 7366                    window,
 7367                    cx,
 7368                )
 7369            })
 7370    }
 7371
 7372    fn build_tasks_context(
 7373        project: &Entity<Project>,
 7374        buffer: &Entity<Buffer>,
 7375        buffer_row: u32,
 7376        tasks: &Arc<RunnableTasks>,
 7377        cx: &mut Context<Self>,
 7378    ) -> Task<Option<task::TaskContext>> {
 7379        let position = Point::new(buffer_row, tasks.column);
 7380        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7381        let location = Location {
 7382            buffer: buffer.clone(),
 7383            range: range_start..range_start,
 7384        };
 7385        // Fill in the environmental variables from the tree-sitter captures
 7386        let mut captured_task_variables = TaskVariables::default();
 7387        for (capture_name, value) in tasks.extra_variables.clone() {
 7388            captured_task_variables.insert(
 7389                task::VariableName::Custom(capture_name.into()),
 7390                value.clone(),
 7391            );
 7392        }
 7393        project.update(cx, |project, cx| {
 7394            project.task_store().update(cx, |task_store, cx| {
 7395                task_store.task_context_for_location(captured_task_variables, location, cx)
 7396            })
 7397        })
 7398    }
 7399
 7400    pub fn spawn_nearest_task(
 7401        &mut self,
 7402        action: &SpawnNearestTask,
 7403        window: &mut Window,
 7404        cx: &mut Context<Self>,
 7405    ) {
 7406        let Some((workspace, _)) = self.workspace.clone() else {
 7407            return;
 7408        };
 7409        let Some(project) = self.project.clone() else {
 7410            return;
 7411        };
 7412
 7413        // Try to find a closest, enclosing node using tree-sitter that has a
 7414        // task
 7415        let Some((buffer, buffer_row, tasks)) = self
 7416            .find_enclosing_node_task(cx)
 7417            // Or find the task that's closest in row-distance.
 7418            .or_else(|| self.find_closest_task(cx))
 7419        else {
 7420            return;
 7421        };
 7422
 7423        let reveal_strategy = action.reveal;
 7424        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7425        cx.spawn_in(window, async move |_, cx| {
 7426            let context = task_context.await?;
 7427            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7428
 7429            let resolved = &mut resolved_task.resolved;
 7430            resolved.reveal = reveal_strategy;
 7431
 7432            workspace
 7433                .update_in(cx, |workspace, window, cx| {
 7434                    workspace.schedule_resolved_task(
 7435                        task_source_kind,
 7436                        resolved_task,
 7437                        false,
 7438                        window,
 7439                        cx,
 7440                    );
 7441                })
 7442                .ok()
 7443        })
 7444        .detach();
 7445    }
 7446
 7447    fn find_closest_task(
 7448        &mut self,
 7449        cx: &mut Context<Self>,
 7450    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7451        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7452
 7453        let ((buffer_id, row), tasks) = self
 7454            .tasks
 7455            .iter()
 7456            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7457
 7458        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7459        let tasks = Arc::new(tasks.to_owned());
 7460        Some((buffer, *row, tasks))
 7461    }
 7462
 7463    fn find_enclosing_node_task(
 7464        &mut self,
 7465        cx: &mut Context<Self>,
 7466    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7467        let snapshot = self.buffer.read(cx).snapshot(cx);
 7468        let offset = self.selections.newest::<usize>(cx).head();
 7469        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7470        let buffer_id = excerpt.buffer().remote_id();
 7471
 7472        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7473        let mut cursor = layer.node().walk();
 7474
 7475        while cursor.goto_first_child_for_byte(offset).is_some() {
 7476            if cursor.node().end_byte() == offset {
 7477                cursor.goto_next_sibling();
 7478            }
 7479        }
 7480
 7481        // Ascend to the smallest ancestor that contains the range and has a task.
 7482        loop {
 7483            let node = cursor.node();
 7484            let node_range = node.byte_range();
 7485            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7486
 7487            // Check if this node contains our offset
 7488            if node_range.start <= offset && node_range.end >= offset {
 7489                // If it contains offset, check for task
 7490                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7491                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7492                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7493                }
 7494            }
 7495
 7496            if !cursor.goto_parent() {
 7497                break;
 7498            }
 7499        }
 7500        None
 7501    }
 7502
 7503    fn render_run_indicator(
 7504        &self,
 7505        _style: &EditorStyle,
 7506        is_active: bool,
 7507        row: DisplayRow,
 7508        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7509        cx: &mut Context<Self>,
 7510    ) -> IconButton {
 7511        let color = Color::Muted;
 7512        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7513
 7514        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7515            .shape(ui::IconButtonShape::Square)
 7516            .icon_size(IconSize::XSmall)
 7517            .icon_color(color)
 7518            .toggle_state(is_active)
 7519            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7520                let quick_launch = e.down.button == MouseButton::Left;
 7521                window.focus(&editor.focus_handle(cx));
 7522                editor.toggle_code_actions(
 7523                    &ToggleCodeActions {
 7524                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7525                        quick_launch,
 7526                    },
 7527                    window,
 7528                    cx,
 7529                );
 7530            }))
 7531            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7532                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7533            }))
 7534    }
 7535
 7536    pub fn context_menu_visible(&self) -> bool {
 7537        !self.edit_prediction_preview_is_active()
 7538            && self
 7539                .context_menu
 7540                .borrow()
 7541                .as_ref()
 7542                .map_or(false, |menu| menu.visible())
 7543    }
 7544
 7545    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7546        self.context_menu
 7547            .borrow()
 7548            .as_ref()
 7549            .map(|menu| menu.origin())
 7550    }
 7551
 7552    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7553        self.context_menu_options = Some(options);
 7554    }
 7555
 7556    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7557    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7558
 7559    fn render_edit_prediction_popover(
 7560        &mut self,
 7561        text_bounds: &Bounds<Pixels>,
 7562        content_origin: gpui::Point<Pixels>,
 7563        right_margin: Pixels,
 7564        editor_snapshot: &EditorSnapshot,
 7565        visible_row_range: Range<DisplayRow>,
 7566        scroll_top: f32,
 7567        scroll_bottom: f32,
 7568        line_layouts: &[LineWithInvisibles],
 7569        line_height: Pixels,
 7570        scroll_pixel_position: gpui::Point<Pixels>,
 7571        newest_selection_head: Option<DisplayPoint>,
 7572        editor_width: Pixels,
 7573        style: &EditorStyle,
 7574        window: &mut Window,
 7575        cx: &mut App,
 7576    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7577        if self.mode().is_minimap() {
 7578            return None;
 7579        }
 7580        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7581
 7582        if self.edit_prediction_visible_in_cursor_popover(true) {
 7583            return None;
 7584        }
 7585
 7586        match &active_inline_completion.completion {
 7587            InlineCompletion::Move { target, .. } => {
 7588                let target_display_point = target.to_display_point(editor_snapshot);
 7589
 7590                if self.edit_prediction_requires_modifier() {
 7591                    if !self.edit_prediction_preview_is_active() {
 7592                        return None;
 7593                    }
 7594
 7595                    self.render_edit_prediction_modifier_jump_popover(
 7596                        text_bounds,
 7597                        content_origin,
 7598                        visible_row_range,
 7599                        line_layouts,
 7600                        line_height,
 7601                        scroll_pixel_position,
 7602                        newest_selection_head,
 7603                        target_display_point,
 7604                        window,
 7605                        cx,
 7606                    )
 7607                } else {
 7608                    self.render_edit_prediction_eager_jump_popover(
 7609                        text_bounds,
 7610                        content_origin,
 7611                        editor_snapshot,
 7612                        visible_row_range,
 7613                        scroll_top,
 7614                        scroll_bottom,
 7615                        line_height,
 7616                        scroll_pixel_position,
 7617                        target_display_point,
 7618                        editor_width,
 7619                        window,
 7620                        cx,
 7621                    )
 7622                }
 7623            }
 7624            InlineCompletion::Edit {
 7625                display_mode: EditDisplayMode::Inline,
 7626                ..
 7627            } => None,
 7628            InlineCompletion::Edit {
 7629                display_mode: EditDisplayMode::TabAccept,
 7630                edits,
 7631                ..
 7632            } => {
 7633                let range = &edits.first()?.0;
 7634                let target_display_point = range.end.to_display_point(editor_snapshot);
 7635
 7636                self.render_edit_prediction_end_of_line_popover(
 7637                    "Accept",
 7638                    editor_snapshot,
 7639                    visible_row_range,
 7640                    target_display_point,
 7641                    line_height,
 7642                    scroll_pixel_position,
 7643                    content_origin,
 7644                    editor_width,
 7645                    window,
 7646                    cx,
 7647                )
 7648            }
 7649            InlineCompletion::Edit {
 7650                edits,
 7651                edit_preview,
 7652                display_mode: EditDisplayMode::DiffPopover,
 7653                snapshot,
 7654            } => self.render_edit_prediction_diff_popover(
 7655                text_bounds,
 7656                content_origin,
 7657                right_margin,
 7658                editor_snapshot,
 7659                visible_row_range,
 7660                line_layouts,
 7661                line_height,
 7662                scroll_pixel_position,
 7663                newest_selection_head,
 7664                editor_width,
 7665                style,
 7666                edits,
 7667                edit_preview,
 7668                snapshot,
 7669                window,
 7670                cx,
 7671            ),
 7672        }
 7673    }
 7674
 7675    fn render_edit_prediction_modifier_jump_popover(
 7676        &mut self,
 7677        text_bounds: &Bounds<Pixels>,
 7678        content_origin: gpui::Point<Pixels>,
 7679        visible_row_range: Range<DisplayRow>,
 7680        line_layouts: &[LineWithInvisibles],
 7681        line_height: Pixels,
 7682        scroll_pixel_position: gpui::Point<Pixels>,
 7683        newest_selection_head: Option<DisplayPoint>,
 7684        target_display_point: DisplayPoint,
 7685        window: &mut Window,
 7686        cx: &mut App,
 7687    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7688        let scrolled_content_origin =
 7689            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7690
 7691        const SCROLL_PADDING_Y: Pixels = px(12.);
 7692
 7693        if target_display_point.row() < visible_row_range.start {
 7694            return self.render_edit_prediction_scroll_popover(
 7695                |_| SCROLL_PADDING_Y,
 7696                IconName::ArrowUp,
 7697                visible_row_range,
 7698                line_layouts,
 7699                newest_selection_head,
 7700                scrolled_content_origin,
 7701                window,
 7702                cx,
 7703            );
 7704        } else if target_display_point.row() >= visible_row_range.end {
 7705            return self.render_edit_prediction_scroll_popover(
 7706                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7707                IconName::ArrowDown,
 7708                visible_row_range,
 7709                line_layouts,
 7710                newest_selection_head,
 7711                scrolled_content_origin,
 7712                window,
 7713                cx,
 7714            );
 7715        }
 7716
 7717        const POLE_WIDTH: Pixels = px(2.);
 7718
 7719        let line_layout =
 7720            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7721        let target_column = target_display_point.column() as usize;
 7722
 7723        let target_x = line_layout.x_for_index(target_column);
 7724        let target_y =
 7725            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7726
 7727        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7728
 7729        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7730        border_color.l += 0.001;
 7731
 7732        let mut element = v_flex()
 7733            .items_end()
 7734            .when(flag_on_right, |el| el.items_start())
 7735            .child(if flag_on_right {
 7736                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7737                    .rounded_bl(px(0.))
 7738                    .rounded_tl(px(0.))
 7739                    .border_l_2()
 7740                    .border_color(border_color)
 7741            } else {
 7742                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7743                    .rounded_br(px(0.))
 7744                    .rounded_tr(px(0.))
 7745                    .border_r_2()
 7746                    .border_color(border_color)
 7747            })
 7748            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7749            .into_any();
 7750
 7751        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7752
 7753        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7754            - point(
 7755                if flag_on_right {
 7756                    POLE_WIDTH
 7757                } else {
 7758                    size.width - POLE_WIDTH
 7759                },
 7760                size.height - line_height,
 7761            );
 7762
 7763        origin.x = origin.x.max(content_origin.x);
 7764
 7765        element.prepaint_at(origin, window, cx);
 7766
 7767        Some((element, origin))
 7768    }
 7769
 7770    fn render_edit_prediction_scroll_popover(
 7771        &mut self,
 7772        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7773        scroll_icon: IconName,
 7774        visible_row_range: Range<DisplayRow>,
 7775        line_layouts: &[LineWithInvisibles],
 7776        newest_selection_head: Option<DisplayPoint>,
 7777        scrolled_content_origin: gpui::Point<Pixels>,
 7778        window: &mut Window,
 7779        cx: &mut App,
 7780    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7781        let mut element = self
 7782            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7783            .into_any();
 7784
 7785        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7786
 7787        let cursor = newest_selection_head?;
 7788        let cursor_row_layout =
 7789            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7790        let cursor_column = cursor.column() as usize;
 7791
 7792        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7793
 7794        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7795
 7796        element.prepaint_at(origin, window, cx);
 7797        Some((element, origin))
 7798    }
 7799
 7800    fn render_edit_prediction_eager_jump_popover(
 7801        &mut self,
 7802        text_bounds: &Bounds<Pixels>,
 7803        content_origin: gpui::Point<Pixels>,
 7804        editor_snapshot: &EditorSnapshot,
 7805        visible_row_range: Range<DisplayRow>,
 7806        scroll_top: f32,
 7807        scroll_bottom: f32,
 7808        line_height: Pixels,
 7809        scroll_pixel_position: gpui::Point<Pixels>,
 7810        target_display_point: DisplayPoint,
 7811        editor_width: Pixels,
 7812        window: &mut Window,
 7813        cx: &mut App,
 7814    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7815        if target_display_point.row().as_f32() < scroll_top {
 7816            let mut element = self
 7817                .render_edit_prediction_line_popover(
 7818                    "Jump to Edit",
 7819                    Some(IconName::ArrowUp),
 7820                    window,
 7821                    cx,
 7822                )?
 7823                .into_any();
 7824
 7825            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7826            let offset = point(
 7827                (text_bounds.size.width - size.width) / 2.,
 7828                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7829            );
 7830
 7831            let origin = text_bounds.origin + offset;
 7832            element.prepaint_at(origin, window, cx);
 7833            Some((element, origin))
 7834        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7835            let mut element = self
 7836                .render_edit_prediction_line_popover(
 7837                    "Jump to Edit",
 7838                    Some(IconName::ArrowDown),
 7839                    window,
 7840                    cx,
 7841                )?
 7842                .into_any();
 7843
 7844            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7845            let offset = point(
 7846                (text_bounds.size.width - size.width) / 2.,
 7847                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7848            );
 7849
 7850            let origin = text_bounds.origin + offset;
 7851            element.prepaint_at(origin, window, cx);
 7852            Some((element, origin))
 7853        } else {
 7854            self.render_edit_prediction_end_of_line_popover(
 7855                "Jump to Edit",
 7856                editor_snapshot,
 7857                visible_row_range,
 7858                target_display_point,
 7859                line_height,
 7860                scroll_pixel_position,
 7861                content_origin,
 7862                editor_width,
 7863                window,
 7864                cx,
 7865            )
 7866        }
 7867    }
 7868
 7869    fn render_edit_prediction_end_of_line_popover(
 7870        self: &mut Editor,
 7871        label: &'static str,
 7872        editor_snapshot: &EditorSnapshot,
 7873        visible_row_range: Range<DisplayRow>,
 7874        target_display_point: DisplayPoint,
 7875        line_height: Pixels,
 7876        scroll_pixel_position: gpui::Point<Pixels>,
 7877        content_origin: gpui::Point<Pixels>,
 7878        editor_width: Pixels,
 7879        window: &mut Window,
 7880        cx: &mut App,
 7881    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7882        let target_line_end = DisplayPoint::new(
 7883            target_display_point.row(),
 7884            editor_snapshot.line_len(target_display_point.row()),
 7885        );
 7886
 7887        let mut element = self
 7888            .render_edit_prediction_line_popover(label, None, window, cx)?
 7889            .into_any();
 7890
 7891        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7892
 7893        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7894
 7895        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7896        let mut origin = start_point
 7897            + line_origin
 7898            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7899        origin.x = origin.x.max(content_origin.x);
 7900
 7901        let max_x = content_origin.x + editor_width - size.width;
 7902
 7903        if origin.x > max_x {
 7904            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7905
 7906            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7907                origin.y += offset;
 7908                IconName::ArrowUp
 7909            } else {
 7910                origin.y -= offset;
 7911                IconName::ArrowDown
 7912            };
 7913
 7914            element = self
 7915                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7916                .into_any();
 7917
 7918            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7919
 7920            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7921        }
 7922
 7923        element.prepaint_at(origin, window, cx);
 7924        Some((element, origin))
 7925    }
 7926
 7927    fn render_edit_prediction_diff_popover(
 7928        self: &Editor,
 7929        text_bounds: &Bounds<Pixels>,
 7930        content_origin: gpui::Point<Pixels>,
 7931        right_margin: Pixels,
 7932        editor_snapshot: &EditorSnapshot,
 7933        visible_row_range: Range<DisplayRow>,
 7934        line_layouts: &[LineWithInvisibles],
 7935        line_height: Pixels,
 7936        scroll_pixel_position: gpui::Point<Pixels>,
 7937        newest_selection_head: Option<DisplayPoint>,
 7938        editor_width: Pixels,
 7939        style: &EditorStyle,
 7940        edits: &Vec<(Range<Anchor>, String)>,
 7941        edit_preview: &Option<language::EditPreview>,
 7942        snapshot: &language::BufferSnapshot,
 7943        window: &mut Window,
 7944        cx: &mut App,
 7945    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7946        let edit_start = edits
 7947            .first()
 7948            .unwrap()
 7949            .0
 7950            .start
 7951            .to_display_point(editor_snapshot);
 7952        let edit_end = edits
 7953            .last()
 7954            .unwrap()
 7955            .0
 7956            .end
 7957            .to_display_point(editor_snapshot);
 7958
 7959        let is_visible = visible_row_range.contains(&edit_start.row())
 7960            || visible_row_range.contains(&edit_end.row());
 7961        if !is_visible {
 7962            return None;
 7963        }
 7964
 7965        let highlighted_edits =
 7966            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7967
 7968        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7969        let line_count = highlighted_edits.text.lines().count();
 7970
 7971        const BORDER_WIDTH: Pixels = px(1.);
 7972
 7973        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7974        let has_keybind = keybind.is_some();
 7975
 7976        let mut element = h_flex()
 7977            .items_start()
 7978            .child(
 7979                h_flex()
 7980                    .bg(cx.theme().colors().editor_background)
 7981                    .border(BORDER_WIDTH)
 7982                    .shadow_sm()
 7983                    .border_color(cx.theme().colors().border)
 7984                    .rounded_l_lg()
 7985                    .when(line_count > 1, |el| el.rounded_br_lg())
 7986                    .pr_1()
 7987                    .child(styled_text),
 7988            )
 7989            .child(
 7990                h_flex()
 7991                    .h(line_height + BORDER_WIDTH * 2.)
 7992                    .px_1p5()
 7993                    .gap_1()
 7994                    // Workaround: For some reason, there's a gap if we don't do this
 7995                    .ml(-BORDER_WIDTH)
 7996                    .shadow(smallvec![gpui::BoxShadow {
 7997                        color: gpui::black().opacity(0.05),
 7998                        offset: point(px(1.), px(1.)),
 7999                        blur_radius: px(2.),
 8000                        spread_radius: px(0.),
 8001                    }])
 8002                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8003                    .border(BORDER_WIDTH)
 8004                    .border_color(cx.theme().colors().border)
 8005                    .rounded_r_lg()
 8006                    .id("edit_prediction_diff_popover_keybind")
 8007                    .when(!has_keybind, |el| {
 8008                        let status_colors = cx.theme().status();
 8009
 8010                        el.bg(status_colors.error_background)
 8011                            .border_color(status_colors.error.opacity(0.6))
 8012                            .child(Icon::new(IconName::Info).color(Color::Error))
 8013                            .cursor_default()
 8014                            .hoverable_tooltip(move |_window, cx| {
 8015                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8016                            })
 8017                    })
 8018                    .children(keybind),
 8019            )
 8020            .into_any();
 8021
 8022        let longest_row =
 8023            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8024        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8025            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8026        } else {
 8027            layout_line(
 8028                longest_row,
 8029                editor_snapshot,
 8030                style,
 8031                editor_width,
 8032                |_| false,
 8033                window,
 8034                cx,
 8035            )
 8036            .width
 8037        };
 8038
 8039        let viewport_bounds =
 8040            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8041                right: -right_margin,
 8042                ..Default::default()
 8043            });
 8044
 8045        let x_after_longest =
 8046            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8047                - scroll_pixel_position.x;
 8048
 8049        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8050
 8051        // Fully visible if it can be displayed within the window (allow overlapping other
 8052        // panes). However, this is only allowed if the popover starts within text_bounds.
 8053        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8054            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8055
 8056        let mut origin = if can_position_to_the_right {
 8057            point(
 8058                x_after_longest,
 8059                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8060                    - scroll_pixel_position.y,
 8061            )
 8062        } else {
 8063            let cursor_row = newest_selection_head.map(|head| head.row());
 8064            let above_edit = edit_start
 8065                .row()
 8066                .0
 8067                .checked_sub(line_count as u32)
 8068                .map(DisplayRow);
 8069            let below_edit = Some(edit_end.row() + 1);
 8070            let above_cursor =
 8071                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8072            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8073
 8074            // Place the edit popover adjacent to the edit if there is a location
 8075            // available that is onscreen and does not obscure the cursor. Otherwise,
 8076            // place it adjacent to the cursor.
 8077            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8078                .into_iter()
 8079                .flatten()
 8080                .find(|&start_row| {
 8081                    let end_row = start_row + line_count as u32;
 8082                    visible_row_range.contains(&start_row)
 8083                        && visible_row_range.contains(&end_row)
 8084                        && cursor_row.map_or(true, |cursor_row| {
 8085                            !((start_row..end_row).contains(&cursor_row))
 8086                        })
 8087                })?;
 8088
 8089            content_origin
 8090                + point(
 8091                    -scroll_pixel_position.x,
 8092                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8093                )
 8094        };
 8095
 8096        origin.x -= BORDER_WIDTH;
 8097
 8098        window.defer_draw(element, origin, 1);
 8099
 8100        // Do not return an element, since it will already be drawn due to defer_draw.
 8101        None
 8102    }
 8103
 8104    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8105        px(30.)
 8106    }
 8107
 8108    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8109        if self.read_only(cx) {
 8110            cx.theme().players().read_only()
 8111        } else {
 8112            self.style.as_ref().unwrap().local_player
 8113        }
 8114    }
 8115
 8116    fn render_edit_prediction_accept_keybind(
 8117        &self,
 8118        window: &mut Window,
 8119        cx: &App,
 8120    ) -> Option<AnyElement> {
 8121        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8122        let accept_keystroke = accept_binding.keystroke()?;
 8123
 8124        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8125
 8126        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8127            Color::Accent
 8128        } else {
 8129            Color::Muted
 8130        };
 8131
 8132        h_flex()
 8133            .px_0p5()
 8134            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8135            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8136            .text_size(TextSize::XSmall.rems(cx))
 8137            .child(h_flex().children(ui::render_modifiers(
 8138                &accept_keystroke.modifiers,
 8139                PlatformStyle::platform(),
 8140                Some(modifiers_color),
 8141                Some(IconSize::XSmall.rems().into()),
 8142                true,
 8143            )))
 8144            .when(is_platform_style_mac, |parent| {
 8145                parent.child(accept_keystroke.key.clone())
 8146            })
 8147            .when(!is_platform_style_mac, |parent| {
 8148                parent.child(
 8149                    Key::new(
 8150                        util::capitalize(&accept_keystroke.key),
 8151                        Some(Color::Default),
 8152                    )
 8153                    .size(Some(IconSize::XSmall.rems().into())),
 8154                )
 8155            })
 8156            .into_any()
 8157            .into()
 8158    }
 8159
 8160    fn render_edit_prediction_line_popover(
 8161        &self,
 8162        label: impl Into<SharedString>,
 8163        icon: Option<IconName>,
 8164        window: &mut Window,
 8165        cx: &App,
 8166    ) -> Option<Stateful<Div>> {
 8167        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8168
 8169        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8170        let has_keybind = keybind.is_some();
 8171
 8172        let result = h_flex()
 8173            .id("ep-line-popover")
 8174            .py_0p5()
 8175            .pl_1()
 8176            .pr(padding_right)
 8177            .gap_1()
 8178            .rounded_md()
 8179            .border_1()
 8180            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8181            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8182            .shadow_sm()
 8183            .when(!has_keybind, |el| {
 8184                let status_colors = cx.theme().status();
 8185
 8186                el.bg(status_colors.error_background)
 8187                    .border_color(status_colors.error.opacity(0.6))
 8188                    .pl_2()
 8189                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8190                    .cursor_default()
 8191                    .hoverable_tooltip(move |_window, cx| {
 8192                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8193                    })
 8194            })
 8195            .children(keybind)
 8196            .child(
 8197                Label::new(label)
 8198                    .size(LabelSize::Small)
 8199                    .when(!has_keybind, |el| {
 8200                        el.color(cx.theme().status().error.into()).strikethrough()
 8201                    }),
 8202            )
 8203            .when(!has_keybind, |el| {
 8204                el.child(
 8205                    h_flex().ml_1().child(
 8206                        Icon::new(IconName::Info)
 8207                            .size(IconSize::Small)
 8208                            .color(cx.theme().status().error.into()),
 8209                    ),
 8210                )
 8211            })
 8212            .when_some(icon, |element, icon| {
 8213                element.child(
 8214                    div()
 8215                        .mt(px(1.5))
 8216                        .child(Icon::new(icon).size(IconSize::Small)),
 8217                )
 8218            });
 8219
 8220        Some(result)
 8221    }
 8222
 8223    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8224        let accent_color = cx.theme().colors().text_accent;
 8225        let editor_bg_color = cx.theme().colors().editor_background;
 8226        editor_bg_color.blend(accent_color.opacity(0.1))
 8227    }
 8228
 8229    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8230        let accent_color = cx.theme().colors().text_accent;
 8231        let editor_bg_color = cx.theme().colors().editor_background;
 8232        editor_bg_color.blend(accent_color.opacity(0.6))
 8233    }
 8234
 8235    fn render_edit_prediction_cursor_popover(
 8236        &self,
 8237        min_width: Pixels,
 8238        max_width: Pixels,
 8239        cursor_point: Point,
 8240        style: &EditorStyle,
 8241        accept_keystroke: Option<&gpui::Keystroke>,
 8242        _window: &Window,
 8243        cx: &mut Context<Editor>,
 8244    ) -> Option<AnyElement> {
 8245        let provider = self.edit_prediction_provider.as_ref()?;
 8246
 8247        if provider.provider.needs_terms_acceptance(cx) {
 8248            return Some(
 8249                h_flex()
 8250                    .min_w(min_width)
 8251                    .flex_1()
 8252                    .px_2()
 8253                    .py_1()
 8254                    .gap_3()
 8255                    .elevation_2(cx)
 8256                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8257                    .id("accept-terms")
 8258                    .cursor_pointer()
 8259                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8260                    .on_click(cx.listener(|this, _event, window, cx| {
 8261                        cx.stop_propagation();
 8262                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8263                        window.dispatch_action(
 8264                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8265                            cx,
 8266                        );
 8267                    }))
 8268                    .child(
 8269                        h_flex()
 8270                            .flex_1()
 8271                            .gap_2()
 8272                            .child(Icon::new(IconName::ZedPredict))
 8273                            .child(Label::new("Accept Terms of Service"))
 8274                            .child(div().w_full())
 8275                            .child(
 8276                                Icon::new(IconName::ArrowUpRight)
 8277                                    .color(Color::Muted)
 8278                                    .size(IconSize::Small),
 8279                            )
 8280                            .into_any_element(),
 8281                    )
 8282                    .into_any(),
 8283            );
 8284        }
 8285
 8286        let is_refreshing = provider.provider.is_refreshing(cx);
 8287
 8288        fn pending_completion_container() -> Div {
 8289            h_flex()
 8290                .h_full()
 8291                .flex_1()
 8292                .gap_2()
 8293                .child(Icon::new(IconName::ZedPredict))
 8294        }
 8295
 8296        let completion = match &self.active_inline_completion {
 8297            Some(prediction) => {
 8298                if !self.has_visible_completions_menu() {
 8299                    const RADIUS: Pixels = px(6.);
 8300                    const BORDER_WIDTH: Pixels = px(1.);
 8301
 8302                    return Some(
 8303                        h_flex()
 8304                            .elevation_2(cx)
 8305                            .border(BORDER_WIDTH)
 8306                            .border_color(cx.theme().colors().border)
 8307                            .when(accept_keystroke.is_none(), |el| {
 8308                                el.border_color(cx.theme().status().error)
 8309                            })
 8310                            .rounded(RADIUS)
 8311                            .rounded_tl(px(0.))
 8312                            .overflow_hidden()
 8313                            .child(div().px_1p5().child(match &prediction.completion {
 8314                                InlineCompletion::Move { target, snapshot } => {
 8315                                    use text::ToPoint as _;
 8316                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8317                                    {
 8318                                        Icon::new(IconName::ZedPredictDown)
 8319                                    } else {
 8320                                        Icon::new(IconName::ZedPredictUp)
 8321                                    }
 8322                                }
 8323                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8324                            }))
 8325                            .child(
 8326                                h_flex()
 8327                                    .gap_1()
 8328                                    .py_1()
 8329                                    .px_2()
 8330                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8331                                    .border_l_1()
 8332                                    .border_color(cx.theme().colors().border)
 8333                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8334                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8335                                        el.child(
 8336                                            Label::new("Hold")
 8337                                                .size(LabelSize::Small)
 8338                                                .when(accept_keystroke.is_none(), |el| {
 8339                                                    el.strikethrough()
 8340                                                })
 8341                                                .line_height_style(LineHeightStyle::UiLabel),
 8342                                        )
 8343                                    })
 8344                                    .id("edit_prediction_cursor_popover_keybind")
 8345                                    .when(accept_keystroke.is_none(), |el| {
 8346                                        let status_colors = cx.theme().status();
 8347
 8348                                        el.bg(status_colors.error_background)
 8349                                            .border_color(status_colors.error.opacity(0.6))
 8350                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8351                                            .cursor_default()
 8352                                            .hoverable_tooltip(move |_window, cx| {
 8353                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8354                                                    .into()
 8355                                            })
 8356                                    })
 8357                                    .when_some(
 8358                                        accept_keystroke.as_ref(),
 8359                                        |el, accept_keystroke| {
 8360                                            el.child(h_flex().children(ui::render_modifiers(
 8361                                                &accept_keystroke.modifiers,
 8362                                                PlatformStyle::platform(),
 8363                                                Some(Color::Default),
 8364                                                Some(IconSize::XSmall.rems().into()),
 8365                                                false,
 8366                                            )))
 8367                                        },
 8368                                    ),
 8369                            )
 8370                            .into_any(),
 8371                    );
 8372                }
 8373
 8374                self.render_edit_prediction_cursor_popover_preview(
 8375                    prediction,
 8376                    cursor_point,
 8377                    style,
 8378                    cx,
 8379                )?
 8380            }
 8381
 8382            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8383                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8384                    stale_completion,
 8385                    cursor_point,
 8386                    style,
 8387                    cx,
 8388                )?,
 8389
 8390                None => {
 8391                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8392                }
 8393            },
 8394
 8395            None => pending_completion_container().child(Label::new("No Prediction")),
 8396        };
 8397
 8398        let completion = if is_refreshing {
 8399            completion
 8400                .with_animation(
 8401                    "loading-completion",
 8402                    Animation::new(Duration::from_secs(2))
 8403                        .repeat()
 8404                        .with_easing(pulsating_between(0.4, 0.8)),
 8405                    |label, delta| label.opacity(delta),
 8406                )
 8407                .into_any_element()
 8408        } else {
 8409            completion.into_any_element()
 8410        };
 8411
 8412        let has_completion = self.active_inline_completion.is_some();
 8413
 8414        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8415        Some(
 8416            h_flex()
 8417                .min_w(min_width)
 8418                .max_w(max_width)
 8419                .flex_1()
 8420                .elevation_2(cx)
 8421                .border_color(cx.theme().colors().border)
 8422                .child(
 8423                    div()
 8424                        .flex_1()
 8425                        .py_1()
 8426                        .px_2()
 8427                        .overflow_hidden()
 8428                        .child(completion),
 8429                )
 8430                .when_some(accept_keystroke, |el, accept_keystroke| {
 8431                    if !accept_keystroke.modifiers.modified() {
 8432                        return el;
 8433                    }
 8434
 8435                    el.child(
 8436                        h_flex()
 8437                            .h_full()
 8438                            .border_l_1()
 8439                            .rounded_r_lg()
 8440                            .border_color(cx.theme().colors().border)
 8441                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8442                            .gap_1()
 8443                            .py_1()
 8444                            .px_2()
 8445                            .child(
 8446                                h_flex()
 8447                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8448                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8449                                    .child(h_flex().children(ui::render_modifiers(
 8450                                        &accept_keystroke.modifiers,
 8451                                        PlatformStyle::platform(),
 8452                                        Some(if !has_completion {
 8453                                            Color::Muted
 8454                                        } else {
 8455                                            Color::Default
 8456                                        }),
 8457                                        None,
 8458                                        false,
 8459                                    ))),
 8460                            )
 8461                            .child(Label::new("Preview").into_any_element())
 8462                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8463                    )
 8464                })
 8465                .into_any(),
 8466        )
 8467    }
 8468
 8469    fn render_edit_prediction_cursor_popover_preview(
 8470        &self,
 8471        completion: &InlineCompletionState,
 8472        cursor_point: Point,
 8473        style: &EditorStyle,
 8474        cx: &mut Context<Editor>,
 8475    ) -> Option<Div> {
 8476        use text::ToPoint as _;
 8477
 8478        fn render_relative_row_jump(
 8479            prefix: impl Into<String>,
 8480            current_row: u32,
 8481            target_row: u32,
 8482        ) -> Div {
 8483            let (row_diff, arrow) = if target_row < current_row {
 8484                (current_row - target_row, IconName::ArrowUp)
 8485            } else {
 8486                (target_row - current_row, IconName::ArrowDown)
 8487            };
 8488
 8489            h_flex()
 8490                .child(
 8491                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8492                        .color(Color::Muted)
 8493                        .size(LabelSize::Small),
 8494                )
 8495                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8496        }
 8497
 8498        match &completion.completion {
 8499            InlineCompletion::Move {
 8500                target, snapshot, ..
 8501            } => Some(
 8502                h_flex()
 8503                    .px_2()
 8504                    .gap_2()
 8505                    .flex_1()
 8506                    .child(
 8507                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8508                            Icon::new(IconName::ZedPredictDown)
 8509                        } else {
 8510                            Icon::new(IconName::ZedPredictUp)
 8511                        },
 8512                    )
 8513                    .child(Label::new("Jump to Edit")),
 8514            ),
 8515
 8516            InlineCompletion::Edit {
 8517                edits,
 8518                edit_preview,
 8519                snapshot,
 8520                display_mode: _,
 8521            } => {
 8522                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8523
 8524                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8525                    &snapshot,
 8526                    &edits,
 8527                    edit_preview.as_ref()?,
 8528                    true,
 8529                    cx,
 8530                )
 8531                .first_line_preview();
 8532
 8533                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8534                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8535
 8536                let preview = h_flex()
 8537                    .gap_1()
 8538                    .min_w_16()
 8539                    .child(styled_text)
 8540                    .when(has_more_lines, |parent| parent.child(""));
 8541
 8542                let left = if first_edit_row != cursor_point.row {
 8543                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8544                        .into_any_element()
 8545                } else {
 8546                    Icon::new(IconName::ZedPredict).into_any_element()
 8547                };
 8548
 8549                Some(
 8550                    h_flex()
 8551                        .h_full()
 8552                        .flex_1()
 8553                        .gap_2()
 8554                        .pr_1()
 8555                        .overflow_x_hidden()
 8556                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8557                        .child(left)
 8558                        .child(preview),
 8559                )
 8560            }
 8561        }
 8562    }
 8563
 8564    pub fn render_context_menu(
 8565        &self,
 8566        style: &EditorStyle,
 8567        max_height_in_lines: u32,
 8568        window: &mut Window,
 8569        cx: &mut Context<Editor>,
 8570    ) -> Option<AnyElement> {
 8571        let menu = self.context_menu.borrow();
 8572        let menu = menu.as_ref()?;
 8573        if !menu.visible() {
 8574            return None;
 8575        };
 8576        Some(menu.render(style, max_height_in_lines, window, cx))
 8577    }
 8578
 8579    fn render_context_menu_aside(
 8580        &mut self,
 8581        max_size: Size<Pixels>,
 8582        window: &mut Window,
 8583        cx: &mut Context<Editor>,
 8584    ) -> Option<AnyElement> {
 8585        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8586            if menu.visible() {
 8587                menu.render_aside(self, max_size, window, cx)
 8588            } else {
 8589                None
 8590            }
 8591        })
 8592    }
 8593
 8594    fn hide_context_menu(
 8595        &mut self,
 8596        window: &mut Window,
 8597        cx: &mut Context<Self>,
 8598    ) -> Option<CodeContextMenu> {
 8599        cx.notify();
 8600        self.completion_tasks.clear();
 8601        let context_menu = self.context_menu.borrow_mut().take();
 8602        self.stale_inline_completion_in_menu.take();
 8603        self.update_visible_inline_completion(window, cx);
 8604        context_menu
 8605    }
 8606
 8607    fn show_snippet_choices(
 8608        &mut self,
 8609        choices: &Vec<String>,
 8610        selection: Range<Anchor>,
 8611        cx: &mut Context<Self>,
 8612    ) {
 8613        if selection.start.buffer_id.is_none() {
 8614            return;
 8615        }
 8616        let buffer_id = selection.start.buffer_id.unwrap();
 8617        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8618        let id = post_inc(&mut self.next_completion_id);
 8619        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8620
 8621        if let Some(buffer) = buffer {
 8622            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8623                CompletionsMenu::new_snippet_choices(
 8624                    id,
 8625                    true,
 8626                    choices,
 8627                    selection,
 8628                    buffer,
 8629                    snippet_sort_order,
 8630                ),
 8631            ));
 8632        }
 8633    }
 8634
 8635    pub fn insert_snippet(
 8636        &mut self,
 8637        insertion_ranges: &[Range<usize>],
 8638        snippet: Snippet,
 8639        window: &mut Window,
 8640        cx: &mut Context<Self>,
 8641    ) -> Result<()> {
 8642        struct Tabstop<T> {
 8643            is_end_tabstop: bool,
 8644            ranges: Vec<Range<T>>,
 8645            choices: Option<Vec<String>>,
 8646        }
 8647
 8648        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8649            let snippet_text: Arc<str> = snippet.text.clone().into();
 8650            let edits = insertion_ranges
 8651                .iter()
 8652                .cloned()
 8653                .map(|range| (range, snippet_text.clone()));
 8654            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8655
 8656            let snapshot = &*buffer.read(cx);
 8657            let snippet = &snippet;
 8658            snippet
 8659                .tabstops
 8660                .iter()
 8661                .map(|tabstop| {
 8662                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8663                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8664                    });
 8665                    let mut tabstop_ranges = tabstop
 8666                        .ranges
 8667                        .iter()
 8668                        .flat_map(|tabstop_range| {
 8669                            let mut delta = 0_isize;
 8670                            insertion_ranges.iter().map(move |insertion_range| {
 8671                                let insertion_start = insertion_range.start as isize + delta;
 8672                                delta +=
 8673                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8674
 8675                                let start = ((insertion_start + tabstop_range.start) as usize)
 8676                                    .min(snapshot.len());
 8677                                let end = ((insertion_start + tabstop_range.end) as usize)
 8678                                    .min(snapshot.len());
 8679                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8680                            })
 8681                        })
 8682                        .collect::<Vec<_>>();
 8683                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8684
 8685                    Tabstop {
 8686                        is_end_tabstop,
 8687                        ranges: tabstop_ranges,
 8688                        choices: tabstop.choices.clone(),
 8689                    }
 8690                })
 8691                .collect::<Vec<_>>()
 8692        });
 8693        if let Some(tabstop) = tabstops.first() {
 8694            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8695                s.select_ranges(tabstop.ranges.iter().cloned());
 8696            });
 8697
 8698            if let Some(choices) = &tabstop.choices {
 8699                if let Some(selection) = tabstop.ranges.first() {
 8700                    self.show_snippet_choices(choices, selection.clone(), cx)
 8701                }
 8702            }
 8703
 8704            // If we're already at the last tabstop and it's at the end of the snippet,
 8705            // we're done, we don't need to keep the state around.
 8706            if !tabstop.is_end_tabstop {
 8707                let choices = tabstops
 8708                    .iter()
 8709                    .map(|tabstop| tabstop.choices.clone())
 8710                    .collect();
 8711
 8712                let ranges = tabstops
 8713                    .into_iter()
 8714                    .map(|tabstop| tabstop.ranges)
 8715                    .collect::<Vec<_>>();
 8716
 8717                self.snippet_stack.push(SnippetState {
 8718                    active_index: 0,
 8719                    ranges,
 8720                    choices,
 8721                });
 8722            }
 8723
 8724            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8725            if self.autoclose_regions.is_empty() {
 8726                let snapshot = self.buffer.read(cx).snapshot(cx);
 8727                for selection in &mut self.selections.all::<Point>(cx) {
 8728                    let selection_head = selection.head();
 8729                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8730                        continue;
 8731                    };
 8732
 8733                    let mut bracket_pair = None;
 8734                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8735                    let prev_chars = snapshot
 8736                        .reversed_chars_at(selection_head)
 8737                        .collect::<String>();
 8738                    for (pair, enabled) in scope.brackets() {
 8739                        if enabled
 8740                            && pair.close
 8741                            && prev_chars.starts_with(pair.start.as_str())
 8742                            && next_chars.starts_with(pair.end.as_str())
 8743                        {
 8744                            bracket_pair = Some(pair.clone());
 8745                            break;
 8746                        }
 8747                    }
 8748                    if let Some(pair) = bracket_pair {
 8749                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8750                        let autoclose_enabled =
 8751                            self.use_autoclose && snapshot_settings.use_autoclose;
 8752                        if autoclose_enabled {
 8753                            let start = snapshot.anchor_after(selection_head);
 8754                            let end = snapshot.anchor_after(selection_head);
 8755                            self.autoclose_regions.push(AutocloseRegion {
 8756                                selection_id: selection.id,
 8757                                range: start..end,
 8758                                pair,
 8759                            });
 8760                        }
 8761                    }
 8762                }
 8763            }
 8764        }
 8765        Ok(())
 8766    }
 8767
 8768    pub fn move_to_next_snippet_tabstop(
 8769        &mut self,
 8770        window: &mut Window,
 8771        cx: &mut Context<Self>,
 8772    ) -> bool {
 8773        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8774    }
 8775
 8776    pub fn move_to_prev_snippet_tabstop(
 8777        &mut self,
 8778        window: &mut Window,
 8779        cx: &mut Context<Self>,
 8780    ) -> bool {
 8781        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8782    }
 8783
 8784    pub fn move_to_snippet_tabstop(
 8785        &mut self,
 8786        bias: Bias,
 8787        window: &mut Window,
 8788        cx: &mut Context<Self>,
 8789    ) -> bool {
 8790        if let Some(mut snippet) = self.snippet_stack.pop() {
 8791            match bias {
 8792                Bias::Left => {
 8793                    if snippet.active_index > 0 {
 8794                        snippet.active_index -= 1;
 8795                    } else {
 8796                        self.snippet_stack.push(snippet);
 8797                        return false;
 8798                    }
 8799                }
 8800                Bias::Right => {
 8801                    if snippet.active_index + 1 < snippet.ranges.len() {
 8802                        snippet.active_index += 1;
 8803                    } else {
 8804                        self.snippet_stack.push(snippet);
 8805                        return false;
 8806                    }
 8807                }
 8808            }
 8809            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8810                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8811                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8812                });
 8813
 8814                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8815                    if let Some(selection) = current_ranges.first() {
 8816                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8817                    }
 8818                }
 8819
 8820                // If snippet state is not at the last tabstop, push it back on the stack
 8821                if snippet.active_index + 1 < snippet.ranges.len() {
 8822                    self.snippet_stack.push(snippet);
 8823                }
 8824                return true;
 8825            }
 8826        }
 8827
 8828        false
 8829    }
 8830
 8831    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8832        self.transact(window, cx, |this, window, cx| {
 8833            this.select_all(&SelectAll, window, cx);
 8834            this.insert("", window, cx);
 8835        });
 8836    }
 8837
 8838    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8839        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8840        self.transact(window, cx, |this, window, cx| {
 8841            this.select_autoclose_pair(window, cx);
 8842            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8843            if !this.linked_edit_ranges.is_empty() {
 8844                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8845                let snapshot = this.buffer.read(cx).snapshot(cx);
 8846
 8847                for selection in selections.iter() {
 8848                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8849                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8850                    if selection_start.buffer_id != selection_end.buffer_id {
 8851                        continue;
 8852                    }
 8853                    if let Some(ranges) =
 8854                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8855                    {
 8856                        for (buffer, entries) in ranges {
 8857                            linked_ranges.entry(buffer).or_default().extend(entries);
 8858                        }
 8859                    }
 8860                }
 8861            }
 8862
 8863            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8864            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8865            for selection in &mut selections {
 8866                if selection.is_empty() {
 8867                    let old_head = selection.head();
 8868                    let mut new_head =
 8869                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8870                            .to_point(&display_map);
 8871                    if let Some((buffer, line_buffer_range)) = display_map
 8872                        .buffer_snapshot
 8873                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8874                    {
 8875                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8876                        let indent_len = match indent_size.kind {
 8877                            IndentKind::Space => {
 8878                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8879                            }
 8880                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8881                        };
 8882                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8883                            let indent_len = indent_len.get();
 8884                            new_head = cmp::min(
 8885                                new_head,
 8886                                MultiBufferPoint::new(
 8887                                    old_head.row,
 8888                                    ((old_head.column - 1) / indent_len) * indent_len,
 8889                                ),
 8890                            );
 8891                        }
 8892                    }
 8893
 8894                    selection.set_head(new_head, SelectionGoal::None);
 8895                }
 8896            }
 8897
 8898            this.signature_help_state.set_backspace_pressed(true);
 8899            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8900                s.select(selections)
 8901            });
 8902            this.insert("", window, cx);
 8903            let empty_str: Arc<str> = Arc::from("");
 8904            for (buffer, edits) in linked_ranges {
 8905                let snapshot = buffer.read(cx).snapshot();
 8906                use text::ToPoint as TP;
 8907
 8908                let edits = edits
 8909                    .into_iter()
 8910                    .map(|range| {
 8911                        let end_point = TP::to_point(&range.end, &snapshot);
 8912                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8913
 8914                        if end_point == start_point {
 8915                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8916                                .saturating_sub(1);
 8917                            start_point =
 8918                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8919                        };
 8920
 8921                        (start_point..end_point, empty_str.clone())
 8922                    })
 8923                    .sorted_by_key(|(range, _)| range.start)
 8924                    .collect::<Vec<_>>();
 8925                buffer.update(cx, |this, cx| {
 8926                    this.edit(edits, None, cx);
 8927                })
 8928            }
 8929            this.refresh_inline_completion(true, false, window, cx);
 8930            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8931        });
 8932    }
 8933
 8934    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8935        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8936        self.transact(window, cx, |this, window, cx| {
 8937            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8938                s.move_with(|map, selection| {
 8939                    if selection.is_empty() {
 8940                        let cursor = movement::right(map, selection.head());
 8941                        selection.end = cursor;
 8942                        selection.reversed = true;
 8943                        selection.goal = SelectionGoal::None;
 8944                    }
 8945                })
 8946            });
 8947            this.insert("", window, cx);
 8948            this.refresh_inline_completion(true, false, window, cx);
 8949        });
 8950    }
 8951
 8952    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8953        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8954        if self.move_to_prev_snippet_tabstop(window, cx) {
 8955            return;
 8956        }
 8957        self.outdent(&Outdent, window, cx);
 8958    }
 8959
 8960    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8961        if self.move_to_next_snippet_tabstop(window, cx) {
 8962            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8963            return;
 8964        }
 8965        if self.read_only(cx) {
 8966            return;
 8967        }
 8968        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8969        let mut selections = self.selections.all_adjusted(cx);
 8970        let buffer = self.buffer.read(cx);
 8971        let snapshot = buffer.snapshot(cx);
 8972        let rows_iter = selections.iter().map(|s| s.head().row);
 8973        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8974
 8975        let has_some_cursor_in_whitespace = selections
 8976            .iter()
 8977            .filter(|selection| selection.is_empty())
 8978            .any(|selection| {
 8979                let cursor = selection.head();
 8980                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8981                cursor.column < current_indent.len
 8982            });
 8983
 8984        let mut edits = Vec::new();
 8985        let mut prev_edited_row = 0;
 8986        let mut row_delta = 0;
 8987        for selection in &mut selections {
 8988            if selection.start.row != prev_edited_row {
 8989                row_delta = 0;
 8990            }
 8991            prev_edited_row = selection.end.row;
 8992
 8993            // If the selection is non-empty, then increase the indentation of the selected lines.
 8994            if !selection.is_empty() {
 8995                row_delta =
 8996                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8997                continue;
 8998            }
 8999
 9000            let cursor = selection.head();
 9001            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9002            if let Some(suggested_indent) =
 9003                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9004            {
 9005                // Don't do anything if already at suggested indent
 9006                // and there is any other cursor which is not
 9007                if has_some_cursor_in_whitespace
 9008                    && cursor.column == current_indent.len
 9009                    && current_indent.len == suggested_indent.len
 9010                {
 9011                    continue;
 9012                }
 9013
 9014                // Adjust line and move cursor to suggested indent
 9015                // if cursor is not at suggested indent
 9016                if cursor.column < suggested_indent.len
 9017                    && cursor.column <= current_indent.len
 9018                    && current_indent.len <= suggested_indent.len
 9019                {
 9020                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9021                    selection.end = selection.start;
 9022                    if row_delta == 0 {
 9023                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9024                            cursor.row,
 9025                            current_indent,
 9026                            suggested_indent,
 9027                        ));
 9028                        row_delta = suggested_indent.len - current_indent.len;
 9029                    }
 9030                    continue;
 9031                }
 9032
 9033                // If current indent is more than suggested indent
 9034                // only move cursor to current indent and skip indent
 9035                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9036                    selection.start = Point::new(cursor.row, current_indent.len);
 9037                    selection.end = selection.start;
 9038                    continue;
 9039                }
 9040            }
 9041
 9042            // Otherwise, insert a hard or soft tab.
 9043            let settings = buffer.language_settings_at(cursor, cx);
 9044            let tab_size = if settings.hard_tabs {
 9045                IndentSize::tab()
 9046            } else {
 9047                let tab_size = settings.tab_size.get();
 9048                let indent_remainder = snapshot
 9049                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9050                    .flat_map(str::chars)
 9051                    .fold(row_delta % tab_size, |counter: u32, c| {
 9052                        if c == '\t' {
 9053                            0
 9054                        } else {
 9055                            (counter + 1) % tab_size
 9056                        }
 9057                    });
 9058
 9059                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9060                IndentSize::spaces(chars_to_next_tab_stop)
 9061            };
 9062            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9063            selection.end = selection.start;
 9064            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9065            row_delta += tab_size.len;
 9066        }
 9067
 9068        self.transact(window, cx, |this, window, cx| {
 9069            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9070            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9071                s.select(selections)
 9072            });
 9073            this.refresh_inline_completion(true, false, window, cx);
 9074        });
 9075    }
 9076
 9077    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9078        if self.read_only(cx) {
 9079            return;
 9080        }
 9081        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9082        let mut selections = self.selections.all::<Point>(cx);
 9083        let mut prev_edited_row = 0;
 9084        let mut row_delta = 0;
 9085        let mut edits = Vec::new();
 9086        let buffer = self.buffer.read(cx);
 9087        let snapshot = buffer.snapshot(cx);
 9088        for selection in &mut selections {
 9089            if selection.start.row != prev_edited_row {
 9090                row_delta = 0;
 9091            }
 9092            prev_edited_row = selection.end.row;
 9093
 9094            row_delta =
 9095                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9096        }
 9097
 9098        self.transact(window, cx, |this, window, cx| {
 9099            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9100            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9101                s.select(selections)
 9102            });
 9103        });
 9104    }
 9105
 9106    fn indent_selection(
 9107        buffer: &MultiBuffer,
 9108        snapshot: &MultiBufferSnapshot,
 9109        selection: &mut Selection<Point>,
 9110        edits: &mut Vec<(Range<Point>, String)>,
 9111        delta_for_start_row: u32,
 9112        cx: &App,
 9113    ) -> u32 {
 9114        let settings = buffer.language_settings_at(selection.start, cx);
 9115        let tab_size = settings.tab_size.get();
 9116        let indent_kind = if settings.hard_tabs {
 9117            IndentKind::Tab
 9118        } else {
 9119            IndentKind::Space
 9120        };
 9121        let mut start_row = selection.start.row;
 9122        let mut end_row = selection.end.row + 1;
 9123
 9124        // If a selection ends at the beginning of a line, don't indent
 9125        // that last line.
 9126        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9127            end_row -= 1;
 9128        }
 9129
 9130        // Avoid re-indenting a row that has already been indented by a
 9131        // previous selection, but still update this selection's column
 9132        // to reflect that indentation.
 9133        if delta_for_start_row > 0 {
 9134            start_row += 1;
 9135            selection.start.column += delta_for_start_row;
 9136            if selection.end.row == selection.start.row {
 9137                selection.end.column += delta_for_start_row;
 9138            }
 9139        }
 9140
 9141        let mut delta_for_end_row = 0;
 9142        let has_multiple_rows = start_row + 1 != end_row;
 9143        for row in start_row..end_row {
 9144            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9145            let indent_delta = match (current_indent.kind, indent_kind) {
 9146                (IndentKind::Space, IndentKind::Space) => {
 9147                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9148                    IndentSize::spaces(columns_to_next_tab_stop)
 9149                }
 9150                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9151                (_, IndentKind::Tab) => IndentSize::tab(),
 9152            };
 9153
 9154            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9155                0
 9156            } else {
 9157                selection.start.column
 9158            };
 9159            let row_start = Point::new(row, start);
 9160            edits.push((
 9161                row_start..row_start,
 9162                indent_delta.chars().collect::<String>(),
 9163            ));
 9164
 9165            // Update this selection's endpoints to reflect the indentation.
 9166            if row == selection.start.row {
 9167                selection.start.column += indent_delta.len;
 9168            }
 9169            if row == selection.end.row {
 9170                selection.end.column += indent_delta.len;
 9171                delta_for_end_row = indent_delta.len;
 9172            }
 9173        }
 9174
 9175        if selection.start.row == selection.end.row {
 9176            delta_for_start_row + delta_for_end_row
 9177        } else {
 9178            delta_for_end_row
 9179        }
 9180    }
 9181
 9182    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9183        if self.read_only(cx) {
 9184            return;
 9185        }
 9186        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9187        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9188        let selections = self.selections.all::<Point>(cx);
 9189        let mut deletion_ranges = Vec::new();
 9190        let mut last_outdent = None;
 9191        {
 9192            let buffer = self.buffer.read(cx);
 9193            let snapshot = buffer.snapshot(cx);
 9194            for selection in &selections {
 9195                let settings = buffer.language_settings_at(selection.start, cx);
 9196                let tab_size = settings.tab_size.get();
 9197                let mut rows = selection.spanned_rows(false, &display_map);
 9198
 9199                // Avoid re-outdenting a row that has already been outdented by a
 9200                // previous selection.
 9201                if let Some(last_row) = last_outdent {
 9202                    if last_row == rows.start {
 9203                        rows.start = rows.start.next_row();
 9204                    }
 9205                }
 9206                let has_multiple_rows = rows.len() > 1;
 9207                for row in rows.iter_rows() {
 9208                    let indent_size = snapshot.indent_size_for_line(row);
 9209                    if indent_size.len > 0 {
 9210                        let deletion_len = match indent_size.kind {
 9211                            IndentKind::Space => {
 9212                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9213                                if columns_to_prev_tab_stop == 0 {
 9214                                    tab_size
 9215                                } else {
 9216                                    columns_to_prev_tab_stop
 9217                                }
 9218                            }
 9219                            IndentKind::Tab => 1,
 9220                        };
 9221                        let start = if has_multiple_rows
 9222                            || deletion_len > selection.start.column
 9223                            || indent_size.len < selection.start.column
 9224                        {
 9225                            0
 9226                        } else {
 9227                            selection.start.column - deletion_len
 9228                        };
 9229                        deletion_ranges.push(
 9230                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9231                        );
 9232                        last_outdent = Some(row);
 9233                    }
 9234                }
 9235            }
 9236        }
 9237
 9238        self.transact(window, cx, |this, window, cx| {
 9239            this.buffer.update(cx, |buffer, cx| {
 9240                let empty_str: Arc<str> = Arc::default();
 9241                buffer.edit(
 9242                    deletion_ranges
 9243                        .into_iter()
 9244                        .map(|range| (range, empty_str.clone())),
 9245                    None,
 9246                    cx,
 9247                );
 9248            });
 9249            let selections = this.selections.all::<usize>(cx);
 9250            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9251                s.select(selections)
 9252            });
 9253        });
 9254    }
 9255
 9256    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9257        if self.read_only(cx) {
 9258            return;
 9259        }
 9260        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9261        let selections = self
 9262            .selections
 9263            .all::<usize>(cx)
 9264            .into_iter()
 9265            .map(|s| s.range());
 9266
 9267        self.transact(window, cx, |this, window, cx| {
 9268            this.buffer.update(cx, |buffer, cx| {
 9269                buffer.autoindent_ranges(selections, cx);
 9270            });
 9271            let selections = this.selections.all::<usize>(cx);
 9272            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9273                s.select(selections)
 9274            });
 9275        });
 9276    }
 9277
 9278    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9279        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9280        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9281        let selections = self.selections.all::<Point>(cx);
 9282
 9283        let mut new_cursors = Vec::new();
 9284        let mut edit_ranges = Vec::new();
 9285        let mut selections = selections.iter().peekable();
 9286        while let Some(selection) = selections.next() {
 9287            let mut rows = selection.spanned_rows(false, &display_map);
 9288            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9289
 9290            // Accumulate contiguous regions of rows that we want to delete.
 9291            while let Some(next_selection) = selections.peek() {
 9292                let next_rows = next_selection.spanned_rows(false, &display_map);
 9293                if next_rows.start <= rows.end {
 9294                    rows.end = next_rows.end;
 9295                    selections.next().unwrap();
 9296                } else {
 9297                    break;
 9298                }
 9299            }
 9300
 9301            let buffer = &display_map.buffer_snapshot;
 9302            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9303            let edit_end;
 9304            let cursor_buffer_row;
 9305            if buffer.max_point().row >= rows.end.0 {
 9306                // If there's a line after the range, delete the \n from the end of the row range
 9307                // and position the cursor on the next line.
 9308                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9309                cursor_buffer_row = rows.end;
 9310            } else {
 9311                // If there isn't a line after the range, delete the \n from the line before the
 9312                // start of the row range and position the cursor there.
 9313                edit_start = edit_start.saturating_sub(1);
 9314                edit_end = buffer.len();
 9315                cursor_buffer_row = rows.start.previous_row();
 9316            }
 9317
 9318            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9319            *cursor.column_mut() =
 9320                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9321
 9322            new_cursors.push((
 9323                selection.id,
 9324                buffer.anchor_after(cursor.to_point(&display_map)),
 9325            ));
 9326            edit_ranges.push(edit_start..edit_end);
 9327        }
 9328
 9329        self.transact(window, cx, |this, window, cx| {
 9330            let buffer = this.buffer.update(cx, |buffer, cx| {
 9331                let empty_str: Arc<str> = Arc::default();
 9332                buffer.edit(
 9333                    edit_ranges
 9334                        .into_iter()
 9335                        .map(|range| (range, empty_str.clone())),
 9336                    None,
 9337                    cx,
 9338                );
 9339                buffer.snapshot(cx)
 9340            });
 9341            let new_selections = new_cursors
 9342                .into_iter()
 9343                .map(|(id, cursor)| {
 9344                    let cursor = cursor.to_point(&buffer);
 9345                    Selection {
 9346                        id,
 9347                        start: cursor,
 9348                        end: cursor,
 9349                        reversed: false,
 9350                        goal: SelectionGoal::None,
 9351                    }
 9352                })
 9353                .collect();
 9354
 9355            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9356                s.select(new_selections);
 9357            });
 9358        });
 9359    }
 9360
 9361    pub fn join_lines_impl(
 9362        &mut self,
 9363        insert_whitespace: bool,
 9364        window: &mut Window,
 9365        cx: &mut Context<Self>,
 9366    ) {
 9367        if self.read_only(cx) {
 9368            return;
 9369        }
 9370        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9371        for selection in self.selections.all::<Point>(cx) {
 9372            let start = MultiBufferRow(selection.start.row);
 9373            // Treat single line selections as if they include the next line. Otherwise this action
 9374            // would do nothing for single line selections individual cursors.
 9375            let end = if selection.start.row == selection.end.row {
 9376                MultiBufferRow(selection.start.row + 1)
 9377            } else {
 9378                MultiBufferRow(selection.end.row)
 9379            };
 9380
 9381            if let Some(last_row_range) = row_ranges.last_mut() {
 9382                if start <= last_row_range.end {
 9383                    last_row_range.end = end;
 9384                    continue;
 9385                }
 9386            }
 9387            row_ranges.push(start..end);
 9388        }
 9389
 9390        let snapshot = self.buffer.read(cx).snapshot(cx);
 9391        let mut cursor_positions = Vec::new();
 9392        for row_range in &row_ranges {
 9393            let anchor = snapshot.anchor_before(Point::new(
 9394                row_range.end.previous_row().0,
 9395                snapshot.line_len(row_range.end.previous_row()),
 9396            ));
 9397            cursor_positions.push(anchor..anchor);
 9398        }
 9399
 9400        self.transact(window, cx, |this, window, cx| {
 9401            for row_range in row_ranges.into_iter().rev() {
 9402                for row in row_range.iter_rows().rev() {
 9403                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9404                    let next_line_row = row.next_row();
 9405                    let indent = snapshot.indent_size_for_line(next_line_row);
 9406                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9407
 9408                    let replace =
 9409                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9410                            " "
 9411                        } else {
 9412                            ""
 9413                        };
 9414
 9415                    this.buffer.update(cx, |buffer, cx| {
 9416                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9417                    });
 9418                }
 9419            }
 9420
 9421            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9422                s.select_anchor_ranges(cursor_positions)
 9423            });
 9424        });
 9425    }
 9426
 9427    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9428        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9429        self.join_lines_impl(true, window, cx);
 9430    }
 9431
 9432    pub fn sort_lines_case_sensitive(
 9433        &mut self,
 9434        _: &SortLinesCaseSensitive,
 9435        window: &mut Window,
 9436        cx: &mut Context<Self>,
 9437    ) {
 9438        self.manipulate_lines(window, cx, |lines| lines.sort())
 9439    }
 9440
 9441    pub fn sort_lines_case_insensitive(
 9442        &mut self,
 9443        _: &SortLinesCaseInsensitive,
 9444        window: &mut Window,
 9445        cx: &mut Context<Self>,
 9446    ) {
 9447        self.manipulate_lines(window, cx, |lines| {
 9448            lines.sort_by_key(|line| line.to_lowercase())
 9449        })
 9450    }
 9451
 9452    pub fn unique_lines_case_insensitive(
 9453        &mut self,
 9454        _: &UniqueLinesCaseInsensitive,
 9455        window: &mut Window,
 9456        cx: &mut Context<Self>,
 9457    ) {
 9458        self.manipulate_lines(window, cx, |lines| {
 9459            let mut seen = HashSet::default();
 9460            lines.retain(|line| seen.insert(line.to_lowercase()));
 9461        })
 9462    }
 9463
 9464    pub fn unique_lines_case_sensitive(
 9465        &mut self,
 9466        _: &UniqueLinesCaseSensitive,
 9467        window: &mut Window,
 9468        cx: &mut Context<Self>,
 9469    ) {
 9470        self.manipulate_lines(window, cx, |lines| {
 9471            let mut seen = HashSet::default();
 9472            lines.retain(|line| seen.insert(*line));
 9473        })
 9474    }
 9475
 9476    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9477        let Some(project) = self.project.clone() else {
 9478            return;
 9479        };
 9480        self.reload(project, window, cx)
 9481            .detach_and_notify_err(window, cx);
 9482    }
 9483
 9484    pub fn restore_file(
 9485        &mut self,
 9486        _: &::git::RestoreFile,
 9487        window: &mut Window,
 9488        cx: &mut Context<Self>,
 9489    ) {
 9490        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9491        let mut buffer_ids = HashSet::default();
 9492        let snapshot = self.buffer().read(cx).snapshot(cx);
 9493        for selection in self.selections.all::<usize>(cx) {
 9494            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9495        }
 9496
 9497        let buffer = self.buffer().read(cx);
 9498        let ranges = buffer_ids
 9499            .into_iter()
 9500            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9501            .collect::<Vec<_>>();
 9502
 9503        self.restore_hunks_in_ranges(ranges, window, cx);
 9504    }
 9505
 9506    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9507        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9508        let selections = self
 9509            .selections
 9510            .all(cx)
 9511            .into_iter()
 9512            .map(|s| s.range())
 9513            .collect();
 9514        self.restore_hunks_in_ranges(selections, window, cx);
 9515    }
 9516
 9517    pub fn restore_hunks_in_ranges(
 9518        &mut self,
 9519        ranges: Vec<Range<Point>>,
 9520        window: &mut Window,
 9521        cx: &mut Context<Editor>,
 9522    ) {
 9523        let mut revert_changes = HashMap::default();
 9524        let chunk_by = self
 9525            .snapshot(window, cx)
 9526            .hunks_for_ranges(ranges)
 9527            .into_iter()
 9528            .chunk_by(|hunk| hunk.buffer_id);
 9529        for (buffer_id, hunks) in &chunk_by {
 9530            let hunks = hunks.collect::<Vec<_>>();
 9531            for hunk in &hunks {
 9532                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9533            }
 9534            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9535        }
 9536        drop(chunk_by);
 9537        if !revert_changes.is_empty() {
 9538            self.transact(window, cx, |editor, window, cx| {
 9539                editor.restore(revert_changes, window, cx);
 9540            });
 9541        }
 9542    }
 9543
 9544    pub fn open_active_item_in_terminal(
 9545        &mut self,
 9546        _: &OpenInTerminal,
 9547        window: &mut Window,
 9548        cx: &mut Context<Self>,
 9549    ) {
 9550        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9551            let project_path = buffer.read(cx).project_path(cx)?;
 9552            let project = self.project.as_ref()?.read(cx);
 9553            let entry = project.entry_for_path(&project_path, cx)?;
 9554            let parent = match &entry.canonical_path {
 9555                Some(canonical_path) => canonical_path.to_path_buf(),
 9556                None => project.absolute_path(&project_path, cx)?,
 9557            }
 9558            .parent()?
 9559            .to_path_buf();
 9560            Some(parent)
 9561        }) {
 9562            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9563        }
 9564    }
 9565
 9566    fn set_breakpoint_context_menu(
 9567        &mut self,
 9568        display_row: DisplayRow,
 9569        position: Option<Anchor>,
 9570        clicked_point: gpui::Point<Pixels>,
 9571        window: &mut Window,
 9572        cx: &mut Context<Self>,
 9573    ) {
 9574        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9575            return;
 9576        }
 9577        let source = self
 9578            .buffer
 9579            .read(cx)
 9580            .snapshot(cx)
 9581            .anchor_before(Point::new(display_row.0, 0u32));
 9582
 9583        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9584
 9585        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9586            self,
 9587            source,
 9588            clicked_point,
 9589            context_menu,
 9590            window,
 9591            cx,
 9592        );
 9593    }
 9594
 9595    fn add_edit_breakpoint_block(
 9596        &mut self,
 9597        anchor: Anchor,
 9598        breakpoint: &Breakpoint,
 9599        edit_action: BreakpointPromptEditAction,
 9600        window: &mut Window,
 9601        cx: &mut Context<Self>,
 9602    ) {
 9603        let weak_editor = cx.weak_entity();
 9604        let bp_prompt = cx.new(|cx| {
 9605            BreakpointPromptEditor::new(
 9606                weak_editor,
 9607                anchor,
 9608                breakpoint.clone(),
 9609                edit_action,
 9610                window,
 9611                cx,
 9612            )
 9613        });
 9614
 9615        let height = bp_prompt.update(cx, |this, cx| {
 9616            this.prompt
 9617                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9618        });
 9619        let cloned_prompt = bp_prompt.clone();
 9620        let blocks = vec![BlockProperties {
 9621            style: BlockStyle::Sticky,
 9622            placement: BlockPlacement::Above(anchor),
 9623            height: Some(height),
 9624            render: Arc::new(move |cx| {
 9625                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9626                cloned_prompt.clone().into_any_element()
 9627            }),
 9628            priority: 0,
 9629            render_in_minimap: true,
 9630        }];
 9631
 9632        let focus_handle = bp_prompt.focus_handle(cx);
 9633        window.focus(&focus_handle);
 9634
 9635        let block_ids = self.insert_blocks(blocks, None, cx);
 9636        bp_prompt.update(cx, |prompt, _| {
 9637            prompt.add_block_ids(block_ids);
 9638        });
 9639    }
 9640
 9641    pub(crate) fn breakpoint_at_row(
 9642        &self,
 9643        row: u32,
 9644        window: &mut Window,
 9645        cx: &mut Context<Self>,
 9646    ) -> Option<(Anchor, Breakpoint)> {
 9647        let snapshot = self.snapshot(window, cx);
 9648        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9649
 9650        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9651    }
 9652
 9653    pub(crate) fn breakpoint_at_anchor(
 9654        &self,
 9655        breakpoint_position: Anchor,
 9656        snapshot: &EditorSnapshot,
 9657        cx: &mut Context<Self>,
 9658    ) -> Option<(Anchor, Breakpoint)> {
 9659        let project = self.project.clone()?;
 9660
 9661        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9662            snapshot
 9663                .buffer_snapshot
 9664                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9665        })?;
 9666
 9667        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9668        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9669        let buffer_snapshot = buffer.read(cx).snapshot();
 9670
 9671        let row = buffer_snapshot
 9672            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9673            .row;
 9674
 9675        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9676        let anchor_end = snapshot
 9677            .buffer_snapshot
 9678            .anchor_after(Point::new(row, line_len));
 9679
 9680        let bp = self
 9681            .breakpoint_store
 9682            .as_ref()?
 9683            .read_with(cx, |breakpoint_store, cx| {
 9684                breakpoint_store
 9685                    .breakpoints(
 9686                        &buffer,
 9687                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9688                        &buffer_snapshot,
 9689                        cx,
 9690                    )
 9691                    .next()
 9692                    .and_then(|(bp, _)| {
 9693                        let breakpoint_row = buffer_snapshot
 9694                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9695                            .row;
 9696
 9697                        if breakpoint_row == row {
 9698                            snapshot
 9699                                .buffer_snapshot
 9700                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9701                                .map(|position| (position, bp.bp.clone()))
 9702                        } else {
 9703                            None
 9704                        }
 9705                    })
 9706            });
 9707        bp
 9708    }
 9709
 9710    pub fn edit_log_breakpoint(
 9711        &mut self,
 9712        _: &EditLogBreakpoint,
 9713        window: &mut Window,
 9714        cx: &mut Context<Self>,
 9715    ) {
 9716        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9717            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9718                message: None,
 9719                state: BreakpointState::Enabled,
 9720                condition: None,
 9721                hit_condition: None,
 9722            });
 9723
 9724            self.add_edit_breakpoint_block(
 9725                anchor,
 9726                &breakpoint,
 9727                BreakpointPromptEditAction::Log,
 9728                window,
 9729                cx,
 9730            );
 9731        }
 9732    }
 9733
 9734    fn breakpoints_at_cursors(
 9735        &self,
 9736        window: &mut Window,
 9737        cx: &mut Context<Self>,
 9738    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9739        let snapshot = self.snapshot(window, cx);
 9740        let cursors = self
 9741            .selections
 9742            .disjoint_anchors()
 9743            .into_iter()
 9744            .map(|selection| {
 9745                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9746
 9747                let breakpoint_position = self
 9748                    .breakpoint_at_row(cursor_position.row, window, cx)
 9749                    .map(|bp| bp.0)
 9750                    .unwrap_or_else(|| {
 9751                        snapshot
 9752                            .display_snapshot
 9753                            .buffer_snapshot
 9754                            .anchor_after(Point::new(cursor_position.row, 0))
 9755                    });
 9756
 9757                let breakpoint = self
 9758                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9759                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9760
 9761                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9762            })
 9763            // 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.
 9764            .collect::<HashMap<Anchor, _>>();
 9765
 9766        cursors.into_iter().collect()
 9767    }
 9768
 9769    pub fn enable_breakpoint(
 9770        &mut self,
 9771        _: &crate::actions::EnableBreakpoint,
 9772        window: &mut Window,
 9773        cx: &mut Context<Self>,
 9774    ) {
 9775        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9776            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9777                continue;
 9778            };
 9779            self.edit_breakpoint_at_anchor(
 9780                anchor,
 9781                breakpoint,
 9782                BreakpointEditAction::InvertState,
 9783                cx,
 9784            );
 9785        }
 9786    }
 9787
 9788    pub fn disable_breakpoint(
 9789        &mut self,
 9790        _: &crate::actions::DisableBreakpoint,
 9791        window: &mut Window,
 9792        cx: &mut Context<Self>,
 9793    ) {
 9794        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9795            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9796                continue;
 9797            };
 9798            self.edit_breakpoint_at_anchor(
 9799                anchor,
 9800                breakpoint,
 9801                BreakpointEditAction::InvertState,
 9802                cx,
 9803            );
 9804        }
 9805    }
 9806
 9807    pub fn toggle_breakpoint(
 9808        &mut self,
 9809        _: &crate::actions::ToggleBreakpoint,
 9810        window: &mut Window,
 9811        cx: &mut Context<Self>,
 9812    ) {
 9813        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9814            if let Some(breakpoint) = breakpoint {
 9815                self.edit_breakpoint_at_anchor(
 9816                    anchor,
 9817                    breakpoint,
 9818                    BreakpointEditAction::Toggle,
 9819                    cx,
 9820                );
 9821            } else {
 9822                self.edit_breakpoint_at_anchor(
 9823                    anchor,
 9824                    Breakpoint::new_standard(),
 9825                    BreakpointEditAction::Toggle,
 9826                    cx,
 9827                );
 9828            }
 9829        }
 9830    }
 9831
 9832    pub fn edit_breakpoint_at_anchor(
 9833        &mut self,
 9834        breakpoint_position: Anchor,
 9835        breakpoint: Breakpoint,
 9836        edit_action: BreakpointEditAction,
 9837        cx: &mut Context<Self>,
 9838    ) {
 9839        let Some(breakpoint_store) = &self.breakpoint_store else {
 9840            return;
 9841        };
 9842
 9843        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9844            if breakpoint_position == Anchor::min() {
 9845                self.buffer()
 9846                    .read(cx)
 9847                    .excerpt_buffer_ids()
 9848                    .into_iter()
 9849                    .next()
 9850            } else {
 9851                None
 9852            }
 9853        }) else {
 9854            return;
 9855        };
 9856
 9857        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9858            return;
 9859        };
 9860
 9861        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9862            breakpoint_store.toggle_breakpoint(
 9863                buffer,
 9864                BreakpointWithPosition {
 9865                    position: breakpoint_position.text_anchor,
 9866                    bp: breakpoint,
 9867                },
 9868                edit_action,
 9869                cx,
 9870            );
 9871        });
 9872
 9873        cx.notify();
 9874    }
 9875
 9876    #[cfg(any(test, feature = "test-support"))]
 9877    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9878        self.breakpoint_store.clone()
 9879    }
 9880
 9881    pub fn prepare_restore_change(
 9882        &self,
 9883        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9884        hunk: &MultiBufferDiffHunk,
 9885        cx: &mut App,
 9886    ) -> Option<()> {
 9887        if hunk.is_created_file() {
 9888            return None;
 9889        }
 9890        let buffer = self.buffer.read(cx);
 9891        let diff = buffer.diff_for(hunk.buffer_id)?;
 9892        let buffer = buffer.buffer(hunk.buffer_id)?;
 9893        let buffer = buffer.read(cx);
 9894        let original_text = diff
 9895            .read(cx)
 9896            .base_text()
 9897            .as_rope()
 9898            .slice(hunk.diff_base_byte_range.clone());
 9899        let buffer_snapshot = buffer.snapshot();
 9900        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9901        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9902            probe
 9903                .0
 9904                .start
 9905                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9906                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9907        }) {
 9908            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9909            Some(())
 9910        } else {
 9911            None
 9912        }
 9913    }
 9914
 9915    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9916        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9917    }
 9918
 9919    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9920        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9921    }
 9922
 9923    fn manipulate_lines<Fn>(
 9924        &mut self,
 9925        window: &mut Window,
 9926        cx: &mut Context<Self>,
 9927        mut callback: Fn,
 9928    ) where
 9929        Fn: FnMut(&mut Vec<&str>),
 9930    {
 9931        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9932
 9933        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9934        let buffer = self.buffer.read(cx).snapshot(cx);
 9935
 9936        let mut edits = Vec::new();
 9937
 9938        let selections = self.selections.all::<Point>(cx);
 9939        let mut selections = selections.iter().peekable();
 9940        let mut contiguous_row_selections = Vec::new();
 9941        let mut new_selections = Vec::new();
 9942        let mut added_lines = 0;
 9943        let mut removed_lines = 0;
 9944
 9945        while let Some(selection) = selections.next() {
 9946            let (start_row, end_row) = consume_contiguous_rows(
 9947                &mut contiguous_row_selections,
 9948                selection,
 9949                &display_map,
 9950                &mut selections,
 9951            );
 9952
 9953            let start_point = Point::new(start_row.0, 0);
 9954            let end_point = Point::new(
 9955                end_row.previous_row().0,
 9956                buffer.line_len(end_row.previous_row()),
 9957            );
 9958            let text = buffer
 9959                .text_for_range(start_point..end_point)
 9960                .collect::<String>();
 9961
 9962            let mut lines = text.split('\n').collect_vec();
 9963
 9964            let lines_before = lines.len();
 9965            callback(&mut lines);
 9966            let lines_after = lines.len();
 9967
 9968            edits.push((start_point..end_point, lines.join("\n")));
 9969
 9970            // Selections must change based on added and removed line count
 9971            let start_row =
 9972                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9973            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9974            new_selections.push(Selection {
 9975                id: selection.id,
 9976                start: start_row,
 9977                end: end_row,
 9978                goal: SelectionGoal::None,
 9979                reversed: selection.reversed,
 9980            });
 9981
 9982            if lines_after > lines_before {
 9983                added_lines += lines_after - lines_before;
 9984            } else if lines_before > lines_after {
 9985                removed_lines += lines_before - lines_after;
 9986            }
 9987        }
 9988
 9989        self.transact(window, cx, |this, window, cx| {
 9990            let buffer = this.buffer.update(cx, |buffer, cx| {
 9991                buffer.edit(edits, None, cx);
 9992                buffer.snapshot(cx)
 9993            });
 9994
 9995            // Recalculate offsets on newly edited buffer
 9996            let new_selections = new_selections
 9997                .iter()
 9998                .map(|s| {
 9999                    let start_point = Point::new(s.start.0, 0);
10000                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10001                    Selection {
10002                        id: s.id,
10003                        start: buffer.point_to_offset(start_point),
10004                        end: buffer.point_to_offset(end_point),
10005                        goal: s.goal,
10006                        reversed: s.reversed,
10007                    }
10008                })
10009                .collect();
10010
10011            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10012                s.select(new_selections);
10013            });
10014
10015            this.request_autoscroll(Autoscroll::fit(), cx);
10016        });
10017    }
10018
10019    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10020        self.manipulate_text(window, cx, |text| {
10021            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10022            if has_upper_case_characters {
10023                text.to_lowercase()
10024            } else {
10025                text.to_uppercase()
10026            }
10027        })
10028    }
10029
10030    pub fn convert_to_upper_case(
10031        &mut self,
10032        _: &ConvertToUpperCase,
10033        window: &mut Window,
10034        cx: &mut Context<Self>,
10035    ) {
10036        self.manipulate_text(window, cx, |text| text.to_uppercase())
10037    }
10038
10039    pub fn convert_to_lower_case(
10040        &mut self,
10041        _: &ConvertToLowerCase,
10042        window: &mut Window,
10043        cx: &mut Context<Self>,
10044    ) {
10045        self.manipulate_text(window, cx, |text| text.to_lowercase())
10046    }
10047
10048    pub fn convert_to_title_case(
10049        &mut self,
10050        _: &ConvertToTitleCase,
10051        window: &mut Window,
10052        cx: &mut Context<Self>,
10053    ) {
10054        self.manipulate_text(window, cx, |text| {
10055            text.split('\n')
10056                .map(|line| line.to_case(Case::Title))
10057                .join("\n")
10058        })
10059    }
10060
10061    pub fn convert_to_snake_case(
10062        &mut self,
10063        _: &ConvertToSnakeCase,
10064        window: &mut Window,
10065        cx: &mut Context<Self>,
10066    ) {
10067        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10068    }
10069
10070    pub fn convert_to_kebab_case(
10071        &mut self,
10072        _: &ConvertToKebabCase,
10073        window: &mut Window,
10074        cx: &mut Context<Self>,
10075    ) {
10076        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10077    }
10078
10079    pub fn convert_to_upper_camel_case(
10080        &mut self,
10081        _: &ConvertToUpperCamelCase,
10082        window: &mut Window,
10083        cx: &mut Context<Self>,
10084    ) {
10085        self.manipulate_text(window, cx, |text| {
10086            text.split('\n')
10087                .map(|line| line.to_case(Case::UpperCamel))
10088                .join("\n")
10089        })
10090    }
10091
10092    pub fn convert_to_lower_camel_case(
10093        &mut self,
10094        _: &ConvertToLowerCamelCase,
10095        window: &mut Window,
10096        cx: &mut Context<Self>,
10097    ) {
10098        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10099    }
10100
10101    pub fn convert_to_opposite_case(
10102        &mut self,
10103        _: &ConvertToOppositeCase,
10104        window: &mut Window,
10105        cx: &mut Context<Self>,
10106    ) {
10107        self.manipulate_text(window, cx, |text| {
10108            text.chars()
10109                .fold(String::with_capacity(text.len()), |mut t, c| {
10110                    if c.is_uppercase() {
10111                        t.extend(c.to_lowercase());
10112                    } else {
10113                        t.extend(c.to_uppercase());
10114                    }
10115                    t
10116                })
10117        })
10118    }
10119
10120    pub fn convert_to_rot13(
10121        &mut self,
10122        _: &ConvertToRot13,
10123        window: &mut Window,
10124        cx: &mut Context<Self>,
10125    ) {
10126        self.manipulate_text(window, cx, |text| {
10127            text.chars()
10128                .map(|c| match c {
10129                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10130                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10131                    _ => c,
10132                })
10133                .collect()
10134        })
10135    }
10136
10137    pub fn convert_to_rot47(
10138        &mut self,
10139        _: &ConvertToRot47,
10140        window: &mut Window,
10141        cx: &mut Context<Self>,
10142    ) {
10143        self.manipulate_text(window, cx, |text| {
10144            text.chars()
10145                .map(|c| {
10146                    let code_point = c as u32;
10147                    if code_point >= 33 && code_point <= 126 {
10148                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10149                    }
10150                    c
10151                })
10152                .collect()
10153        })
10154    }
10155
10156    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10157    where
10158        Fn: FnMut(&str) -> String,
10159    {
10160        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10161        let buffer = self.buffer.read(cx).snapshot(cx);
10162
10163        let mut new_selections = Vec::new();
10164        let mut edits = Vec::new();
10165        let mut selection_adjustment = 0i32;
10166
10167        for selection in self.selections.all::<usize>(cx) {
10168            let selection_is_empty = selection.is_empty();
10169
10170            let (start, end) = if selection_is_empty {
10171                let word_range = movement::surrounding_word(
10172                    &display_map,
10173                    selection.start.to_display_point(&display_map),
10174                );
10175                let start = word_range.start.to_offset(&display_map, Bias::Left);
10176                let end = word_range.end.to_offset(&display_map, Bias::Left);
10177                (start, end)
10178            } else {
10179                (selection.start, selection.end)
10180            };
10181
10182            let text = buffer.text_for_range(start..end).collect::<String>();
10183            let old_length = text.len() as i32;
10184            let text = callback(&text);
10185
10186            new_selections.push(Selection {
10187                start: (start as i32 - selection_adjustment) as usize,
10188                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10189                goal: SelectionGoal::None,
10190                ..selection
10191            });
10192
10193            selection_adjustment += old_length - text.len() as i32;
10194
10195            edits.push((start..end, text));
10196        }
10197
10198        self.transact(window, cx, |this, window, cx| {
10199            this.buffer.update(cx, |buffer, cx| {
10200                buffer.edit(edits, None, cx);
10201            });
10202
10203            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10204                s.select(new_selections);
10205            });
10206
10207            this.request_autoscroll(Autoscroll::fit(), cx);
10208        });
10209    }
10210
10211    pub fn duplicate(
10212        &mut self,
10213        upwards: bool,
10214        whole_lines: bool,
10215        window: &mut Window,
10216        cx: &mut Context<Self>,
10217    ) {
10218        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10219
10220        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10221        let buffer = &display_map.buffer_snapshot;
10222        let selections = self.selections.all::<Point>(cx);
10223
10224        let mut edits = Vec::new();
10225        let mut selections_iter = selections.iter().peekable();
10226        while let Some(selection) = selections_iter.next() {
10227            let mut rows = selection.spanned_rows(false, &display_map);
10228            // duplicate line-wise
10229            if whole_lines || selection.start == selection.end {
10230                // Avoid duplicating the same lines twice.
10231                while let Some(next_selection) = selections_iter.peek() {
10232                    let next_rows = next_selection.spanned_rows(false, &display_map);
10233                    if next_rows.start < rows.end {
10234                        rows.end = next_rows.end;
10235                        selections_iter.next().unwrap();
10236                    } else {
10237                        break;
10238                    }
10239                }
10240
10241                // Copy the text from the selected row region and splice it either at the start
10242                // or end of the region.
10243                let start = Point::new(rows.start.0, 0);
10244                let end = Point::new(
10245                    rows.end.previous_row().0,
10246                    buffer.line_len(rows.end.previous_row()),
10247                );
10248                let text = buffer
10249                    .text_for_range(start..end)
10250                    .chain(Some("\n"))
10251                    .collect::<String>();
10252                let insert_location = if upwards {
10253                    Point::new(rows.end.0, 0)
10254                } else {
10255                    start
10256                };
10257                edits.push((insert_location..insert_location, text));
10258            } else {
10259                // duplicate character-wise
10260                let start = selection.start;
10261                let end = selection.end;
10262                let text = buffer.text_for_range(start..end).collect::<String>();
10263                edits.push((selection.end..selection.end, text));
10264            }
10265        }
10266
10267        self.transact(window, cx, |this, _, cx| {
10268            this.buffer.update(cx, |buffer, cx| {
10269                buffer.edit(edits, None, cx);
10270            });
10271
10272            this.request_autoscroll(Autoscroll::fit(), cx);
10273        });
10274    }
10275
10276    pub fn duplicate_line_up(
10277        &mut self,
10278        _: &DuplicateLineUp,
10279        window: &mut Window,
10280        cx: &mut Context<Self>,
10281    ) {
10282        self.duplicate(true, true, window, cx);
10283    }
10284
10285    pub fn duplicate_line_down(
10286        &mut self,
10287        _: &DuplicateLineDown,
10288        window: &mut Window,
10289        cx: &mut Context<Self>,
10290    ) {
10291        self.duplicate(false, true, window, cx);
10292    }
10293
10294    pub fn duplicate_selection(
10295        &mut self,
10296        _: &DuplicateSelection,
10297        window: &mut Window,
10298        cx: &mut Context<Self>,
10299    ) {
10300        self.duplicate(false, false, window, cx);
10301    }
10302
10303    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10304        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10305
10306        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10307        let buffer = self.buffer.read(cx).snapshot(cx);
10308
10309        let mut edits = Vec::new();
10310        let mut unfold_ranges = Vec::new();
10311        let mut refold_creases = Vec::new();
10312
10313        let selections = self.selections.all::<Point>(cx);
10314        let mut selections = selections.iter().peekable();
10315        let mut contiguous_row_selections = Vec::new();
10316        let mut new_selections = Vec::new();
10317
10318        while let Some(selection) = selections.next() {
10319            // Find all the selections that span a contiguous row range
10320            let (start_row, end_row) = consume_contiguous_rows(
10321                &mut contiguous_row_selections,
10322                selection,
10323                &display_map,
10324                &mut selections,
10325            );
10326
10327            // Move the text spanned by the row range to be before the line preceding the row range
10328            if start_row.0 > 0 {
10329                let range_to_move = Point::new(
10330                    start_row.previous_row().0,
10331                    buffer.line_len(start_row.previous_row()),
10332                )
10333                    ..Point::new(
10334                        end_row.previous_row().0,
10335                        buffer.line_len(end_row.previous_row()),
10336                    );
10337                let insertion_point = display_map
10338                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10339                    .0;
10340
10341                // Don't move lines across excerpts
10342                if buffer
10343                    .excerpt_containing(insertion_point..range_to_move.end)
10344                    .is_some()
10345                {
10346                    let text = buffer
10347                        .text_for_range(range_to_move.clone())
10348                        .flat_map(|s| s.chars())
10349                        .skip(1)
10350                        .chain(['\n'])
10351                        .collect::<String>();
10352
10353                    edits.push((
10354                        buffer.anchor_after(range_to_move.start)
10355                            ..buffer.anchor_before(range_to_move.end),
10356                        String::new(),
10357                    ));
10358                    let insertion_anchor = buffer.anchor_after(insertion_point);
10359                    edits.push((insertion_anchor..insertion_anchor, text));
10360
10361                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10362
10363                    // Move selections up
10364                    new_selections.extend(contiguous_row_selections.drain(..).map(
10365                        |mut selection| {
10366                            selection.start.row -= row_delta;
10367                            selection.end.row -= row_delta;
10368                            selection
10369                        },
10370                    ));
10371
10372                    // Move folds up
10373                    unfold_ranges.push(range_to_move.clone());
10374                    for fold in display_map.folds_in_range(
10375                        buffer.anchor_before(range_to_move.start)
10376                            ..buffer.anchor_after(range_to_move.end),
10377                    ) {
10378                        let mut start = fold.range.start.to_point(&buffer);
10379                        let mut end = fold.range.end.to_point(&buffer);
10380                        start.row -= row_delta;
10381                        end.row -= row_delta;
10382                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10383                    }
10384                }
10385            }
10386
10387            // If we didn't move line(s), preserve the existing selections
10388            new_selections.append(&mut contiguous_row_selections);
10389        }
10390
10391        self.transact(window, cx, |this, window, cx| {
10392            this.unfold_ranges(&unfold_ranges, true, true, cx);
10393            this.buffer.update(cx, |buffer, cx| {
10394                for (range, text) in edits {
10395                    buffer.edit([(range, text)], None, cx);
10396                }
10397            });
10398            this.fold_creases(refold_creases, true, window, cx);
10399            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10400                s.select(new_selections);
10401            })
10402        });
10403    }
10404
10405    pub fn move_line_down(
10406        &mut self,
10407        _: &MoveLineDown,
10408        window: &mut Window,
10409        cx: &mut Context<Self>,
10410    ) {
10411        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10412
10413        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10414        let buffer = self.buffer.read(cx).snapshot(cx);
10415
10416        let mut edits = Vec::new();
10417        let mut unfold_ranges = Vec::new();
10418        let mut refold_creases = Vec::new();
10419
10420        let selections = self.selections.all::<Point>(cx);
10421        let mut selections = selections.iter().peekable();
10422        let mut contiguous_row_selections = Vec::new();
10423        let mut new_selections = Vec::new();
10424
10425        while let Some(selection) = selections.next() {
10426            // Find all the selections that span a contiguous row range
10427            let (start_row, end_row) = consume_contiguous_rows(
10428                &mut contiguous_row_selections,
10429                selection,
10430                &display_map,
10431                &mut selections,
10432            );
10433
10434            // Move the text spanned by the row range to be after the last line of the row range
10435            if end_row.0 <= buffer.max_point().row {
10436                let range_to_move =
10437                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10438                let insertion_point = display_map
10439                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10440                    .0;
10441
10442                // Don't move lines across excerpt boundaries
10443                if buffer
10444                    .excerpt_containing(range_to_move.start..insertion_point)
10445                    .is_some()
10446                {
10447                    let mut text = String::from("\n");
10448                    text.extend(buffer.text_for_range(range_to_move.clone()));
10449                    text.pop(); // Drop trailing newline
10450                    edits.push((
10451                        buffer.anchor_after(range_to_move.start)
10452                            ..buffer.anchor_before(range_to_move.end),
10453                        String::new(),
10454                    ));
10455                    let insertion_anchor = buffer.anchor_after(insertion_point);
10456                    edits.push((insertion_anchor..insertion_anchor, text));
10457
10458                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10459
10460                    // Move selections down
10461                    new_selections.extend(contiguous_row_selections.drain(..).map(
10462                        |mut selection| {
10463                            selection.start.row += row_delta;
10464                            selection.end.row += row_delta;
10465                            selection
10466                        },
10467                    ));
10468
10469                    // Move folds down
10470                    unfold_ranges.push(range_to_move.clone());
10471                    for fold in display_map.folds_in_range(
10472                        buffer.anchor_before(range_to_move.start)
10473                            ..buffer.anchor_after(range_to_move.end),
10474                    ) {
10475                        let mut start = fold.range.start.to_point(&buffer);
10476                        let mut end = fold.range.end.to_point(&buffer);
10477                        start.row += row_delta;
10478                        end.row += row_delta;
10479                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10480                    }
10481                }
10482            }
10483
10484            // If we didn't move line(s), preserve the existing selections
10485            new_selections.append(&mut contiguous_row_selections);
10486        }
10487
10488        self.transact(window, cx, |this, window, cx| {
10489            this.unfold_ranges(&unfold_ranges, true, true, cx);
10490            this.buffer.update(cx, |buffer, cx| {
10491                for (range, text) in edits {
10492                    buffer.edit([(range, text)], None, cx);
10493                }
10494            });
10495            this.fold_creases(refold_creases, true, window, cx);
10496            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10497                s.select(new_selections)
10498            });
10499        });
10500    }
10501
10502    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10503        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10504        let text_layout_details = &self.text_layout_details(window);
10505        self.transact(window, cx, |this, window, cx| {
10506            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10507                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10508                s.move_with(|display_map, selection| {
10509                    if !selection.is_empty() {
10510                        return;
10511                    }
10512
10513                    let mut head = selection.head();
10514                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10515                    if head.column() == display_map.line_len(head.row()) {
10516                        transpose_offset = display_map
10517                            .buffer_snapshot
10518                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10519                    }
10520
10521                    if transpose_offset == 0 {
10522                        return;
10523                    }
10524
10525                    *head.column_mut() += 1;
10526                    head = display_map.clip_point(head, Bias::Right);
10527                    let goal = SelectionGoal::HorizontalPosition(
10528                        display_map
10529                            .x_for_display_point(head, text_layout_details)
10530                            .into(),
10531                    );
10532                    selection.collapse_to(head, goal);
10533
10534                    let transpose_start = display_map
10535                        .buffer_snapshot
10536                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10537                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10538                        let transpose_end = display_map
10539                            .buffer_snapshot
10540                            .clip_offset(transpose_offset + 1, Bias::Right);
10541                        if let Some(ch) =
10542                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10543                        {
10544                            edits.push((transpose_start..transpose_offset, String::new()));
10545                            edits.push((transpose_end..transpose_end, ch.to_string()));
10546                        }
10547                    }
10548                });
10549                edits
10550            });
10551            this.buffer
10552                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10553            let selections = this.selections.all::<usize>(cx);
10554            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10555                s.select(selections);
10556            });
10557        });
10558    }
10559
10560    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10561        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10562        self.rewrap_impl(RewrapOptions::default(), cx)
10563    }
10564
10565    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10566        let buffer = self.buffer.read(cx).snapshot(cx);
10567        let selections = self.selections.all::<Point>(cx);
10568        let mut selections = selections.iter().peekable();
10569
10570        let mut edits = Vec::new();
10571        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10572
10573        while let Some(selection) = selections.next() {
10574            let mut start_row = selection.start.row;
10575            let mut end_row = selection.end.row;
10576
10577            // Skip selections that overlap with a range that has already been rewrapped.
10578            let selection_range = start_row..end_row;
10579            if rewrapped_row_ranges
10580                .iter()
10581                .any(|range| range.overlaps(&selection_range))
10582            {
10583                continue;
10584            }
10585
10586            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10587
10588            // Since not all lines in the selection may be at the same indent
10589            // level, choose the indent size that is the most common between all
10590            // of the lines.
10591            //
10592            // If there is a tie, we use the deepest indent.
10593            let (indent_size, indent_end) = {
10594                let mut indent_size_occurrences = HashMap::default();
10595                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10596
10597                for row in start_row..=end_row {
10598                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10599                    rows_by_indent_size.entry(indent).or_default().push(row);
10600                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10601                }
10602
10603                let indent_size = indent_size_occurrences
10604                    .into_iter()
10605                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10606                    .map(|(indent, _)| indent)
10607                    .unwrap_or_default();
10608                let row = rows_by_indent_size[&indent_size][0];
10609                let indent_end = Point::new(row, indent_size.len);
10610
10611                (indent_size, indent_end)
10612            };
10613
10614            let mut line_prefix = indent_size.chars().collect::<String>();
10615
10616            let mut inside_comment = false;
10617            if let Some(comment_prefix) =
10618                buffer
10619                    .language_scope_at(selection.head())
10620                    .and_then(|language| {
10621                        language
10622                            .line_comment_prefixes()
10623                            .iter()
10624                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10625                            .cloned()
10626                    })
10627            {
10628                line_prefix.push_str(&comment_prefix);
10629                inside_comment = true;
10630            }
10631
10632            let language_settings = buffer.language_settings_at(selection.head(), cx);
10633            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10634                RewrapBehavior::InComments => inside_comment,
10635                RewrapBehavior::InSelections => !selection.is_empty(),
10636                RewrapBehavior::Anywhere => true,
10637            };
10638
10639            let should_rewrap = options.override_language_settings
10640                || allow_rewrap_based_on_language
10641                || self.hard_wrap.is_some();
10642            if !should_rewrap {
10643                continue;
10644            }
10645
10646            if selection.is_empty() {
10647                'expand_upwards: while start_row > 0 {
10648                    let prev_row = start_row - 1;
10649                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10650                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10651                    {
10652                        start_row = prev_row;
10653                    } else {
10654                        break 'expand_upwards;
10655                    }
10656                }
10657
10658                'expand_downwards: while end_row < buffer.max_point().row {
10659                    let next_row = end_row + 1;
10660                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10661                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10662                    {
10663                        end_row = next_row;
10664                    } else {
10665                        break 'expand_downwards;
10666                    }
10667                }
10668            }
10669
10670            let start = Point::new(start_row, 0);
10671            let start_offset = start.to_offset(&buffer);
10672            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10673            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10674            let Some(lines_without_prefixes) = selection_text
10675                .lines()
10676                .map(|line| {
10677                    line.strip_prefix(&line_prefix)
10678                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10679                        .with_context(|| {
10680                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10681                        })
10682                })
10683                .collect::<Result<Vec<_>, _>>()
10684                .log_err()
10685            else {
10686                continue;
10687            };
10688
10689            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10690                buffer
10691                    .language_settings_at(Point::new(start_row, 0), cx)
10692                    .preferred_line_length as usize
10693            });
10694            let wrapped_text = wrap_with_prefix(
10695                line_prefix,
10696                lines_without_prefixes.join("\n"),
10697                wrap_column,
10698                tab_size,
10699                options.preserve_existing_whitespace,
10700            );
10701
10702            // TODO: should always use char-based diff while still supporting cursor behavior that
10703            // matches vim.
10704            let mut diff_options = DiffOptions::default();
10705            if options.override_language_settings {
10706                diff_options.max_word_diff_len = 0;
10707                diff_options.max_word_diff_line_count = 0;
10708            } else {
10709                diff_options.max_word_diff_len = usize::MAX;
10710                diff_options.max_word_diff_line_count = usize::MAX;
10711            }
10712
10713            for (old_range, new_text) in
10714                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10715            {
10716                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10717                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10718                edits.push((edit_start..edit_end, new_text));
10719            }
10720
10721            rewrapped_row_ranges.push(start_row..=end_row);
10722        }
10723
10724        self.buffer
10725            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10726    }
10727
10728    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10729        let mut text = String::new();
10730        let buffer = self.buffer.read(cx).snapshot(cx);
10731        let mut selections = self.selections.all::<Point>(cx);
10732        let mut clipboard_selections = Vec::with_capacity(selections.len());
10733        {
10734            let max_point = buffer.max_point();
10735            let mut is_first = true;
10736            for selection in &mut selections {
10737                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10738                if is_entire_line {
10739                    selection.start = Point::new(selection.start.row, 0);
10740                    if !selection.is_empty() && selection.end.column == 0 {
10741                        selection.end = cmp::min(max_point, selection.end);
10742                    } else {
10743                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10744                    }
10745                    selection.goal = SelectionGoal::None;
10746                }
10747                if is_first {
10748                    is_first = false;
10749                } else {
10750                    text += "\n";
10751                }
10752                let mut len = 0;
10753                for chunk in buffer.text_for_range(selection.start..selection.end) {
10754                    text.push_str(chunk);
10755                    len += chunk.len();
10756                }
10757                clipboard_selections.push(ClipboardSelection {
10758                    len,
10759                    is_entire_line,
10760                    first_line_indent: buffer
10761                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10762                        .len,
10763                });
10764            }
10765        }
10766
10767        self.transact(window, cx, |this, window, cx| {
10768            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10769                s.select(selections);
10770            });
10771            this.insert("", window, cx);
10772        });
10773        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10774    }
10775
10776    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10777        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10778        let item = self.cut_common(window, cx);
10779        cx.write_to_clipboard(item);
10780    }
10781
10782    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10783        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10784        self.change_selections(None, window, cx, |s| {
10785            s.move_with(|snapshot, sel| {
10786                if sel.is_empty() {
10787                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10788                }
10789            });
10790        });
10791        let item = self.cut_common(window, cx);
10792        cx.set_global(KillRing(item))
10793    }
10794
10795    pub fn kill_ring_yank(
10796        &mut self,
10797        _: &KillRingYank,
10798        window: &mut Window,
10799        cx: &mut Context<Self>,
10800    ) {
10801        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10802        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10803            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10804                (kill_ring.text().to_string(), kill_ring.metadata_json())
10805            } else {
10806                return;
10807            }
10808        } else {
10809            return;
10810        };
10811        self.do_paste(&text, metadata, false, window, cx);
10812    }
10813
10814    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10815        self.do_copy(true, cx);
10816    }
10817
10818    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10819        self.do_copy(false, cx);
10820    }
10821
10822    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10823        let selections = self.selections.all::<Point>(cx);
10824        let buffer = self.buffer.read(cx).read(cx);
10825        let mut text = String::new();
10826
10827        let mut clipboard_selections = Vec::with_capacity(selections.len());
10828        {
10829            let max_point = buffer.max_point();
10830            let mut is_first = true;
10831            for selection in &selections {
10832                let mut start = selection.start;
10833                let mut end = selection.end;
10834                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10835                if is_entire_line {
10836                    start = Point::new(start.row, 0);
10837                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10838                }
10839
10840                let mut trimmed_selections = Vec::new();
10841                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10842                    let row = MultiBufferRow(start.row);
10843                    let first_indent = buffer.indent_size_for_line(row);
10844                    if first_indent.len == 0 || start.column > first_indent.len {
10845                        trimmed_selections.push(start..end);
10846                    } else {
10847                        trimmed_selections.push(
10848                            Point::new(row.0, first_indent.len)
10849                                ..Point::new(row.0, buffer.line_len(row)),
10850                        );
10851                        for row in start.row + 1..=end.row {
10852                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10853                            if row == end.row {
10854                                line_len = end.column;
10855                            }
10856                            if line_len == 0 {
10857                                trimmed_selections
10858                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10859                                continue;
10860                            }
10861                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10862                            if row_indent_size.len >= first_indent.len {
10863                                trimmed_selections.push(
10864                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10865                                );
10866                            } else {
10867                                trimmed_selections.clear();
10868                                trimmed_selections.push(start..end);
10869                                break;
10870                            }
10871                        }
10872                    }
10873                } else {
10874                    trimmed_selections.push(start..end);
10875                }
10876
10877                for trimmed_range in trimmed_selections {
10878                    if is_first {
10879                        is_first = false;
10880                    } else {
10881                        text += "\n";
10882                    }
10883                    let mut len = 0;
10884                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10885                        text.push_str(chunk);
10886                        len += chunk.len();
10887                    }
10888                    clipboard_selections.push(ClipboardSelection {
10889                        len,
10890                        is_entire_line,
10891                        first_line_indent: buffer
10892                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10893                            .len,
10894                    });
10895                }
10896            }
10897        }
10898
10899        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10900            text,
10901            clipboard_selections,
10902        ));
10903    }
10904
10905    pub fn do_paste(
10906        &mut self,
10907        text: &String,
10908        clipboard_selections: Option<Vec<ClipboardSelection>>,
10909        handle_entire_lines: bool,
10910        window: &mut Window,
10911        cx: &mut Context<Self>,
10912    ) {
10913        if self.read_only(cx) {
10914            return;
10915        }
10916
10917        let clipboard_text = Cow::Borrowed(text);
10918
10919        self.transact(window, cx, |this, window, cx| {
10920            if let Some(mut clipboard_selections) = clipboard_selections {
10921                let old_selections = this.selections.all::<usize>(cx);
10922                let all_selections_were_entire_line =
10923                    clipboard_selections.iter().all(|s| s.is_entire_line);
10924                let first_selection_indent_column =
10925                    clipboard_selections.first().map(|s| s.first_line_indent);
10926                if clipboard_selections.len() != old_selections.len() {
10927                    clipboard_selections.drain(..);
10928                }
10929                let cursor_offset = this.selections.last::<usize>(cx).head();
10930                let mut auto_indent_on_paste = true;
10931
10932                this.buffer.update(cx, |buffer, cx| {
10933                    let snapshot = buffer.read(cx);
10934                    auto_indent_on_paste = snapshot
10935                        .language_settings_at(cursor_offset, cx)
10936                        .auto_indent_on_paste;
10937
10938                    let mut start_offset = 0;
10939                    let mut edits = Vec::new();
10940                    let mut original_indent_columns = Vec::new();
10941                    for (ix, selection) in old_selections.iter().enumerate() {
10942                        let to_insert;
10943                        let entire_line;
10944                        let original_indent_column;
10945                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10946                            let end_offset = start_offset + clipboard_selection.len;
10947                            to_insert = &clipboard_text[start_offset..end_offset];
10948                            entire_line = clipboard_selection.is_entire_line;
10949                            start_offset = end_offset + 1;
10950                            original_indent_column = Some(clipboard_selection.first_line_indent);
10951                        } else {
10952                            to_insert = clipboard_text.as_str();
10953                            entire_line = all_selections_were_entire_line;
10954                            original_indent_column = first_selection_indent_column
10955                        }
10956
10957                        // If the corresponding selection was empty when this slice of the
10958                        // clipboard text was written, then the entire line containing the
10959                        // selection was copied. If this selection is also currently empty,
10960                        // then paste the line before the current line of the buffer.
10961                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10962                            let column = selection.start.to_point(&snapshot).column as usize;
10963                            let line_start = selection.start - column;
10964                            line_start..line_start
10965                        } else {
10966                            selection.range()
10967                        };
10968
10969                        edits.push((range, to_insert));
10970                        original_indent_columns.push(original_indent_column);
10971                    }
10972                    drop(snapshot);
10973
10974                    buffer.edit(
10975                        edits,
10976                        if auto_indent_on_paste {
10977                            Some(AutoindentMode::Block {
10978                                original_indent_columns,
10979                            })
10980                        } else {
10981                            None
10982                        },
10983                        cx,
10984                    );
10985                });
10986
10987                let selections = this.selections.all::<usize>(cx);
10988                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10989                    s.select(selections)
10990                });
10991            } else {
10992                this.insert(&clipboard_text, window, cx);
10993            }
10994        });
10995    }
10996
10997    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10998        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10999        if let Some(item) = cx.read_from_clipboard() {
11000            let entries = item.entries();
11001
11002            match entries.first() {
11003                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11004                // of all the pasted entries.
11005                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11006                    .do_paste(
11007                        clipboard_string.text(),
11008                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11009                        true,
11010                        window,
11011                        cx,
11012                    ),
11013                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11014            }
11015        }
11016    }
11017
11018    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11019        if self.read_only(cx) {
11020            return;
11021        }
11022
11023        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11024
11025        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11026            if let Some((selections, _)) =
11027                self.selection_history.transaction(transaction_id).cloned()
11028            {
11029                self.change_selections(None, window, cx, |s| {
11030                    s.select_anchors(selections.to_vec());
11031                });
11032            } else {
11033                log::error!(
11034                    "No entry in selection_history found for undo. \
11035                     This may correspond to a bug where undo does not update the selection. \
11036                     If this is occurring, please add details to \
11037                     https://github.com/zed-industries/zed/issues/22692"
11038                );
11039            }
11040            self.request_autoscroll(Autoscroll::fit(), cx);
11041            self.unmark_text(window, cx);
11042            self.refresh_inline_completion(true, false, window, cx);
11043            cx.emit(EditorEvent::Edited { transaction_id });
11044            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11045        }
11046    }
11047
11048    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11049        if self.read_only(cx) {
11050            return;
11051        }
11052
11053        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11054
11055        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11056            if let Some((_, Some(selections))) =
11057                self.selection_history.transaction(transaction_id).cloned()
11058            {
11059                self.change_selections(None, window, cx, |s| {
11060                    s.select_anchors(selections.to_vec());
11061                });
11062            } else {
11063                log::error!(
11064                    "No entry in selection_history found for redo. \
11065                     This may correspond to a bug where undo does not update the selection. \
11066                     If this is occurring, please add details to \
11067                     https://github.com/zed-industries/zed/issues/22692"
11068                );
11069            }
11070            self.request_autoscroll(Autoscroll::fit(), cx);
11071            self.unmark_text(window, cx);
11072            self.refresh_inline_completion(true, false, window, cx);
11073            cx.emit(EditorEvent::Edited { transaction_id });
11074        }
11075    }
11076
11077    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11078        self.buffer
11079            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11080    }
11081
11082    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11083        self.buffer
11084            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11085    }
11086
11087    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11088        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11089        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11090            s.move_with(|map, selection| {
11091                let cursor = if selection.is_empty() {
11092                    movement::left(map, selection.start)
11093                } else {
11094                    selection.start
11095                };
11096                selection.collapse_to(cursor, SelectionGoal::None);
11097            });
11098        })
11099    }
11100
11101    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11102        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11103        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11104            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11105        })
11106    }
11107
11108    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11109        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11110        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11111            s.move_with(|map, selection| {
11112                let cursor = if selection.is_empty() {
11113                    movement::right(map, selection.end)
11114                } else {
11115                    selection.end
11116                };
11117                selection.collapse_to(cursor, SelectionGoal::None)
11118            });
11119        })
11120    }
11121
11122    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11123        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11124        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11125            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11126        })
11127    }
11128
11129    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11130        if self.take_rename(true, window, cx).is_some() {
11131            return;
11132        }
11133
11134        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11135            cx.propagate();
11136            return;
11137        }
11138
11139        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11140
11141        let text_layout_details = &self.text_layout_details(window);
11142        let selection_count = self.selections.count();
11143        let first_selection = self.selections.first_anchor();
11144
11145        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11146            s.move_with(|map, selection| {
11147                if !selection.is_empty() {
11148                    selection.goal = SelectionGoal::None;
11149                }
11150                let (cursor, goal) = movement::up(
11151                    map,
11152                    selection.start,
11153                    selection.goal,
11154                    false,
11155                    text_layout_details,
11156                );
11157                selection.collapse_to(cursor, goal);
11158            });
11159        });
11160
11161        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11162        {
11163            cx.propagate();
11164        }
11165    }
11166
11167    pub fn move_up_by_lines(
11168        &mut self,
11169        action: &MoveUpByLines,
11170        window: &mut Window,
11171        cx: &mut Context<Self>,
11172    ) {
11173        if self.take_rename(true, window, cx).is_some() {
11174            return;
11175        }
11176
11177        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11178            cx.propagate();
11179            return;
11180        }
11181
11182        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11183
11184        let text_layout_details = &self.text_layout_details(window);
11185
11186        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11187            s.move_with(|map, selection| {
11188                if !selection.is_empty() {
11189                    selection.goal = SelectionGoal::None;
11190                }
11191                let (cursor, goal) = movement::up_by_rows(
11192                    map,
11193                    selection.start,
11194                    action.lines,
11195                    selection.goal,
11196                    false,
11197                    text_layout_details,
11198                );
11199                selection.collapse_to(cursor, goal);
11200            });
11201        })
11202    }
11203
11204    pub fn move_down_by_lines(
11205        &mut self,
11206        action: &MoveDownByLines,
11207        window: &mut Window,
11208        cx: &mut Context<Self>,
11209    ) {
11210        if self.take_rename(true, window, cx).is_some() {
11211            return;
11212        }
11213
11214        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11215            cx.propagate();
11216            return;
11217        }
11218
11219        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11220
11221        let text_layout_details = &self.text_layout_details(window);
11222
11223        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11224            s.move_with(|map, selection| {
11225                if !selection.is_empty() {
11226                    selection.goal = SelectionGoal::None;
11227                }
11228                let (cursor, goal) = movement::down_by_rows(
11229                    map,
11230                    selection.start,
11231                    action.lines,
11232                    selection.goal,
11233                    false,
11234                    text_layout_details,
11235                );
11236                selection.collapse_to(cursor, goal);
11237            });
11238        })
11239    }
11240
11241    pub fn select_down_by_lines(
11242        &mut self,
11243        action: &SelectDownByLines,
11244        window: &mut Window,
11245        cx: &mut Context<Self>,
11246    ) {
11247        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11248        let text_layout_details = &self.text_layout_details(window);
11249        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11250            s.move_heads_with(|map, head, goal| {
11251                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11252            })
11253        })
11254    }
11255
11256    pub fn select_up_by_lines(
11257        &mut self,
11258        action: &SelectUpByLines,
11259        window: &mut Window,
11260        cx: &mut Context<Self>,
11261    ) {
11262        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11263        let text_layout_details = &self.text_layout_details(window);
11264        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11265            s.move_heads_with(|map, head, goal| {
11266                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11267            })
11268        })
11269    }
11270
11271    pub fn select_page_up(
11272        &mut self,
11273        _: &SelectPageUp,
11274        window: &mut Window,
11275        cx: &mut Context<Self>,
11276    ) {
11277        let Some(row_count) = self.visible_row_count() else {
11278            return;
11279        };
11280
11281        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11282
11283        let text_layout_details = &self.text_layout_details(window);
11284
11285        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11286            s.move_heads_with(|map, head, goal| {
11287                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11288            })
11289        })
11290    }
11291
11292    pub fn move_page_up(
11293        &mut self,
11294        action: &MovePageUp,
11295        window: &mut Window,
11296        cx: &mut Context<Self>,
11297    ) {
11298        if self.take_rename(true, window, cx).is_some() {
11299            return;
11300        }
11301
11302        if self
11303            .context_menu
11304            .borrow_mut()
11305            .as_mut()
11306            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11307            .unwrap_or(false)
11308        {
11309            return;
11310        }
11311
11312        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11313            cx.propagate();
11314            return;
11315        }
11316
11317        let Some(row_count) = self.visible_row_count() else {
11318            return;
11319        };
11320
11321        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11322
11323        let autoscroll = if action.center_cursor {
11324            Autoscroll::center()
11325        } else {
11326            Autoscroll::fit()
11327        };
11328
11329        let text_layout_details = &self.text_layout_details(window);
11330
11331        self.change_selections(Some(autoscroll), window, cx, |s| {
11332            s.move_with(|map, selection| {
11333                if !selection.is_empty() {
11334                    selection.goal = SelectionGoal::None;
11335                }
11336                let (cursor, goal) = movement::up_by_rows(
11337                    map,
11338                    selection.end,
11339                    row_count,
11340                    selection.goal,
11341                    false,
11342                    text_layout_details,
11343                );
11344                selection.collapse_to(cursor, goal);
11345            });
11346        });
11347    }
11348
11349    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11350        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11351        let text_layout_details = &self.text_layout_details(window);
11352        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11353            s.move_heads_with(|map, head, goal| {
11354                movement::up(map, head, goal, false, text_layout_details)
11355            })
11356        })
11357    }
11358
11359    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11360        self.take_rename(true, window, cx);
11361
11362        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11363            cx.propagate();
11364            return;
11365        }
11366
11367        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11368
11369        let text_layout_details = &self.text_layout_details(window);
11370        let selection_count = self.selections.count();
11371        let first_selection = self.selections.first_anchor();
11372
11373        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11374            s.move_with(|map, selection| {
11375                if !selection.is_empty() {
11376                    selection.goal = SelectionGoal::None;
11377                }
11378                let (cursor, goal) = movement::down(
11379                    map,
11380                    selection.end,
11381                    selection.goal,
11382                    false,
11383                    text_layout_details,
11384                );
11385                selection.collapse_to(cursor, goal);
11386            });
11387        });
11388
11389        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11390        {
11391            cx.propagate();
11392        }
11393    }
11394
11395    pub fn select_page_down(
11396        &mut self,
11397        _: &SelectPageDown,
11398        window: &mut Window,
11399        cx: &mut Context<Self>,
11400    ) {
11401        let Some(row_count) = self.visible_row_count() else {
11402            return;
11403        };
11404
11405        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11406
11407        let text_layout_details = &self.text_layout_details(window);
11408
11409        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11410            s.move_heads_with(|map, head, goal| {
11411                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11412            })
11413        })
11414    }
11415
11416    pub fn move_page_down(
11417        &mut self,
11418        action: &MovePageDown,
11419        window: &mut Window,
11420        cx: &mut Context<Self>,
11421    ) {
11422        if self.take_rename(true, window, cx).is_some() {
11423            return;
11424        }
11425
11426        if self
11427            .context_menu
11428            .borrow_mut()
11429            .as_mut()
11430            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11431            .unwrap_or(false)
11432        {
11433            return;
11434        }
11435
11436        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11437            cx.propagate();
11438            return;
11439        }
11440
11441        let Some(row_count) = self.visible_row_count() else {
11442            return;
11443        };
11444
11445        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11446
11447        let autoscroll = if action.center_cursor {
11448            Autoscroll::center()
11449        } else {
11450            Autoscroll::fit()
11451        };
11452
11453        let text_layout_details = &self.text_layout_details(window);
11454        self.change_selections(Some(autoscroll), window, cx, |s| {
11455            s.move_with(|map, selection| {
11456                if !selection.is_empty() {
11457                    selection.goal = SelectionGoal::None;
11458                }
11459                let (cursor, goal) = movement::down_by_rows(
11460                    map,
11461                    selection.end,
11462                    row_count,
11463                    selection.goal,
11464                    false,
11465                    text_layout_details,
11466                );
11467                selection.collapse_to(cursor, goal);
11468            });
11469        });
11470    }
11471
11472    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11473        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11474        let text_layout_details = &self.text_layout_details(window);
11475        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11476            s.move_heads_with(|map, head, goal| {
11477                movement::down(map, head, goal, false, text_layout_details)
11478            })
11479        });
11480    }
11481
11482    pub fn context_menu_first(
11483        &mut self,
11484        _: &ContextMenuFirst,
11485        _window: &mut Window,
11486        cx: &mut Context<Self>,
11487    ) {
11488        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11489            context_menu.select_first(self.completion_provider.as_deref(), cx);
11490        }
11491    }
11492
11493    pub fn context_menu_prev(
11494        &mut self,
11495        _: &ContextMenuPrevious,
11496        _window: &mut Window,
11497        cx: &mut Context<Self>,
11498    ) {
11499        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11500            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11501        }
11502    }
11503
11504    pub fn context_menu_next(
11505        &mut self,
11506        _: &ContextMenuNext,
11507        _window: &mut Window,
11508        cx: &mut Context<Self>,
11509    ) {
11510        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11511            context_menu.select_next(self.completion_provider.as_deref(), cx);
11512        }
11513    }
11514
11515    pub fn context_menu_last(
11516        &mut self,
11517        _: &ContextMenuLast,
11518        _window: &mut Window,
11519        cx: &mut Context<Self>,
11520    ) {
11521        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11522            context_menu.select_last(self.completion_provider.as_deref(), cx);
11523        }
11524    }
11525
11526    pub fn move_to_previous_word_start(
11527        &mut self,
11528        _: &MoveToPreviousWordStart,
11529        window: &mut Window,
11530        cx: &mut Context<Self>,
11531    ) {
11532        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11533        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11534            s.move_cursors_with(|map, head, _| {
11535                (
11536                    movement::previous_word_start(map, head),
11537                    SelectionGoal::None,
11538                )
11539            });
11540        })
11541    }
11542
11543    pub fn move_to_previous_subword_start(
11544        &mut self,
11545        _: &MoveToPreviousSubwordStart,
11546        window: &mut Window,
11547        cx: &mut Context<Self>,
11548    ) {
11549        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11550        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11551            s.move_cursors_with(|map, head, _| {
11552                (
11553                    movement::previous_subword_start(map, head),
11554                    SelectionGoal::None,
11555                )
11556            });
11557        })
11558    }
11559
11560    pub fn select_to_previous_word_start(
11561        &mut self,
11562        _: &SelectToPreviousWordStart,
11563        window: &mut Window,
11564        cx: &mut Context<Self>,
11565    ) {
11566        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11567        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11568            s.move_heads_with(|map, head, _| {
11569                (
11570                    movement::previous_word_start(map, head),
11571                    SelectionGoal::None,
11572                )
11573            });
11574        })
11575    }
11576
11577    pub fn select_to_previous_subword_start(
11578        &mut self,
11579        _: &SelectToPreviousSubwordStart,
11580        window: &mut Window,
11581        cx: &mut Context<Self>,
11582    ) {
11583        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11584        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11585            s.move_heads_with(|map, head, _| {
11586                (
11587                    movement::previous_subword_start(map, head),
11588                    SelectionGoal::None,
11589                )
11590            });
11591        })
11592    }
11593
11594    pub fn delete_to_previous_word_start(
11595        &mut self,
11596        action: &DeleteToPreviousWordStart,
11597        window: &mut Window,
11598        cx: &mut Context<Self>,
11599    ) {
11600        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11601        self.transact(window, cx, |this, window, cx| {
11602            this.select_autoclose_pair(window, cx);
11603            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11604                s.move_with(|map, selection| {
11605                    if selection.is_empty() {
11606                        let cursor = if action.ignore_newlines {
11607                            movement::previous_word_start(map, selection.head())
11608                        } else {
11609                            movement::previous_word_start_or_newline(map, selection.head())
11610                        };
11611                        selection.set_head(cursor, SelectionGoal::None);
11612                    }
11613                });
11614            });
11615            this.insert("", window, cx);
11616        });
11617    }
11618
11619    pub fn delete_to_previous_subword_start(
11620        &mut self,
11621        _: &DeleteToPreviousSubwordStart,
11622        window: &mut Window,
11623        cx: &mut Context<Self>,
11624    ) {
11625        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11626        self.transact(window, cx, |this, window, cx| {
11627            this.select_autoclose_pair(window, cx);
11628            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11629                s.move_with(|map, selection| {
11630                    if selection.is_empty() {
11631                        let cursor = movement::previous_subword_start(map, selection.head());
11632                        selection.set_head(cursor, SelectionGoal::None);
11633                    }
11634                });
11635            });
11636            this.insert("", window, cx);
11637        });
11638    }
11639
11640    pub fn move_to_next_word_end(
11641        &mut self,
11642        _: &MoveToNextWordEnd,
11643        window: &mut Window,
11644        cx: &mut Context<Self>,
11645    ) {
11646        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11647        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11648            s.move_cursors_with(|map, head, _| {
11649                (movement::next_word_end(map, head), SelectionGoal::None)
11650            });
11651        })
11652    }
11653
11654    pub fn move_to_next_subword_end(
11655        &mut self,
11656        _: &MoveToNextSubwordEnd,
11657        window: &mut Window,
11658        cx: &mut Context<Self>,
11659    ) {
11660        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11661        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11662            s.move_cursors_with(|map, head, _| {
11663                (movement::next_subword_end(map, head), SelectionGoal::None)
11664            });
11665        })
11666    }
11667
11668    pub fn select_to_next_word_end(
11669        &mut self,
11670        _: &SelectToNextWordEnd,
11671        window: &mut Window,
11672        cx: &mut Context<Self>,
11673    ) {
11674        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11675        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11676            s.move_heads_with(|map, head, _| {
11677                (movement::next_word_end(map, head), SelectionGoal::None)
11678            });
11679        })
11680    }
11681
11682    pub fn select_to_next_subword_end(
11683        &mut self,
11684        _: &SelectToNextSubwordEnd,
11685        window: &mut Window,
11686        cx: &mut Context<Self>,
11687    ) {
11688        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11689        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11690            s.move_heads_with(|map, head, _| {
11691                (movement::next_subword_end(map, head), SelectionGoal::None)
11692            });
11693        })
11694    }
11695
11696    pub fn delete_to_next_word_end(
11697        &mut self,
11698        action: &DeleteToNextWordEnd,
11699        window: &mut Window,
11700        cx: &mut Context<Self>,
11701    ) {
11702        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11703        self.transact(window, cx, |this, window, cx| {
11704            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11705                s.move_with(|map, selection| {
11706                    if selection.is_empty() {
11707                        let cursor = if action.ignore_newlines {
11708                            movement::next_word_end(map, selection.head())
11709                        } else {
11710                            movement::next_word_end_or_newline(map, selection.head())
11711                        };
11712                        selection.set_head(cursor, SelectionGoal::None);
11713                    }
11714                });
11715            });
11716            this.insert("", window, cx);
11717        });
11718    }
11719
11720    pub fn delete_to_next_subword_end(
11721        &mut self,
11722        _: &DeleteToNextSubwordEnd,
11723        window: &mut Window,
11724        cx: &mut Context<Self>,
11725    ) {
11726        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11727        self.transact(window, cx, |this, window, cx| {
11728            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11729                s.move_with(|map, selection| {
11730                    if selection.is_empty() {
11731                        let cursor = movement::next_subword_end(map, selection.head());
11732                        selection.set_head(cursor, SelectionGoal::None);
11733                    }
11734                });
11735            });
11736            this.insert("", window, cx);
11737        });
11738    }
11739
11740    pub fn move_to_beginning_of_line(
11741        &mut self,
11742        action: &MoveToBeginningOfLine,
11743        window: &mut Window,
11744        cx: &mut Context<Self>,
11745    ) {
11746        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11747        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11748            s.move_cursors_with(|map, head, _| {
11749                (
11750                    movement::indented_line_beginning(
11751                        map,
11752                        head,
11753                        action.stop_at_soft_wraps,
11754                        action.stop_at_indent,
11755                    ),
11756                    SelectionGoal::None,
11757                )
11758            });
11759        })
11760    }
11761
11762    pub fn select_to_beginning_of_line(
11763        &mut self,
11764        action: &SelectToBeginningOfLine,
11765        window: &mut Window,
11766        cx: &mut Context<Self>,
11767    ) {
11768        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11769        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11770            s.move_heads_with(|map, head, _| {
11771                (
11772                    movement::indented_line_beginning(
11773                        map,
11774                        head,
11775                        action.stop_at_soft_wraps,
11776                        action.stop_at_indent,
11777                    ),
11778                    SelectionGoal::None,
11779                )
11780            });
11781        });
11782    }
11783
11784    pub fn delete_to_beginning_of_line(
11785        &mut self,
11786        action: &DeleteToBeginningOfLine,
11787        window: &mut Window,
11788        cx: &mut Context<Self>,
11789    ) {
11790        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11791        self.transact(window, cx, |this, window, cx| {
11792            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11793                s.move_with(|_, selection| {
11794                    selection.reversed = true;
11795                });
11796            });
11797
11798            this.select_to_beginning_of_line(
11799                &SelectToBeginningOfLine {
11800                    stop_at_soft_wraps: false,
11801                    stop_at_indent: action.stop_at_indent,
11802                },
11803                window,
11804                cx,
11805            );
11806            this.backspace(&Backspace, window, cx);
11807        });
11808    }
11809
11810    pub fn move_to_end_of_line(
11811        &mut self,
11812        action: &MoveToEndOfLine,
11813        window: &mut Window,
11814        cx: &mut Context<Self>,
11815    ) {
11816        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11817        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11818            s.move_cursors_with(|map, head, _| {
11819                (
11820                    movement::line_end(map, head, action.stop_at_soft_wraps),
11821                    SelectionGoal::None,
11822                )
11823            });
11824        })
11825    }
11826
11827    pub fn select_to_end_of_line(
11828        &mut self,
11829        action: &SelectToEndOfLine,
11830        window: &mut Window,
11831        cx: &mut Context<Self>,
11832    ) {
11833        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11834        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11835            s.move_heads_with(|map, head, _| {
11836                (
11837                    movement::line_end(map, head, action.stop_at_soft_wraps),
11838                    SelectionGoal::None,
11839                )
11840            });
11841        })
11842    }
11843
11844    pub fn delete_to_end_of_line(
11845        &mut self,
11846        _: &DeleteToEndOfLine,
11847        window: &mut Window,
11848        cx: &mut Context<Self>,
11849    ) {
11850        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11851        self.transact(window, cx, |this, window, cx| {
11852            this.select_to_end_of_line(
11853                &SelectToEndOfLine {
11854                    stop_at_soft_wraps: false,
11855                },
11856                window,
11857                cx,
11858            );
11859            this.delete(&Delete, window, cx);
11860        });
11861    }
11862
11863    pub fn cut_to_end_of_line(
11864        &mut self,
11865        _: &CutToEndOfLine,
11866        window: &mut Window,
11867        cx: &mut Context<Self>,
11868    ) {
11869        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11870        self.transact(window, cx, |this, window, cx| {
11871            this.select_to_end_of_line(
11872                &SelectToEndOfLine {
11873                    stop_at_soft_wraps: false,
11874                },
11875                window,
11876                cx,
11877            );
11878            this.cut(&Cut, window, cx);
11879        });
11880    }
11881
11882    pub fn move_to_start_of_paragraph(
11883        &mut self,
11884        _: &MoveToStartOfParagraph,
11885        window: &mut Window,
11886        cx: &mut Context<Self>,
11887    ) {
11888        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11889            cx.propagate();
11890            return;
11891        }
11892        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11893        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11894            s.move_with(|map, selection| {
11895                selection.collapse_to(
11896                    movement::start_of_paragraph(map, selection.head(), 1),
11897                    SelectionGoal::None,
11898                )
11899            });
11900        })
11901    }
11902
11903    pub fn move_to_end_of_paragraph(
11904        &mut self,
11905        _: &MoveToEndOfParagraph,
11906        window: &mut Window,
11907        cx: &mut Context<Self>,
11908    ) {
11909        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11910            cx.propagate();
11911            return;
11912        }
11913        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11914        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11915            s.move_with(|map, selection| {
11916                selection.collapse_to(
11917                    movement::end_of_paragraph(map, selection.head(), 1),
11918                    SelectionGoal::None,
11919                )
11920            });
11921        })
11922    }
11923
11924    pub fn select_to_start_of_paragraph(
11925        &mut self,
11926        _: &SelectToStartOfParagraph,
11927        window: &mut Window,
11928        cx: &mut Context<Self>,
11929    ) {
11930        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11931            cx.propagate();
11932            return;
11933        }
11934        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11935        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11936            s.move_heads_with(|map, head, _| {
11937                (
11938                    movement::start_of_paragraph(map, head, 1),
11939                    SelectionGoal::None,
11940                )
11941            });
11942        })
11943    }
11944
11945    pub fn select_to_end_of_paragraph(
11946        &mut self,
11947        _: &SelectToEndOfParagraph,
11948        window: &mut Window,
11949        cx: &mut Context<Self>,
11950    ) {
11951        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11952            cx.propagate();
11953            return;
11954        }
11955        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11956        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11957            s.move_heads_with(|map, head, _| {
11958                (
11959                    movement::end_of_paragraph(map, head, 1),
11960                    SelectionGoal::None,
11961                )
11962            });
11963        })
11964    }
11965
11966    pub fn move_to_start_of_excerpt(
11967        &mut self,
11968        _: &MoveToStartOfExcerpt,
11969        window: &mut Window,
11970        cx: &mut Context<Self>,
11971    ) {
11972        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11973            cx.propagate();
11974            return;
11975        }
11976        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11977        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11978            s.move_with(|map, selection| {
11979                selection.collapse_to(
11980                    movement::start_of_excerpt(
11981                        map,
11982                        selection.head(),
11983                        workspace::searchable::Direction::Prev,
11984                    ),
11985                    SelectionGoal::None,
11986                )
11987            });
11988        })
11989    }
11990
11991    pub fn move_to_start_of_next_excerpt(
11992        &mut self,
11993        _: &MoveToStartOfNextExcerpt,
11994        window: &mut Window,
11995        cx: &mut Context<Self>,
11996    ) {
11997        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11998            cx.propagate();
11999            return;
12000        }
12001
12002        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12003            s.move_with(|map, selection| {
12004                selection.collapse_to(
12005                    movement::start_of_excerpt(
12006                        map,
12007                        selection.head(),
12008                        workspace::searchable::Direction::Next,
12009                    ),
12010                    SelectionGoal::None,
12011                )
12012            });
12013        })
12014    }
12015
12016    pub fn move_to_end_of_excerpt(
12017        &mut self,
12018        _: &MoveToEndOfExcerpt,
12019        window: &mut Window,
12020        cx: &mut Context<Self>,
12021    ) {
12022        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12023            cx.propagate();
12024            return;
12025        }
12026        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12027        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12028            s.move_with(|map, selection| {
12029                selection.collapse_to(
12030                    movement::end_of_excerpt(
12031                        map,
12032                        selection.head(),
12033                        workspace::searchable::Direction::Next,
12034                    ),
12035                    SelectionGoal::None,
12036                )
12037            });
12038        })
12039    }
12040
12041    pub fn move_to_end_of_previous_excerpt(
12042        &mut self,
12043        _: &MoveToEndOfPreviousExcerpt,
12044        window: &mut Window,
12045        cx: &mut Context<Self>,
12046    ) {
12047        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12048            cx.propagate();
12049            return;
12050        }
12051        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12052        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12053            s.move_with(|map, selection| {
12054                selection.collapse_to(
12055                    movement::end_of_excerpt(
12056                        map,
12057                        selection.head(),
12058                        workspace::searchable::Direction::Prev,
12059                    ),
12060                    SelectionGoal::None,
12061                )
12062            });
12063        })
12064    }
12065
12066    pub fn select_to_start_of_excerpt(
12067        &mut self,
12068        _: &SelectToStartOfExcerpt,
12069        window: &mut Window,
12070        cx: &mut Context<Self>,
12071    ) {
12072        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12073            cx.propagate();
12074            return;
12075        }
12076        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12077        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12078            s.move_heads_with(|map, head, _| {
12079                (
12080                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12081                    SelectionGoal::None,
12082                )
12083            });
12084        })
12085    }
12086
12087    pub fn select_to_start_of_next_excerpt(
12088        &mut self,
12089        _: &SelectToStartOfNextExcerpt,
12090        window: &mut Window,
12091        cx: &mut Context<Self>,
12092    ) {
12093        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12094            cx.propagate();
12095            return;
12096        }
12097        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12098        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12099            s.move_heads_with(|map, head, _| {
12100                (
12101                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12102                    SelectionGoal::None,
12103                )
12104            });
12105        })
12106    }
12107
12108    pub fn select_to_end_of_excerpt(
12109        &mut self,
12110        _: &SelectToEndOfExcerpt,
12111        window: &mut Window,
12112        cx: &mut Context<Self>,
12113    ) {
12114        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12115            cx.propagate();
12116            return;
12117        }
12118        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12119        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12120            s.move_heads_with(|map, head, _| {
12121                (
12122                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12123                    SelectionGoal::None,
12124                )
12125            });
12126        })
12127    }
12128
12129    pub fn select_to_end_of_previous_excerpt(
12130        &mut self,
12131        _: &SelectToEndOfPreviousExcerpt,
12132        window: &mut Window,
12133        cx: &mut Context<Self>,
12134    ) {
12135        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12136            cx.propagate();
12137            return;
12138        }
12139        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12140        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12141            s.move_heads_with(|map, head, _| {
12142                (
12143                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12144                    SelectionGoal::None,
12145                )
12146            });
12147        })
12148    }
12149
12150    pub fn move_to_beginning(
12151        &mut self,
12152        _: &MoveToBeginning,
12153        window: &mut Window,
12154        cx: &mut Context<Self>,
12155    ) {
12156        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12157            cx.propagate();
12158            return;
12159        }
12160        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12161        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12162            s.select_ranges(vec![0..0]);
12163        });
12164    }
12165
12166    pub fn select_to_beginning(
12167        &mut self,
12168        _: &SelectToBeginning,
12169        window: &mut Window,
12170        cx: &mut Context<Self>,
12171    ) {
12172        let mut selection = self.selections.last::<Point>(cx);
12173        selection.set_head(Point::zero(), SelectionGoal::None);
12174        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12175        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12176            s.select(vec![selection]);
12177        });
12178    }
12179
12180    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12181        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12182            cx.propagate();
12183            return;
12184        }
12185        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12186        let cursor = self.buffer.read(cx).read(cx).len();
12187        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12188            s.select_ranges(vec![cursor..cursor])
12189        });
12190    }
12191
12192    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12193        self.nav_history = nav_history;
12194    }
12195
12196    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12197        self.nav_history.as_ref()
12198    }
12199
12200    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12201        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12202    }
12203
12204    fn push_to_nav_history(
12205        &mut self,
12206        cursor_anchor: Anchor,
12207        new_position: Option<Point>,
12208        is_deactivate: bool,
12209        cx: &mut Context<Self>,
12210    ) {
12211        if let Some(nav_history) = self.nav_history.as_mut() {
12212            let buffer = self.buffer.read(cx).read(cx);
12213            let cursor_position = cursor_anchor.to_point(&buffer);
12214            let scroll_state = self.scroll_manager.anchor();
12215            let scroll_top_row = scroll_state.top_row(&buffer);
12216            drop(buffer);
12217
12218            if let Some(new_position) = new_position {
12219                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12220                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12221                    return;
12222                }
12223            }
12224
12225            nav_history.push(
12226                Some(NavigationData {
12227                    cursor_anchor,
12228                    cursor_position,
12229                    scroll_anchor: scroll_state,
12230                    scroll_top_row,
12231                }),
12232                cx,
12233            );
12234            cx.emit(EditorEvent::PushedToNavHistory {
12235                anchor: cursor_anchor,
12236                is_deactivate,
12237            })
12238        }
12239    }
12240
12241    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12242        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12243        let buffer = self.buffer.read(cx).snapshot(cx);
12244        let mut selection = self.selections.first::<usize>(cx);
12245        selection.set_head(buffer.len(), SelectionGoal::None);
12246        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12247            s.select(vec![selection]);
12248        });
12249    }
12250
12251    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12252        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12253        let end = self.buffer.read(cx).read(cx).len();
12254        self.change_selections(None, window, cx, |s| {
12255            s.select_ranges(vec![0..end]);
12256        });
12257    }
12258
12259    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12260        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12261        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12262        let mut selections = self.selections.all::<Point>(cx);
12263        let max_point = display_map.buffer_snapshot.max_point();
12264        for selection in &mut selections {
12265            let rows = selection.spanned_rows(true, &display_map);
12266            selection.start = Point::new(rows.start.0, 0);
12267            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12268            selection.reversed = false;
12269        }
12270        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12271            s.select(selections);
12272        });
12273    }
12274
12275    pub fn split_selection_into_lines(
12276        &mut self,
12277        _: &SplitSelectionIntoLines,
12278        window: &mut Window,
12279        cx: &mut Context<Self>,
12280    ) {
12281        let selections = self
12282            .selections
12283            .all::<Point>(cx)
12284            .into_iter()
12285            .map(|selection| selection.start..selection.end)
12286            .collect::<Vec<_>>();
12287        self.unfold_ranges(&selections, true, true, cx);
12288
12289        let mut new_selection_ranges = Vec::new();
12290        {
12291            let buffer = self.buffer.read(cx).read(cx);
12292            for selection in selections {
12293                for row in selection.start.row..selection.end.row {
12294                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12295                    new_selection_ranges.push(cursor..cursor);
12296                }
12297
12298                let is_multiline_selection = selection.start.row != selection.end.row;
12299                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12300                // so this action feels more ergonomic when paired with other selection operations
12301                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12302                if !should_skip_last {
12303                    new_selection_ranges.push(selection.end..selection.end);
12304                }
12305            }
12306        }
12307        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12308            s.select_ranges(new_selection_ranges);
12309        });
12310    }
12311
12312    pub fn add_selection_above(
12313        &mut self,
12314        _: &AddSelectionAbove,
12315        window: &mut Window,
12316        cx: &mut Context<Self>,
12317    ) {
12318        self.add_selection(true, window, cx);
12319    }
12320
12321    pub fn add_selection_below(
12322        &mut self,
12323        _: &AddSelectionBelow,
12324        window: &mut Window,
12325        cx: &mut Context<Self>,
12326    ) {
12327        self.add_selection(false, window, cx);
12328    }
12329
12330    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12331        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12332
12333        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12334        let mut selections = self.selections.all::<Point>(cx);
12335        let text_layout_details = self.text_layout_details(window);
12336        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12337            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12338            let range = oldest_selection.display_range(&display_map).sorted();
12339
12340            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12341            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12342            let positions = start_x.min(end_x)..start_x.max(end_x);
12343
12344            selections.clear();
12345            let mut stack = Vec::new();
12346            for row in range.start.row().0..=range.end.row().0 {
12347                if let Some(selection) = self.selections.build_columnar_selection(
12348                    &display_map,
12349                    DisplayRow(row),
12350                    &positions,
12351                    oldest_selection.reversed,
12352                    &text_layout_details,
12353                ) {
12354                    stack.push(selection.id);
12355                    selections.push(selection);
12356                }
12357            }
12358
12359            if above {
12360                stack.reverse();
12361            }
12362
12363            AddSelectionsState { above, stack }
12364        });
12365
12366        let last_added_selection = *state.stack.last().unwrap();
12367        let mut new_selections = Vec::new();
12368        if above == state.above {
12369            let end_row = if above {
12370                DisplayRow(0)
12371            } else {
12372                display_map.max_point().row()
12373            };
12374
12375            'outer: for selection in selections {
12376                if selection.id == last_added_selection {
12377                    let range = selection.display_range(&display_map).sorted();
12378                    debug_assert_eq!(range.start.row(), range.end.row());
12379                    let mut row = range.start.row();
12380                    let positions =
12381                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12382                            px(start)..px(end)
12383                        } else {
12384                            let start_x =
12385                                display_map.x_for_display_point(range.start, &text_layout_details);
12386                            let end_x =
12387                                display_map.x_for_display_point(range.end, &text_layout_details);
12388                            start_x.min(end_x)..start_x.max(end_x)
12389                        };
12390
12391                    while row != end_row {
12392                        if above {
12393                            row.0 -= 1;
12394                        } else {
12395                            row.0 += 1;
12396                        }
12397
12398                        if let Some(new_selection) = self.selections.build_columnar_selection(
12399                            &display_map,
12400                            row,
12401                            &positions,
12402                            selection.reversed,
12403                            &text_layout_details,
12404                        ) {
12405                            state.stack.push(new_selection.id);
12406                            if above {
12407                                new_selections.push(new_selection);
12408                                new_selections.push(selection);
12409                            } else {
12410                                new_selections.push(selection);
12411                                new_selections.push(new_selection);
12412                            }
12413
12414                            continue 'outer;
12415                        }
12416                    }
12417                }
12418
12419                new_selections.push(selection);
12420            }
12421        } else {
12422            new_selections = selections;
12423            new_selections.retain(|s| s.id != last_added_selection);
12424            state.stack.pop();
12425        }
12426
12427        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12428            s.select(new_selections);
12429        });
12430        if state.stack.len() > 1 {
12431            self.add_selections_state = Some(state);
12432        }
12433    }
12434
12435    fn select_match_ranges(
12436        &mut self,
12437        range: Range<usize>,
12438        reversed: bool,
12439        replace_newest: bool,
12440        auto_scroll: Option<Autoscroll>,
12441        window: &mut Window,
12442        cx: &mut Context<Editor>,
12443    ) {
12444        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12445        self.change_selections(auto_scroll, window, cx, |s| {
12446            if replace_newest {
12447                s.delete(s.newest_anchor().id);
12448            }
12449            if reversed {
12450                s.insert_range(range.end..range.start);
12451            } else {
12452                s.insert_range(range);
12453            }
12454        });
12455    }
12456
12457    pub fn select_next_match_internal(
12458        &mut self,
12459        display_map: &DisplaySnapshot,
12460        replace_newest: bool,
12461        autoscroll: Option<Autoscroll>,
12462        window: &mut Window,
12463        cx: &mut Context<Self>,
12464    ) -> Result<()> {
12465        let buffer = &display_map.buffer_snapshot;
12466        let mut selections = self.selections.all::<usize>(cx);
12467        if let Some(mut select_next_state) = self.select_next_state.take() {
12468            let query = &select_next_state.query;
12469            if !select_next_state.done {
12470                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12471                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12472                let mut next_selected_range = None;
12473
12474                let bytes_after_last_selection =
12475                    buffer.bytes_in_range(last_selection.end..buffer.len());
12476                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12477                let query_matches = query
12478                    .stream_find_iter(bytes_after_last_selection)
12479                    .map(|result| (last_selection.end, result))
12480                    .chain(
12481                        query
12482                            .stream_find_iter(bytes_before_first_selection)
12483                            .map(|result| (0, result)),
12484                    );
12485
12486                for (start_offset, query_match) in query_matches {
12487                    let query_match = query_match.unwrap(); // can only fail due to I/O
12488                    let offset_range =
12489                        start_offset + query_match.start()..start_offset + query_match.end();
12490                    let display_range = offset_range.start.to_display_point(display_map)
12491                        ..offset_range.end.to_display_point(display_map);
12492
12493                    if !select_next_state.wordwise
12494                        || (!movement::is_inside_word(display_map, display_range.start)
12495                            && !movement::is_inside_word(display_map, display_range.end))
12496                    {
12497                        // TODO: This is n^2, because we might check all the selections
12498                        if !selections
12499                            .iter()
12500                            .any(|selection| selection.range().overlaps(&offset_range))
12501                        {
12502                            next_selected_range = Some(offset_range);
12503                            break;
12504                        }
12505                    }
12506                }
12507
12508                if let Some(next_selected_range) = next_selected_range {
12509                    self.select_match_ranges(
12510                        next_selected_range,
12511                        last_selection.reversed,
12512                        replace_newest,
12513                        autoscroll,
12514                        window,
12515                        cx,
12516                    );
12517                } else {
12518                    select_next_state.done = true;
12519                }
12520            }
12521
12522            self.select_next_state = Some(select_next_state);
12523        } else {
12524            let mut only_carets = true;
12525            let mut same_text_selected = true;
12526            let mut selected_text = None;
12527
12528            let mut selections_iter = selections.iter().peekable();
12529            while let Some(selection) = selections_iter.next() {
12530                if selection.start != selection.end {
12531                    only_carets = false;
12532                }
12533
12534                if same_text_selected {
12535                    if selected_text.is_none() {
12536                        selected_text =
12537                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12538                    }
12539
12540                    if let Some(next_selection) = selections_iter.peek() {
12541                        if next_selection.range().len() == selection.range().len() {
12542                            let next_selected_text = buffer
12543                                .text_for_range(next_selection.range())
12544                                .collect::<String>();
12545                            if Some(next_selected_text) != selected_text {
12546                                same_text_selected = false;
12547                                selected_text = None;
12548                            }
12549                        } else {
12550                            same_text_selected = false;
12551                            selected_text = None;
12552                        }
12553                    }
12554                }
12555            }
12556
12557            if only_carets {
12558                for selection in &mut selections {
12559                    let word_range = movement::surrounding_word(
12560                        display_map,
12561                        selection.start.to_display_point(display_map),
12562                    );
12563                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12564                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12565                    selection.goal = SelectionGoal::None;
12566                    selection.reversed = false;
12567                    self.select_match_ranges(
12568                        selection.start..selection.end,
12569                        selection.reversed,
12570                        replace_newest,
12571                        autoscroll,
12572                        window,
12573                        cx,
12574                    );
12575                }
12576
12577                if selections.len() == 1 {
12578                    let selection = selections
12579                        .last()
12580                        .expect("ensured that there's only one selection");
12581                    let query = buffer
12582                        .text_for_range(selection.start..selection.end)
12583                        .collect::<String>();
12584                    let is_empty = query.is_empty();
12585                    let select_state = SelectNextState {
12586                        query: AhoCorasick::new(&[query])?,
12587                        wordwise: true,
12588                        done: is_empty,
12589                    };
12590                    self.select_next_state = Some(select_state);
12591                } else {
12592                    self.select_next_state = None;
12593                }
12594            } else if let Some(selected_text) = selected_text {
12595                self.select_next_state = Some(SelectNextState {
12596                    query: AhoCorasick::new(&[selected_text])?,
12597                    wordwise: false,
12598                    done: false,
12599                });
12600                self.select_next_match_internal(
12601                    display_map,
12602                    replace_newest,
12603                    autoscroll,
12604                    window,
12605                    cx,
12606                )?;
12607            }
12608        }
12609        Ok(())
12610    }
12611
12612    pub fn select_all_matches(
12613        &mut self,
12614        _action: &SelectAllMatches,
12615        window: &mut Window,
12616        cx: &mut Context<Self>,
12617    ) -> Result<()> {
12618        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12619
12620        self.push_to_selection_history();
12621        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12622
12623        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12624        let Some(select_next_state) = self.select_next_state.as_mut() else {
12625            return Ok(());
12626        };
12627        if select_next_state.done {
12628            return Ok(());
12629        }
12630
12631        let mut new_selections = Vec::new();
12632
12633        let reversed = self.selections.oldest::<usize>(cx).reversed;
12634        let buffer = &display_map.buffer_snapshot;
12635        let query_matches = select_next_state
12636            .query
12637            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12638
12639        for query_match in query_matches.into_iter() {
12640            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12641            let offset_range = if reversed {
12642                query_match.end()..query_match.start()
12643            } else {
12644                query_match.start()..query_match.end()
12645            };
12646            let display_range = offset_range.start.to_display_point(&display_map)
12647                ..offset_range.end.to_display_point(&display_map);
12648
12649            if !select_next_state.wordwise
12650                || (!movement::is_inside_word(&display_map, display_range.start)
12651                    && !movement::is_inside_word(&display_map, display_range.end))
12652            {
12653                new_selections.push(offset_range.start..offset_range.end);
12654            }
12655        }
12656
12657        select_next_state.done = true;
12658        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12659        self.change_selections(None, window, cx, |selections| {
12660            selections.select_ranges(new_selections)
12661        });
12662
12663        Ok(())
12664    }
12665
12666    pub fn select_next(
12667        &mut self,
12668        action: &SelectNext,
12669        window: &mut Window,
12670        cx: &mut Context<Self>,
12671    ) -> Result<()> {
12672        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12673        self.push_to_selection_history();
12674        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12675        self.select_next_match_internal(
12676            &display_map,
12677            action.replace_newest,
12678            Some(Autoscroll::newest()),
12679            window,
12680            cx,
12681        )?;
12682        Ok(())
12683    }
12684
12685    pub fn select_previous(
12686        &mut self,
12687        action: &SelectPrevious,
12688        window: &mut Window,
12689        cx: &mut Context<Self>,
12690    ) -> Result<()> {
12691        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12692        self.push_to_selection_history();
12693        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12694        let buffer = &display_map.buffer_snapshot;
12695        let mut selections = self.selections.all::<usize>(cx);
12696        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12697            let query = &select_prev_state.query;
12698            if !select_prev_state.done {
12699                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12700                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12701                let mut next_selected_range = None;
12702                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12703                let bytes_before_last_selection =
12704                    buffer.reversed_bytes_in_range(0..last_selection.start);
12705                let bytes_after_first_selection =
12706                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12707                let query_matches = query
12708                    .stream_find_iter(bytes_before_last_selection)
12709                    .map(|result| (last_selection.start, result))
12710                    .chain(
12711                        query
12712                            .stream_find_iter(bytes_after_first_selection)
12713                            .map(|result| (buffer.len(), result)),
12714                    );
12715                for (end_offset, query_match) in query_matches {
12716                    let query_match = query_match.unwrap(); // can only fail due to I/O
12717                    let offset_range =
12718                        end_offset - query_match.end()..end_offset - query_match.start();
12719                    let display_range = offset_range.start.to_display_point(&display_map)
12720                        ..offset_range.end.to_display_point(&display_map);
12721
12722                    if !select_prev_state.wordwise
12723                        || (!movement::is_inside_word(&display_map, display_range.start)
12724                            && !movement::is_inside_word(&display_map, display_range.end))
12725                    {
12726                        next_selected_range = Some(offset_range);
12727                        break;
12728                    }
12729                }
12730
12731                if let Some(next_selected_range) = next_selected_range {
12732                    self.select_match_ranges(
12733                        next_selected_range,
12734                        last_selection.reversed,
12735                        action.replace_newest,
12736                        Some(Autoscroll::newest()),
12737                        window,
12738                        cx,
12739                    );
12740                } else {
12741                    select_prev_state.done = true;
12742                }
12743            }
12744
12745            self.select_prev_state = Some(select_prev_state);
12746        } else {
12747            let mut only_carets = true;
12748            let mut same_text_selected = true;
12749            let mut selected_text = None;
12750
12751            let mut selections_iter = selections.iter().peekable();
12752            while let Some(selection) = selections_iter.next() {
12753                if selection.start != selection.end {
12754                    only_carets = false;
12755                }
12756
12757                if same_text_selected {
12758                    if selected_text.is_none() {
12759                        selected_text =
12760                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12761                    }
12762
12763                    if let Some(next_selection) = selections_iter.peek() {
12764                        if next_selection.range().len() == selection.range().len() {
12765                            let next_selected_text = buffer
12766                                .text_for_range(next_selection.range())
12767                                .collect::<String>();
12768                            if Some(next_selected_text) != selected_text {
12769                                same_text_selected = false;
12770                                selected_text = None;
12771                            }
12772                        } else {
12773                            same_text_selected = false;
12774                            selected_text = None;
12775                        }
12776                    }
12777                }
12778            }
12779
12780            if only_carets {
12781                for selection in &mut selections {
12782                    let word_range = movement::surrounding_word(
12783                        &display_map,
12784                        selection.start.to_display_point(&display_map),
12785                    );
12786                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12787                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12788                    selection.goal = SelectionGoal::None;
12789                    selection.reversed = false;
12790                    self.select_match_ranges(
12791                        selection.start..selection.end,
12792                        selection.reversed,
12793                        action.replace_newest,
12794                        Some(Autoscroll::newest()),
12795                        window,
12796                        cx,
12797                    );
12798                }
12799                if selections.len() == 1 {
12800                    let selection = selections
12801                        .last()
12802                        .expect("ensured that there's only one selection");
12803                    let query = buffer
12804                        .text_for_range(selection.start..selection.end)
12805                        .collect::<String>();
12806                    let is_empty = query.is_empty();
12807                    let select_state = SelectNextState {
12808                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12809                        wordwise: true,
12810                        done: is_empty,
12811                    };
12812                    self.select_prev_state = Some(select_state);
12813                } else {
12814                    self.select_prev_state = None;
12815                }
12816            } else if let Some(selected_text) = selected_text {
12817                self.select_prev_state = Some(SelectNextState {
12818                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12819                    wordwise: false,
12820                    done: false,
12821                });
12822                self.select_previous(action, window, cx)?;
12823            }
12824        }
12825        Ok(())
12826    }
12827
12828    pub fn find_next_match(
12829        &mut self,
12830        _: &FindNextMatch,
12831        window: &mut Window,
12832        cx: &mut Context<Self>,
12833    ) -> Result<()> {
12834        let selections = self.selections.disjoint_anchors();
12835        match selections.first() {
12836            Some(first) if selections.len() >= 2 => {
12837                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12838                    s.select_ranges([first.range()]);
12839                });
12840            }
12841            _ => self.select_next(
12842                &SelectNext {
12843                    replace_newest: true,
12844                },
12845                window,
12846                cx,
12847            )?,
12848        }
12849        Ok(())
12850    }
12851
12852    pub fn find_previous_match(
12853        &mut self,
12854        _: &FindPreviousMatch,
12855        window: &mut Window,
12856        cx: &mut Context<Self>,
12857    ) -> Result<()> {
12858        let selections = self.selections.disjoint_anchors();
12859        match selections.last() {
12860            Some(last) if selections.len() >= 2 => {
12861                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12862                    s.select_ranges([last.range()]);
12863                });
12864            }
12865            _ => self.select_previous(
12866                &SelectPrevious {
12867                    replace_newest: true,
12868                },
12869                window,
12870                cx,
12871            )?,
12872        }
12873        Ok(())
12874    }
12875
12876    pub fn toggle_comments(
12877        &mut self,
12878        action: &ToggleComments,
12879        window: &mut Window,
12880        cx: &mut Context<Self>,
12881    ) {
12882        if self.read_only(cx) {
12883            return;
12884        }
12885        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12886        let text_layout_details = &self.text_layout_details(window);
12887        self.transact(window, cx, |this, window, cx| {
12888            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12889            let mut edits = Vec::new();
12890            let mut selection_edit_ranges = Vec::new();
12891            let mut last_toggled_row = None;
12892            let snapshot = this.buffer.read(cx).read(cx);
12893            let empty_str: Arc<str> = Arc::default();
12894            let mut suffixes_inserted = Vec::new();
12895            let ignore_indent = action.ignore_indent;
12896
12897            fn comment_prefix_range(
12898                snapshot: &MultiBufferSnapshot,
12899                row: MultiBufferRow,
12900                comment_prefix: &str,
12901                comment_prefix_whitespace: &str,
12902                ignore_indent: bool,
12903            ) -> Range<Point> {
12904                let indent_size = if ignore_indent {
12905                    0
12906                } else {
12907                    snapshot.indent_size_for_line(row).len
12908                };
12909
12910                let start = Point::new(row.0, indent_size);
12911
12912                let mut line_bytes = snapshot
12913                    .bytes_in_range(start..snapshot.max_point())
12914                    .flatten()
12915                    .copied();
12916
12917                // If this line currently begins with the line comment prefix, then record
12918                // the range containing the prefix.
12919                if line_bytes
12920                    .by_ref()
12921                    .take(comment_prefix.len())
12922                    .eq(comment_prefix.bytes())
12923                {
12924                    // Include any whitespace that matches the comment prefix.
12925                    let matching_whitespace_len = line_bytes
12926                        .zip(comment_prefix_whitespace.bytes())
12927                        .take_while(|(a, b)| a == b)
12928                        .count() as u32;
12929                    let end = Point::new(
12930                        start.row,
12931                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12932                    );
12933                    start..end
12934                } else {
12935                    start..start
12936                }
12937            }
12938
12939            fn comment_suffix_range(
12940                snapshot: &MultiBufferSnapshot,
12941                row: MultiBufferRow,
12942                comment_suffix: &str,
12943                comment_suffix_has_leading_space: bool,
12944            ) -> Range<Point> {
12945                let end = Point::new(row.0, snapshot.line_len(row));
12946                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12947
12948                let mut line_end_bytes = snapshot
12949                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12950                    .flatten()
12951                    .copied();
12952
12953                let leading_space_len = if suffix_start_column > 0
12954                    && line_end_bytes.next() == Some(b' ')
12955                    && comment_suffix_has_leading_space
12956                {
12957                    1
12958                } else {
12959                    0
12960                };
12961
12962                // If this line currently begins with the line comment prefix, then record
12963                // the range containing the prefix.
12964                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12965                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12966                    start..end
12967                } else {
12968                    end..end
12969                }
12970            }
12971
12972            // TODO: Handle selections that cross excerpts
12973            for selection in &mut selections {
12974                let start_column = snapshot
12975                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12976                    .len;
12977                let language = if let Some(language) =
12978                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12979                {
12980                    language
12981                } else {
12982                    continue;
12983                };
12984
12985                selection_edit_ranges.clear();
12986
12987                // If multiple selections contain a given row, avoid processing that
12988                // row more than once.
12989                let mut start_row = MultiBufferRow(selection.start.row);
12990                if last_toggled_row == Some(start_row) {
12991                    start_row = start_row.next_row();
12992                }
12993                let end_row =
12994                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12995                        MultiBufferRow(selection.end.row - 1)
12996                    } else {
12997                        MultiBufferRow(selection.end.row)
12998                    };
12999                last_toggled_row = Some(end_row);
13000
13001                if start_row > end_row {
13002                    continue;
13003                }
13004
13005                // If the language has line comments, toggle those.
13006                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13007
13008                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13009                if ignore_indent {
13010                    full_comment_prefixes = full_comment_prefixes
13011                        .into_iter()
13012                        .map(|s| Arc::from(s.trim_end()))
13013                        .collect();
13014                }
13015
13016                if !full_comment_prefixes.is_empty() {
13017                    let first_prefix = full_comment_prefixes
13018                        .first()
13019                        .expect("prefixes is non-empty");
13020                    let prefix_trimmed_lengths = full_comment_prefixes
13021                        .iter()
13022                        .map(|p| p.trim_end_matches(' ').len())
13023                        .collect::<SmallVec<[usize; 4]>>();
13024
13025                    let mut all_selection_lines_are_comments = true;
13026
13027                    for row in start_row.0..=end_row.0 {
13028                        let row = MultiBufferRow(row);
13029                        if start_row < end_row && snapshot.is_line_blank(row) {
13030                            continue;
13031                        }
13032
13033                        let prefix_range = full_comment_prefixes
13034                            .iter()
13035                            .zip(prefix_trimmed_lengths.iter().copied())
13036                            .map(|(prefix, trimmed_prefix_len)| {
13037                                comment_prefix_range(
13038                                    snapshot.deref(),
13039                                    row,
13040                                    &prefix[..trimmed_prefix_len],
13041                                    &prefix[trimmed_prefix_len..],
13042                                    ignore_indent,
13043                                )
13044                            })
13045                            .max_by_key(|range| range.end.column - range.start.column)
13046                            .expect("prefixes is non-empty");
13047
13048                        if prefix_range.is_empty() {
13049                            all_selection_lines_are_comments = false;
13050                        }
13051
13052                        selection_edit_ranges.push(prefix_range);
13053                    }
13054
13055                    if all_selection_lines_are_comments {
13056                        edits.extend(
13057                            selection_edit_ranges
13058                                .iter()
13059                                .cloned()
13060                                .map(|range| (range, empty_str.clone())),
13061                        );
13062                    } else {
13063                        let min_column = selection_edit_ranges
13064                            .iter()
13065                            .map(|range| range.start.column)
13066                            .min()
13067                            .unwrap_or(0);
13068                        edits.extend(selection_edit_ranges.iter().map(|range| {
13069                            let position = Point::new(range.start.row, min_column);
13070                            (position..position, first_prefix.clone())
13071                        }));
13072                    }
13073                } else if let Some((full_comment_prefix, comment_suffix)) =
13074                    language.block_comment_delimiters()
13075                {
13076                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13077                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13078                    let prefix_range = comment_prefix_range(
13079                        snapshot.deref(),
13080                        start_row,
13081                        comment_prefix,
13082                        comment_prefix_whitespace,
13083                        ignore_indent,
13084                    );
13085                    let suffix_range = comment_suffix_range(
13086                        snapshot.deref(),
13087                        end_row,
13088                        comment_suffix.trim_start_matches(' '),
13089                        comment_suffix.starts_with(' '),
13090                    );
13091
13092                    if prefix_range.is_empty() || suffix_range.is_empty() {
13093                        edits.push((
13094                            prefix_range.start..prefix_range.start,
13095                            full_comment_prefix.clone(),
13096                        ));
13097                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13098                        suffixes_inserted.push((end_row, comment_suffix.len()));
13099                    } else {
13100                        edits.push((prefix_range, empty_str.clone()));
13101                        edits.push((suffix_range, empty_str.clone()));
13102                    }
13103                } else {
13104                    continue;
13105                }
13106            }
13107
13108            drop(snapshot);
13109            this.buffer.update(cx, |buffer, cx| {
13110                buffer.edit(edits, None, cx);
13111            });
13112
13113            // Adjust selections so that they end before any comment suffixes that
13114            // were inserted.
13115            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13116            let mut selections = this.selections.all::<Point>(cx);
13117            let snapshot = this.buffer.read(cx).read(cx);
13118            for selection in &mut selections {
13119                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13120                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13121                        Ordering::Less => {
13122                            suffixes_inserted.next();
13123                            continue;
13124                        }
13125                        Ordering::Greater => break,
13126                        Ordering::Equal => {
13127                            if selection.end.column == snapshot.line_len(row) {
13128                                if selection.is_empty() {
13129                                    selection.start.column -= suffix_len as u32;
13130                                }
13131                                selection.end.column -= suffix_len as u32;
13132                            }
13133                            break;
13134                        }
13135                    }
13136                }
13137            }
13138
13139            drop(snapshot);
13140            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13141                s.select(selections)
13142            });
13143
13144            let selections = this.selections.all::<Point>(cx);
13145            let selections_on_single_row = selections.windows(2).all(|selections| {
13146                selections[0].start.row == selections[1].start.row
13147                    && selections[0].end.row == selections[1].end.row
13148                    && selections[0].start.row == selections[0].end.row
13149            });
13150            let selections_selecting = selections
13151                .iter()
13152                .any(|selection| selection.start != selection.end);
13153            let advance_downwards = action.advance_downwards
13154                && selections_on_single_row
13155                && !selections_selecting
13156                && !matches!(this.mode, EditorMode::SingleLine { .. });
13157
13158            if advance_downwards {
13159                let snapshot = this.buffer.read(cx).snapshot(cx);
13160
13161                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13162                    s.move_cursors_with(|display_snapshot, display_point, _| {
13163                        let mut point = display_point.to_point(display_snapshot);
13164                        point.row += 1;
13165                        point = snapshot.clip_point(point, Bias::Left);
13166                        let display_point = point.to_display_point(display_snapshot);
13167                        let goal = SelectionGoal::HorizontalPosition(
13168                            display_snapshot
13169                                .x_for_display_point(display_point, text_layout_details)
13170                                .into(),
13171                        );
13172                        (display_point, goal)
13173                    })
13174                });
13175            }
13176        });
13177    }
13178
13179    pub fn select_enclosing_symbol(
13180        &mut self,
13181        _: &SelectEnclosingSymbol,
13182        window: &mut Window,
13183        cx: &mut Context<Self>,
13184    ) {
13185        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13186
13187        let buffer = self.buffer.read(cx).snapshot(cx);
13188        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13189
13190        fn update_selection(
13191            selection: &Selection<usize>,
13192            buffer_snap: &MultiBufferSnapshot,
13193        ) -> Option<Selection<usize>> {
13194            let cursor = selection.head();
13195            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13196            for symbol in symbols.iter().rev() {
13197                let start = symbol.range.start.to_offset(buffer_snap);
13198                let end = symbol.range.end.to_offset(buffer_snap);
13199                let new_range = start..end;
13200                if start < selection.start || end > selection.end {
13201                    return Some(Selection {
13202                        id: selection.id,
13203                        start: new_range.start,
13204                        end: new_range.end,
13205                        goal: SelectionGoal::None,
13206                        reversed: selection.reversed,
13207                    });
13208                }
13209            }
13210            None
13211        }
13212
13213        let mut selected_larger_symbol = false;
13214        let new_selections = old_selections
13215            .iter()
13216            .map(|selection| match update_selection(selection, &buffer) {
13217                Some(new_selection) => {
13218                    if new_selection.range() != selection.range() {
13219                        selected_larger_symbol = true;
13220                    }
13221                    new_selection
13222                }
13223                None => selection.clone(),
13224            })
13225            .collect::<Vec<_>>();
13226
13227        if selected_larger_symbol {
13228            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13229                s.select(new_selections);
13230            });
13231        }
13232    }
13233
13234    pub fn select_larger_syntax_node(
13235        &mut self,
13236        _: &SelectLargerSyntaxNode,
13237        window: &mut Window,
13238        cx: &mut Context<Self>,
13239    ) {
13240        let Some(visible_row_count) = self.visible_row_count() else {
13241            return;
13242        };
13243        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13244        if old_selections.is_empty() {
13245            return;
13246        }
13247
13248        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13249
13250        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13251        let buffer = self.buffer.read(cx).snapshot(cx);
13252
13253        let mut selected_larger_node = false;
13254        let mut new_selections = old_selections
13255            .iter()
13256            .map(|selection| {
13257                let old_range = selection.start..selection.end;
13258
13259                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13260                    // manually select word at selection
13261                    if ["string_content", "inline"].contains(&node.kind()) {
13262                        let word_range = {
13263                            let display_point = buffer
13264                                .offset_to_point(old_range.start)
13265                                .to_display_point(&display_map);
13266                            let Range { start, end } =
13267                                movement::surrounding_word(&display_map, display_point);
13268                            start.to_point(&display_map).to_offset(&buffer)
13269                                ..end.to_point(&display_map).to_offset(&buffer)
13270                        };
13271                        // ignore if word is already selected
13272                        if !word_range.is_empty() && old_range != word_range {
13273                            let last_word_range = {
13274                                let display_point = buffer
13275                                    .offset_to_point(old_range.end)
13276                                    .to_display_point(&display_map);
13277                                let Range { start, end } =
13278                                    movement::surrounding_word(&display_map, display_point);
13279                                start.to_point(&display_map).to_offset(&buffer)
13280                                    ..end.to_point(&display_map).to_offset(&buffer)
13281                            };
13282                            // only select word if start and end point belongs to same word
13283                            if word_range == last_word_range {
13284                                selected_larger_node = true;
13285                                return Selection {
13286                                    id: selection.id,
13287                                    start: word_range.start,
13288                                    end: word_range.end,
13289                                    goal: SelectionGoal::None,
13290                                    reversed: selection.reversed,
13291                                };
13292                            }
13293                        }
13294                    }
13295                }
13296
13297                let mut new_range = old_range.clone();
13298                while let Some((_node, containing_range)) =
13299                    buffer.syntax_ancestor(new_range.clone())
13300                {
13301                    new_range = match containing_range {
13302                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13303                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13304                    };
13305                    if !display_map.intersects_fold(new_range.start)
13306                        && !display_map.intersects_fold(new_range.end)
13307                    {
13308                        break;
13309                    }
13310                }
13311
13312                selected_larger_node |= new_range != old_range;
13313                Selection {
13314                    id: selection.id,
13315                    start: new_range.start,
13316                    end: new_range.end,
13317                    goal: SelectionGoal::None,
13318                    reversed: selection.reversed,
13319                }
13320            })
13321            .collect::<Vec<_>>();
13322
13323        if !selected_larger_node {
13324            return; // don't put this call in the history
13325        }
13326
13327        // scroll based on transformation done to the last selection created by the user
13328        let (last_old, last_new) = old_selections
13329            .last()
13330            .zip(new_selections.last().cloned())
13331            .expect("old_selections isn't empty");
13332
13333        // revert selection
13334        let is_selection_reversed = {
13335            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13336            new_selections.last_mut().expect("checked above").reversed =
13337                should_newest_selection_be_reversed;
13338            should_newest_selection_be_reversed
13339        };
13340
13341        if selected_larger_node {
13342            self.select_syntax_node_history.disable_clearing = true;
13343            self.change_selections(None, window, cx, |s| {
13344                s.select(new_selections.clone());
13345            });
13346            self.select_syntax_node_history.disable_clearing = false;
13347        }
13348
13349        let start_row = last_new.start.to_display_point(&display_map).row().0;
13350        let end_row = last_new.end.to_display_point(&display_map).row().0;
13351        let selection_height = end_row - start_row + 1;
13352        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13353
13354        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13355        let scroll_behavior = if fits_on_the_screen {
13356            self.request_autoscroll(Autoscroll::fit(), cx);
13357            SelectSyntaxNodeScrollBehavior::FitSelection
13358        } else if is_selection_reversed {
13359            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13360            SelectSyntaxNodeScrollBehavior::CursorTop
13361        } else {
13362            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13363            SelectSyntaxNodeScrollBehavior::CursorBottom
13364        };
13365
13366        self.select_syntax_node_history.push((
13367            old_selections,
13368            scroll_behavior,
13369            is_selection_reversed,
13370        ));
13371    }
13372
13373    pub fn select_smaller_syntax_node(
13374        &mut self,
13375        _: &SelectSmallerSyntaxNode,
13376        window: &mut Window,
13377        cx: &mut Context<Self>,
13378    ) {
13379        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13380
13381        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13382            self.select_syntax_node_history.pop()
13383        {
13384            if let Some(selection) = selections.last_mut() {
13385                selection.reversed = is_selection_reversed;
13386            }
13387
13388            self.select_syntax_node_history.disable_clearing = true;
13389            self.change_selections(None, window, cx, |s| {
13390                s.select(selections.to_vec());
13391            });
13392            self.select_syntax_node_history.disable_clearing = false;
13393
13394            match scroll_behavior {
13395                SelectSyntaxNodeScrollBehavior::CursorTop => {
13396                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13397                }
13398                SelectSyntaxNodeScrollBehavior::FitSelection => {
13399                    self.request_autoscroll(Autoscroll::fit(), cx);
13400                }
13401                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13402                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13403                }
13404            }
13405        }
13406    }
13407
13408    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13409        if !EditorSettings::get_global(cx).gutter.runnables {
13410            self.clear_tasks();
13411            return Task::ready(());
13412        }
13413        let project = self.project.as_ref().map(Entity::downgrade);
13414        let task_sources = self.lsp_task_sources(cx);
13415        cx.spawn_in(window, async move |editor, cx| {
13416            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13417            let Some(project) = project.and_then(|p| p.upgrade()) else {
13418                return;
13419            };
13420            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13421                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13422            }) else {
13423                return;
13424            };
13425
13426            let hide_runnables = project
13427                .update(cx, |project, cx| {
13428                    // Do not display any test indicators in non-dev server remote projects.
13429                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13430                })
13431                .unwrap_or(true);
13432            if hide_runnables {
13433                return;
13434            }
13435            let new_rows =
13436                cx.background_spawn({
13437                    let snapshot = display_snapshot.clone();
13438                    async move {
13439                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13440                    }
13441                })
13442                    .await;
13443            let Ok(lsp_tasks) =
13444                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13445            else {
13446                return;
13447            };
13448            let lsp_tasks = lsp_tasks.await;
13449
13450            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13451                lsp_tasks
13452                    .into_iter()
13453                    .flat_map(|(kind, tasks)| {
13454                        tasks.into_iter().filter_map(move |(location, task)| {
13455                            Some((kind.clone(), location?, task))
13456                        })
13457                    })
13458                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13459                        let buffer = location.target.buffer;
13460                        let buffer_snapshot = buffer.read(cx).snapshot();
13461                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13462                            |(excerpt_id, snapshot, _)| {
13463                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13464                                    display_snapshot
13465                                        .buffer_snapshot
13466                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13467                                } else {
13468                                    None
13469                                }
13470                            },
13471                        );
13472                        if let Some(offset) = offset {
13473                            let task_buffer_range =
13474                                location.target.range.to_point(&buffer_snapshot);
13475                            let context_buffer_range =
13476                                task_buffer_range.to_offset(&buffer_snapshot);
13477                            let context_range = BufferOffset(context_buffer_range.start)
13478                                ..BufferOffset(context_buffer_range.end);
13479
13480                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13481                                .or_insert_with(|| RunnableTasks {
13482                                    templates: Vec::new(),
13483                                    offset,
13484                                    column: task_buffer_range.start.column,
13485                                    extra_variables: HashMap::default(),
13486                                    context_range,
13487                                })
13488                                .templates
13489                                .push((kind, task.original_task().clone()));
13490                        }
13491
13492                        acc
13493                    })
13494            }) else {
13495                return;
13496            };
13497
13498            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13499            editor
13500                .update(cx, |editor, _| {
13501                    editor.clear_tasks();
13502                    for (key, mut value) in rows {
13503                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13504                            value.templates.extend(lsp_tasks.templates);
13505                        }
13506
13507                        editor.insert_tasks(key, value);
13508                    }
13509                    for (key, value) in lsp_tasks_by_rows {
13510                        editor.insert_tasks(key, value);
13511                    }
13512                })
13513                .ok();
13514        })
13515    }
13516    fn fetch_runnable_ranges(
13517        snapshot: &DisplaySnapshot,
13518        range: Range<Anchor>,
13519    ) -> Vec<language::RunnableRange> {
13520        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13521    }
13522
13523    fn runnable_rows(
13524        project: Entity<Project>,
13525        snapshot: DisplaySnapshot,
13526        runnable_ranges: Vec<RunnableRange>,
13527        mut cx: AsyncWindowContext,
13528    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13529        runnable_ranges
13530            .into_iter()
13531            .filter_map(|mut runnable| {
13532                let tasks = cx
13533                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13534                    .ok()?;
13535                if tasks.is_empty() {
13536                    return None;
13537                }
13538
13539                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13540
13541                let row = snapshot
13542                    .buffer_snapshot
13543                    .buffer_line_for_row(MultiBufferRow(point.row))?
13544                    .1
13545                    .start
13546                    .row;
13547
13548                let context_range =
13549                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13550                Some((
13551                    (runnable.buffer_id, row),
13552                    RunnableTasks {
13553                        templates: tasks,
13554                        offset: snapshot
13555                            .buffer_snapshot
13556                            .anchor_before(runnable.run_range.start),
13557                        context_range,
13558                        column: point.column,
13559                        extra_variables: runnable.extra_captures,
13560                    },
13561                ))
13562            })
13563            .collect()
13564    }
13565
13566    fn templates_with_tags(
13567        project: &Entity<Project>,
13568        runnable: &mut Runnable,
13569        cx: &mut App,
13570    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13571        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13572            let (worktree_id, file) = project
13573                .buffer_for_id(runnable.buffer, cx)
13574                .and_then(|buffer| buffer.read(cx).file())
13575                .map(|file| (file.worktree_id(cx), file.clone()))
13576                .unzip();
13577
13578            (
13579                project.task_store().read(cx).task_inventory().cloned(),
13580                worktree_id,
13581                file,
13582            )
13583        });
13584
13585        let mut templates_with_tags = mem::take(&mut runnable.tags)
13586            .into_iter()
13587            .flat_map(|RunnableTag(tag)| {
13588                inventory
13589                    .as_ref()
13590                    .into_iter()
13591                    .flat_map(|inventory| {
13592                        inventory.read(cx).list_tasks(
13593                            file.clone(),
13594                            Some(runnable.language.clone()),
13595                            worktree_id,
13596                            cx,
13597                        )
13598                    })
13599                    .filter(move |(_, template)| {
13600                        template.tags.iter().any(|source_tag| source_tag == &tag)
13601                    })
13602            })
13603            .sorted_by_key(|(kind, _)| kind.to_owned())
13604            .collect::<Vec<_>>();
13605        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13606            // Strongest source wins; if we have worktree tag binding, prefer that to
13607            // global and language bindings;
13608            // if we have a global binding, prefer that to language binding.
13609            let first_mismatch = templates_with_tags
13610                .iter()
13611                .position(|(tag_source, _)| tag_source != leading_tag_source);
13612            if let Some(index) = first_mismatch {
13613                templates_with_tags.truncate(index);
13614            }
13615        }
13616
13617        templates_with_tags
13618    }
13619
13620    pub fn move_to_enclosing_bracket(
13621        &mut self,
13622        _: &MoveToEnclosingBracket,
13623        window: &mut Window,
13624        cx: &mut Context<Self>,
13625    ) {
13626        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13627        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13628            s.move_offsets_with(|snapshot, selection| {
13629                let Some(enclosing_bracket_ranges) =
13630                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13631                else {
13632                    return;
13633                };
13634
13635                let mut best_length = usize::MAX;
13636                let mut best_inside = false;
13637                let mut best_in_bracket_range = false;
13638                let mut best_destination = None;
13639                for (open, close) in enclosing_bracket_ranges {
13640                    let close = close.to_inclusive();
13641                    let length = close.end() - open.start;
13642                    let inside = selection.start >= open.end && selection.end <= *close.start();
13643                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13644                        || close.contains(&selection.head());
13645
13646                    // If best is next to a bracket and current isn't, skip
13647                    if !in_bracket_range && best_in_bracket_range {
13648                        continue;
13649                    }
13650
13651                    // Prefer smaller lengths unless best is inside and current isn't
13652                    if length > best_length && (best_inside || !inside) {
13653                        continue;
13654                    }
13655
13656                    best_length = length;
13657                    best_inside = inside;
13658                    best_in_bracket_range = in_bracket_range;
13659                    best_destination = Some(
13660                        if close.contains(&selection.start) && close.contains(&selection.end) {
13661                            if inside { open.end } else { open.start }
13662                        } else if inside {
13663                            *close.start()
13664                        } else {
13665                            *close.end()
13666                        },
13667                    );
13668                }
13669
13670                if let Some(destination) = best_destination {
13671                    selection.collapse_to(destination, SelectionGoal::None);
13672                }
13673            })
13674        });
13675    }
13676
13677    pub fn undo_selection(
13678        &mut self,
13679        _: &UndoSelection,
13680        window: &mut Window,
13681        cx: &mut Context<Self>,
13682    ) {
13683        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13684        self.end_selection(window, cx);
13685        self.selection_history.mode = SelectionHistoryMode::Undoing;
13686        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13687            self.change_selections(None, window, cx, |s| {
13688                s.select_anchors(entry.selections.to_vec())
13689            });
13690            self.select_next_state = entry.select_next_state;
13691            self.select_prev_state = entry.select_prev_state;
13692            self.add_selections_state = entry.add_selections_state;
13693            self.request_autoscroll(Autoscroll::newest(), cx);
13694        }
13695        self.selection_history.mode = SelectionHistoryMode::Normal;
13696    }
13697
13698    pub fn redo_selection(
13699        &mut self,
13700        _: &RedoSelection,
13701        window: &mut Window,
13702        cx: &mut Context<Self>,
13703    ) {
13704        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13705        self.end_selection(window, cx);
13706        self.selection_history.mode = SelectionHistoryMode::Redoing;
13707        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13708            self.change_selections(None, window, cx, |s| {
13709                s.select_anchors(entry.selections.to_vec())
13710            });
13711            self.select_next_state = entry.select_next_state;
13712            self.select_prev_state = entry.select_prev_state;
13713            self.add_selections_state = entry.add_selections_state;
13714            self.request_autoscroll(Autoscroll::newest(), cx);
13715        }
13716        self.selection_history.mode = SelectionHistoryMode::Normal;
13717    }
13718
13719    pub fn expand_excerpts(
13720        &mut self,
13721        action: &ExpandExcerpts,
13722        _: &mut Window,
13723        cx: &mut Context<Self>,
13724    ) {
13725        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13726    }
13727
13728    pub fn expand_excerpts_down(
13729        &mut self,
13730        action: &ExpandExcerptsDown,
13731        _: &mut Window,
13732        cx: &mut Context<Self>,
13733    ) {
13734        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13735    }
13736
13737    pub fn expand_excerpts_up(
13738        &mut self,
13739        action: &ExpandExcerptsUp,
13740        _: &mut Window,
13741        cx: &mut Context<Self>,
13742    ) {
13743        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13744    }
13745
13746    pub fn expand_excerpts_for_direction(
13747        &mut self,
13748        lines: u32,
13749        direction: ExpandExcerptDirection,
13750
13751        cx: &mut Context<Self>,
13752    ) {
13753        let selections = self.selections.disjoint_anchors();
13754
13755        let lines = if lines == 0 {
13756            EditorSettings::get_global(cx).expand_excerpt_lines
13757        } else {
13758            lines
13759        };
13760
13761        self.buffer.update(cx, |buffer, cx| {
13762            let snapshot = buffer.snapshot(cx);
13763            let mut excerpt_ids = selections
13764                .iter()
13765                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13766                .collect::<Vec<_>>();
13767            excerpt_ids.sort();
13768            excerpt_ids.dedup();
13769            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13770        })
13771    }
13772
13773    pub fn expand_excerpt(
13774        &mut self,
13775        excerpt: ExcerptId,
13776        direction: ExpandExcerptDirection,
13777        window: &mut Window,
13778        cx: &mut Context<Self>,
13779    ) {
13780        let current_scroll_position = self.scroll_position(cx);
13781        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13782        let mut should_scroll_up = false;
13783
13784        if direction == ExpandExcerptDirection::Down {
13785            let multi_buffer = self.buffer.read(cx);
13786            let snapshot = multi_buffer.snapshot(cx);
13787            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13788                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13789                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13790                        let buffer_snapshot = buffer.read(cx).snapshot();
13791                        let excerpt_end_row =
13792                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13793                        let last_row = buffer_snapshot.max_point().row;
13794                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13795                        should_scroll_up = lines_below >= lines_to_expand;
13796                    }
13797                }
13798            }
13799        }
13800
13801        self.buffer.update(cx, |buffer, cx| {
13802            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13803        });
13804
13805        if should_scroll_up {
13806            let new_scroll_position =
13807                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13808            self.set_scroll_position(new_scroll_position, window, cx);
13809        }
13810    }
13811
13812    pub fn go_to_singleton_buffer_point(
13813        &mut self,
13814        point: Point,
13815        window: &mut Window,
13816        cx: &mut Context<Self>,
13817    ) {
13818        self.go_to_singleton_buffer_range(point..point, window, cx);
13819    }
13820
13821    pub fn go_to_singleton_buffer_range(
13822        &mut self,
13823        range: Range<Point>,
13824        window: &mut Window,
13825        cx: &mut Context<Self>,
13826    ) {
13827        let multibuffer = self.buffer().read(cx);
13828        let Some(buffer) = multibuffer.as_singleton() else {
13829            return;
13830        };
13831        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13832            return;
13833        };
13834        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13835            return;
13836        };
13837        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13838            s.select_anchor_ranges([start..end])
13839        });
13840    }
13841
13842    pub fn go_to_diagnostic(
13843        &mut self,
13844        _: &GoToDiagnostic,
13845        window: &mut Window,
13846        cx: &mut Context<Self>,
13847    ) {
13848        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13849        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13850    }
13851
13852    pub fn go_to_prev_diagnostic(
13853        &mut self,
13854        _: &GoToPreviousDiagnostic,
13855        window: &mut Window,
13856        cx: &mut Context<Self>,
13857    ) {
13858        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13859        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13860    }
13861
13862    pub fn go_to_diagnostic_impl(
13863        &mut self,
13864        direction: Direction,
13865        window: &mut Window,
13866        cx: &mut Context<Self>,
13867    ) {
13868        let buffer = self.buffer.read(cx).snapshot(cx);
13869        let selection = self.selections.newest::<usize>(cx);
13870
13871        let mut active_group_id = None;
13872        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13873            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13874                active_group_id = Some(active_group.group_id);
13875            }
13876        }
13877
13878        fn filtered(
13879            snapshot: EditorSnapshot,
13880            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13881        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13882            diagnostics
13883                .filter(|entry| entry.range.start != entry.range.end)
13884                .filter(|entry| !entry.diagnostic.is_unnecessary)
13885                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13886        }
13887
13888        let snapshot = self.snapshot(window, cx);
13889        let before = filtered(
13890            snapshot.clone(),
13891            buffer
13892                .diagnostics_in_range(0..selection.start)
13893                .filter(|entry| entry.range.start <= selection.start),
13894        );
13895        let after = filtered(
13896            snapshot,
13897            buffer
13898                .diagnostics_in_range(selection.start..buffer.len())
13899                .filter(|entry| entry.range.start >= selection.start),
13900        );
13901
13902        let mut found: Option<DiagnosticEntry<usize>> = None;
13903        if direction == Direction::Prev {
13904            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13905            {
13906                for diagnostic in prev_diagnostics.into_iter().rev() {
13907                    if diagnostic.range.start != selection.start
13908                        || active_group_id
13909                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13910                    {
13911                        found = Some(diagnostic);
13912                        break 'outer;
13913                    }
13914                }
13915            }
13916        } else {
13917            for diagnostic in after.chain(before) {
13918                if diagnostic.range.start != selection.start
13919                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13920                {
13921                    found = Some(diagnostic);
13922                    break;
13923                }
13924            }
13925        }
13926        let Some(next_diagnostic) = found else {
13927            return;
13928        };
13929
13930        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13931            return;
13932        };
13933        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13934            s.select_ranges(vec![
13935                next_diagnostic.range.start..next_diagnostic.range.start,
13936            ])
13937        });
13938        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13939        self.refresh_inline_completion(false, true, window, cx);
13940    }
13941
13942    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13943        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13944        let snapshot = self.snapshot(window, cx);
13945        let selection = self.selections.newest::<Point>(cx);
13946        self.go_to_hunk_before_or_after_position(
13947            &snapshot,
13948            selection.head(),
13949            Direction::Next,
13950            window,
13951            cx,
13952        );
13953    }
13954
13955    pub fn go_to_hunk_before_or_after_position(
13956        &mut self,
13957        snapshot: &EditorSnapshot,
13958        position: Point,
13959        direction: Direction,
13960        window: &mut Window,
13961        cx: &mut Context<Editor>,
13962    ) {
13963        let row = if direction == Direction::Next {
13964            self.hunk_after_position(snapshot, position)
13965                .map(|hunk| hunk.row_range.start)
13966        } else {
13967            self.hunk_before_position(snapshot, position)
13968        };
13969
13970        if let Some(row) = row {
13971            let destination = Point::new(row.0, 0);
13972            let autoscroll = Autoscroll::center();
13973
13974            self.unfold_ranges(&[destination..destination], false, false, cx);
13975            self.change_selections(Some(autoscroll), window, cx, |s| {
13976                s.select_ranges([destination..destination]);
13977            });
13978        }
13979    }
13980
13981    fn hunk_after_position(
13982        &mut self,
13983        snapshot: &EditorSnapshot,
13984        position: Point,
13985    ) -> Option<MultiBufferDiffHunk> {
13986        snapshot
13987            .buffer_snapshot
13988            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13989            .find(|hunk| hunk.row_range.start.0 > position.row)
13990            .or_else(|| {
13991                snapshot
13992                    .buffer_snapshot
13993                    .diff_hunks_in_range(Point::zero()..position)
13994                    .find(|hunk| hunk.row_range.end.0 < position.row)
13995            })
13996    }
13997
13998    fn go_to_prev_hunk(
13999        &mut self,
14000        _: &GoToPreviousHunk,
14001        window: &mut Window,
14002        cx: &mut Context<Self>,
14003    ) {
14004        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14005        let snapshot = self.snapshot(window, cx);
14006        let selection = self.selections.newest::<Point>(cx);
14007        self.go_to_hunk_before_or_after_position(
14008            &snapshot,
14009            selection.head(),
14010            Direction::Prev,
14011            window,
14012            cx,
14013        );
14014    }
14015
14016    fn hunk_before_position(
14017        &mut self,
14018        snapshot: &EditorSnapshot,
14019        position: Point,
14020    ) -> Option<MultiBufferRow> {
14021        snapshot
14022            .buffer_snapshot
14023            .diff_hunk_before(position)
14024            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14025    }
14026
14027    fn go_to_next_change(
14028        &mut self,
14029        _: &GoToNextChange,
14030        window: &mut Window,
14031        cx: &mut Context<Self>,
14032    ) {
14033        if let Some(selections) = self
14034            .change_list
14035            .next_change(1, Direction::Next)
14036            .map(|s| s.to_vec())
14037        {
14038            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14039                let map = s.display_map();
14040                s.select_display_ranges(selections.iter().map(|a| {
14041                    let point = a.to_display_point(&map);
14042                    point..point
14043                }))
14044            })
14045        }
14046    }
14047
14048    fn go_to_previous_change(
14049        &mut self,
14050        _: &GoToPreviousChange,
14051        window: &mut Window,
14052        cx: &mut Context<Self>,
14053    ) {
14054        if let Some(selections) = self
14055            .change_list
14056            .next_change(1, Direction::Prev)
14057            .map(|s| s.to_vec())
14058        {
14059            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14060                let map = s.display_map();
14061                s.select_display_ranges(selections.iter().map(|a| {
14062                    let point = a.to_display_point(&map);
14063                    point..point
14064                }))
14065            })
14066        }
14067    }
14068
14069    fn go_to_line<T: 'static>(
14070        &mut self,
14071        position: Anchor,
14072        highlight_color: Option<Hsla>,
14073        window: &mut Window,
14074        cx: &mut Context<Self>,
14075    ) {
14076        let snapshot = self.snapshot(window, cx).display_snapshot;
14077        let position = position.to_point(&snapshot.buffer_snapshot);
14078        let start = snapshot
14079            .buffer_snapshot
14080            .clip_point(Point::new(position.row, 0), Bias::Left);
14081        let end = start + Point::new(1, 0);
14082        let start = snapshot.buffer_snapshot.anchor_before(start);
14083        let end = snapshot.buffer_snapshot.anchor_before(end);
14084
14085        self.highlight_rows::<T>(
14086            start..end,
14087            highlight_color
14088                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14089            Default::default(),
14090            cx,
14091        );
14092
14093        if self.buffer.read(cx).is_singleton() {
14094            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14095        }
14096    }
14097
14098    pub fn go_to_definition(
14099        &mut self,
14100        _: &GoToDefinition,
14101        window: &mut Window,
14102        cx: &mut Context<Self>,
14103    ) -> Task<Result<Navigated>> {
14104        let definition =
14105            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14106        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14107        cx.spawn_in(window, async move |editor, cx| {
14108            if definition.await? == Navigated::Yes {
14109                return Ok(Navigated::Yes);
14110            }
14111            match fallback_strategy {
14112                GoToDefinitionFallback::None => Ok(Navigated::No),
14113                GoToDefinitionFallback::FindAllReferences => {
14114                    match editor.update_in(cx, |editor, window, cx| {
14115                        editor.find_all_references(&FindAllReferences, window, cx)
14116                    })? {
14117                        Some(references) => references.await,
14118                        None => Ok(Navigated::No),
14119                    }
14120                }
14121            }
14122        })
14123    }
14124
14125    pub fn go_to_declaration(
14126        &mut self,
14127        _: &GoToDeclaration,
14128        window: &mut Window,
14129        cx: &mut Context<Self>,
14130    ) -> Task<Result<Navigated>> {
14131        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14132    }
14133
14134    pub fn go_to_declaration_split(
14135        &mut self,
14136        _: &GoToDeclaration,
14137        window: &mut Window,
14138        cx: &mut Context<Self>,
14139    ) -> Task<Result<Navigated>> {
14140        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14141    }
14142
14143    pub fn go_to_implementation(
14144        &mut self,
14145        _: &GoToImplementation,
14146        window: &mut Window,
14147        cx: &mut Context<Self>,
14148    ) -> Task<Result<Navigated>> {
14149        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14150    }
14151
14152    pub fn go_to_implementation_split(
14153        &mut self,
14154        _: &GoToImplementationSplit,
14155        window: &mut Window,
14156        cx: &mut Context<Self>,
14157    ) -> Task<Result<Navigated>> {
14158        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14159    }
14160
14161    pub fn go_to_type_definition(
14162        &mut self,
14163        _: &GoToTypeDefinition,
14164        window: &mut Window,
14165        cx: &mut Context<Self>,
14166    ) -> Task<Result<Navigated>> {
14167        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14168    }
14169
14170    pub fn go_to_definition_split(
14171        &mut self,
14172        _: &GoToDefinitionSplit,
14173        window: &mut Window,
14174        cx: &mut Context<Self>,
14175    ) -> Task<Result<Navigated>> {
14176        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14177    }
14178
14179    pub fn go_to_type_definition_split(
14180        &mut self,
14181        _: &GoToTypeDefinitionSplit,
14182        window: &mut Window,
14183        cx: &mut Context<Self>,
14184    ) -> Task<Result<Navigated>> {
14185        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14186    }
14187
14188    fn go_to_definition_of_kind(
14189        &mut self,
14190        kind: GotoDefinitionKind,
14191        split: bool,
14192        window: &mut Window,
14193        cx: &mut Context<Self>,
14194    ) -> Task<Result<Navigated>> {
14195        let Some(provider) = self.semantics_provider.clone() else {
14196            return Task::ready(Ok(Navigated::No));
14197        };
14198        let head = self.selections.newest::<usize>(cx).head();
14199        let buffer = self.buffer.read(cx);
14200        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14201            text_anchor
14202        } else {
14203            return Task::ready(Ok(Navigated::No));
14204        };
14205
14206        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14207            return Task::ready(Ok(Navigated::No));
14208        };
14209
14210        cx.spawn_in(window, async move |editor, cx| {
14211            let definitions = definitions.await?;
14212            let navigated = editor
14213                .update_in(cx, |editor, window, cx| {
14214                    editor.navigate_to_hover_links(
14215                        Some(kind),
14216                        definitions
14217                            .into_iter()
14218                            .filter(|location| {
14219                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14220                            })
14221                            .map(HoverLink::Text)
14222                            .collect::<Vec<_>>(),
14223                        split,
14224                        window,
14225                        cx,
14226                    )
14227                })?
14228                .await?;
14229            anyhow::Ok(navigated)
14230        })
14231    }
14232
14233    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14234        let selection = self.selections.newest_anchor();
14235        let head = selection.head();
14236        let tail = selection.tail();
14237
14238        let Some((buffer, start_position)) =
14239            self.buffer.read(cx).text_anchor_for_position(head, cx)
14240        else {
14241            return;
14242        };
14243
14244        let end_position = if head != tail {
14245            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14246                return;
14247            };
14248            Some(pos)
14249        } else {
14250            None
14251        };
14252
14253        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14254            let url = if let Some(end_pos) = end_position {
14255                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14256            } else {
14257                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14258            };
14259
14260            if let Some(url) = url {
14261                editor.update(cx, |_, cx| {
14262                    cx.open_url(&url);
14263                })
14264            } else {
14265                Ok(())
14266            }
14267        });
14268
14269        url_finder.detach();
14270    }
14271
14272    pub fn open_selected_filename(
14273        &mut self,
14274        _: &OpenSelectedFilename,
14275        window: &mut Window,
14276        cx: &mut Context<Self>,
14277    ) {
14278        let Some(workspace) = self.workspace() else {
14279            return;
14280        };
14281
14282        let position = self.selections.newest_anchor().head();
14283
14284        let Some((buffer, buffer_position)) =
14285            self.buffer.read(cx).text_anchor_for_position(position, cx)
14286        else {
14287            return;
14288        };
14289
14290        let project = self.project.clone();
14291
14292        cx.spawn_in(window, async move |_, cx| {
14293            let result = find_file(&buffer, project, buffer_position, cx).await;
14294
14295            if let Some((_, path)) = result {
14296                workspace
14297                    .update_in(cx, |workspace, window, cx| {
14298                        workspace.open_resolved_path(path, window, cx)
14299                    })?
14300                    .await?;
14301            }
14302            anyhow::Ok(())
14303        })
14304        .detach();
14305    }
14306
14307    pub(crate) fn navigate_to_hover_links(
14308        &mut self,
14309        kind: Option<GotoDefinitionKind>,
14310        mut definitions: Vec<HoverLink>,
14311        split: bool,
14312        window: &mut Window,
14313        cx: &mut Context<Editor>,
14314    ) -> Task<Result<Navigated>> {
14315        // If there is one definition, just open it directly
14316        if definitions.len() == 1 {
14317            let definition = definitions.pop().unwrap();
14318
14319            enum TargetTaskResult {
14320                Location(Option<Location>),
14321                AlreadyNavigated,
14322            }
14323
14324            let target_task = match definition {
14325                HoverLink::Text(link) => {
14326                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14327                }
14328                HoverLink::InlayHint(lsp_location, server_id) => {
14329                    let computation =
14330                        self.compute_target_location(lsp_location, server_id, window, cx);
14331                    cx.background_spawn(async move {
14332                        let location = computation.await?;
14333                        Ok(TargetTaskResult::Location(location))
14334                    })
14335                }
14336                HoverLink::Url(url) => {
14337                    cx.open_url(&url);
14338                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14339                }
14340                HoverLink::File(path) => {
14341                    if let Some(workspace) = self.workspace() {
14342                        cx.spawn_in(window, async move |_, cx| {
14343                            workspace
14344                                .update_in(cx, |workspace, window, cx| {
14345                                    workspace.open_resolved_path(path, window, cx)
14346                                })?
14347                                .await
14348                                .map(|_| TargetTaskResult::AlreadyNavigated)
14349                        })
14350                    } else {
14351                        Task::ready(Ok(TargetTaskResult::Location(None)))
14352                    }
14353                }
14354            };
14355            cx.spawn_in(window, async move |editor, cx| {
14356                let target = match target_task.await.context("target resolution task")? {
14357                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14358                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14359                    TargetTaskResult::Location(Some(target)) => target,
14360                };
14361
14362                editor.update_in(cx, |editor, window, cx| {
14363                    let Some(workspace) = editor.workspace() else {
14364                        return Navigated::No;
14365                    };
14366                    let pane = workspace.read(cx).active_pane().clone();
14367
14368                    let range = target.range.to_point(target.buffer.read(cx));
14369                    let range = editor.range_for_match(&range);
14370                    let range = collapse_multiline_range(range);
14371
14372                    if !split
14373                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14374                    {
14375                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14376                    } else {
14377                        window.defer(cx, move |window, cx| {
14378                            let target_editor: Entity<Self> =
14379                                workspace.update(cx, |workspace, cx| {
14380                                    let pane = if split {
14381                                        workspace.adjacent_pane(window, cx)
14382                                    } else {
14383                                        workspace.active_pane().clone()
14384                                    };
14385
14386                                    workspace.open_project_item(
14387                                        pane,
14388                                        target.buffer.clone(),
14389                                        true,
14390                                        true,
14391                                        window,
14392                                        cx,
14393                                    )
14394                                });
14395                            target_editor.update(cx, |target_editor, cx| {
14396                                // When selecting a definition in a different buffer, disable the nav history
14397                                // to avoid creating a history entry at the previous cursor location.
14398                                pane.update(cx, |pane, _| pane.disable_history());
14399                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14400                                pane.update(cx, |pane, _| pane.enable_history());
14401                            });
14402                        });
14403                    }
14404                    Navigated::Yes
14405                })
14406            })
14407        } else if !definitions.is_empty() {
14408            cx.spawn_in(window, async move |editor, cx| {
14409                let (title, location_tasks, workspace) = editor
14410                    .update_in(cx, |editor, window, cx| {
14411                        let tab_kind = match kind {
14412                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14413                            _ => "Definitions",
14414                        };
14415                        let title = definitions
14416                            .iter()
14417                            .find_map(|definition| match definition {
14418                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14419                                    let buffer = origin.buffer.read(cx);
14420                                    format!(
14421                                        "{} for {}",
14422                                        tab_kind,
14423                                        buffer
14424                                            .text_for_range(origin.range.clone())
14425                                            .collect::<String>()
14426                                    )
14427                                }),
14428                                HoverLink::InlayHint(_, _) => None,
14429                                HoverLink::Url(_) => None,
14430                                HoverLink::File(_) => None,
14431                            })
14432                            .unwrap_or(tab_kind.to_string());
14433                        let location_tasks = definitions
14434                            .into_iter()
14435                            .map(|definition| match definition {
14436                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14437                                HoverLink::InlayHint(lsp_location, server_id) => editor
14438                                    .compute_target_location(lsp_location, server_id, window, cx),
14439                                HoverLink::Url(_) => Task::ready(Ok(None)),
14440                                HoverLink::File(_) => Task::ready(Ok(None)),
14441                            })
14442                            .collect::<Vec<_>>();
14443                        (title, location_tasks, editor.workspace().clone())
14444                    })
14445                    .context("location tasks preparation")?;
14446
14447                let locations = future::join_all(location_tasks)
14448                    .await
14449                    .into_iter()
14450                    .filter_map(|location| location.transpose())
14451                    .collect::<Result<_>>()
14452                    .context("location tasks")?;
14453
14454                let Some(workspace) = workspace else {
14455                    return Ok(Navigated::No);
14456                };
14457                let opened = workspace
14458                    .update_in(cx, |workspace, window, cx| {
14459                        Self::open_locations_in_multibuffer(
14460                            workspace,
14461                            locations,
14462                            title,
14463                            split,
14464                            MultibufferSelectionMode::First,
14465                            window,
14466                            cx,
14467                        )
14468                    })
14469                    .ok();
14470
14471                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14472            })
14473        } else {
14474            Task::ready(Ok(Navigated::No))
14475        }
14476    }
14477
14478    fn compute_target_location(
14479        &self,
14480        lsp_location: lsp::Location,
14481        server_id: LanguageServerId,
14482        window: &mut Window,
14483        cx: &mut Context<Self>,
14484    ) -> Task<anyhow::Result<Option<Location>>> {
14485        let Some(project) = self.project.clone() else {
14486            return Task::ready(Ok(None));
14487        };
14488
14489        cx.spawn_in(window, async move |editor, cx| {
14490            let location_task = editor.update(cx, |_, cx| {
14491                project.update(cx, |project, cx| {
14492                    let language_server_name = project
14493                        .language_server_statuses(cx)
14494                        .find(|(id, _)| server_id == *id)
14495                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14496                    language_server_name.map(|language_server_name| {
14497                        project.open_local_buffer_via_lsp(
14498                            lsp_location.uri.clone(),
14499                            server_id,
14500                            language_server_name,
14501                            cx,
14502                        )
14503                    })
14504                })
14505            })?;
14506            let location = match location_task {
14507                Some(task) => Some({
14508                    let target_buffer_handle = task.await.context("open local buffer")?;
14509                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14510                        let target_start = target_buffer
14511                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14512                        let target_end = target_buffer
14513                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14514                        target_buffer.anchor_after(target_start)
14515                            ..target_buffer.anchor_before(target_end)
14516                    })?;
14517                    Location {
14518                        buffer: target_buffer_handle,
14519                        range,
14520                    }
14521                }),
14522                None => None,
14523            };
14524            Ok(location)
14525        })
14526    }
14527
14528    pub fn find_all_references(
14529        &mut self,
14530        _: &FindAllReferences,
14531        window: &mut Window,
14532        cx: &mut Context<Self>,
14533    ) -> Option<Task<Result<Navigated>>> {
14534        let selection = self.selections.newest::<usize>(cx);
14535        let multi_buffer = self.buffer.read(cx);
14536        let head = selection.head();
14537
14538        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14539        let head_anchor = multi_buffer_snapshot.anchor_at(
14540            head,
14541            if head < selection.tail() {
14542                Bias::Right
14543            } else {
14544                Bias::Left
14545            },
14546        );
14547
14548        match self
14549            .find_all_references_task_sources
14550            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14551        {
14552            Ok(_) => {
14553                log::info!(
14554                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14555                );
14556                return None;
14557            }
14558            Err(i) => {
14559                self.find_all_references_task_sources.insert(i, head_anchor);
14560            }
14561        }
14562
14563        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14564        let workspace = self.workspace()?;
14565        let project = workspace.read(cx).project().clone();
14566        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14567        Some(cx.spawn_in(window, async move |editor, cx| {
14568            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14569                if let Ok(i) = editor
14570                    .find_all_references_task_sources
14571                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14572                {
14573                    editor.find_all_references_task_sources.remove(i);
14574                }
14575            });
14576
14577            let locations = references.await?;
14578            if locations.is_empty() {
14579                return anyhow::Ok(Navigated::No);
14580            }
14581
14582            workspace.update_in(cx, |workspace, window, cx| {
14583                let title = locations
14584                    .first()
14585                    .as_ref()
14586                    .map(|location| {
14587                        let buffer = location.buffer.read(cx);
14588                        format!(
14589                            "References to `{}`",
14590                            buffer
14591                                .text_for_range(location.range.clone())
14592                                .collect::<String>()
14593                        )
14594                    })
14595                    .unwrap();
14596                Self::open_locations_in_multibuffer(
14597                    workspace,
14598                    locations,
14599                    title,
14600                    false,
14601                    MultibufferSelectionMode::First,
14602                    window,
14603                    cx,
14604                );
14605                Navigated::Yes
14606            })
14607        }))
14608    }
14609
14610    /// Opens a multibuffer with the given project locations in it
14611    pub fn open_locations_in_multibuffer(
14612        workspace: &mut Workspace,
14613        mut locations: Vec<Location>,
14614        title: String,
14615        split: bool,
14616        multibuffer_selection_mode: MultibufferSelectionMode,
14617        window: &mut Window,
14618        cx: &mut Context<Workspace>,
14619    ) {
14620        // If there are multiple definitions, open them in a multibuffer
14621        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14622        let mut locations = locations.into_iter().peekable();
14623        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14624        let capability = workspace.project().read(cx).capability();
14625
14626        let excerpt_buffer = cx.new(|cx| {
14627            let mut multibuffer = MultiBuffer::new(capability);
14628            while let Some(location) = locations.next() {
14629                let buffer = location.buffer.read(cx);
14630                let mut ranges_for_buffer = Vec::new();
14631                let range = location.range.to_point(buffer);
14632                ranges_for_buffer.push(range.clone());
14633
14634                while let Some(next_location) = locations.peek() {
14635                    if next_location.buffer == location.buffer {
14636                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14637                        locations.next();
14638                    } else {
14639                        break;
14640                    }
14641                }
14642
14643                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14644                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14645                    PathKey::for_buffer(&location.buffer, cx),
14646                    location.buffer.clone(),
14647                    ranges_for_buffer,
14648                    DEFAULT_MULTIBUFFER_CONTEXT,
14649                    cx,
14650                );
14651                ranges.extend(new_ranges)
14652            }
14653
14654            multibuffer.with_title(title)
14655        });
14656
14657        let editor = cx.new(|cx| {
14658            Editor::for_multibuffer(
14659                excerpt_buffer,
14660                Some(workspace.project().clone()),
14661                window,
14662                cx,
14663            )
14664        });
14665        editor.update(cx, |editor, cx| {
14666            match multibuffer_selection_mode {
14667                MultibufferSelectionMode::First => {
14668                    if let Some(first_range) = ranges.first() {
14669                        editor.change_selections(None, window, cx, |selections| {
14670                            selections.clear_disjoint();
14671                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14672                        });
14673                    }
14674                    editor.highlight_background::<Self>(
14675                        &ranges,
14676                        |theme| theme.editor_highlighted_line_background,
14677                        cx,
14678                    );
14679                }
14680                MultibufferSelectionMode::All => {
14681                    editor.change_selections(None, window, cx, |selections| {
14682                        selections.clear_disjoint();
14683                        selections.select_anchor_ranges(ranges);
14684                    });
14685                }
14686            }
14687            editor.register_buffers_with_language_servers(cx);
14688        });
14689
14690        let item = Box::new(editor);
14691        let item_id = item.item_id();
14692
14693        if split {
14694            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14695        } else {
14696            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14697                let (preview_item_id, preview_item_idx) =
14698                    workspace.active_pane().update(cx, |pane, _| {
14699                        (pane.preview_item_id(), pane.preview_item_idx())
14700                    });
14701
14702                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14703
14704                if let Some(preview_item_id) = preview_item_id {
14705                    workspace.active_pane().update(cx, |pane, cx| {
14706                        pane.remove_item(preview_item_id, false, false, window, cx);
14707                    });
14708                }
14709            } else {
14710                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14711            }
14712        }
14713        workspace.active_pane().update(cx, |pane, cx| {
14714            pane.set_preview_item_id(Some(item_id), cx);
14715        });
14716    }
14717
14718    pub fn rename(
14719        &mut self,
14720        _: &Rename,
14721        window: &mut Window,
14722        cx: &mut Context<Self>,
14723    ) -> Option<Task<Result<()>>> {
14724        use language::ToOffset as _;
14725
14726        let provider = self.semantics_provider.clone()?;
14727        let selection = self.selections.newest_anchor().clone();
14728        let (cursor_buffer, cursor_buffer_position) = self
14729            .buffer
14730            .read(cx)
14731            .text_anchor_for_position(selection.head(), cx)?;
14732        let (tail_buffer, cursor_buffer_position_end) = self
14733            .buffer
14734            .read(cx)
14735            .text_anchor_for_position(selection.tail(), cx)?;
14736        if tail_buffer != cursor_buffer {
14737            return None;
14738        }
14739
14740        let snapshot = cursor_buffer.read(cx).snapshot();
14741        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14742        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14743        let prepare_rename = provider
14744            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14745            .unwrap_or_else(|| Task::ready(Ok(None)));
14746        drop(snapshot);
14747
14748        Some(cx.spawn_in(window, async move |this, cx| {
14749            let rename_range = if let Some(range) = prepare_rename.await? {
14750                Some(range)
14751            } else {
14752                this.update(cx, |this, cx| {
14753                    let buffer = this.buffer.read(cx).snapshot(cx);
14754                    let mut buffer_highlights = this
14755                        .document_highlights_for_position(selection.head(), &buffer)
14756                        .filter(|highlight| {
14757                            highlight.start.excerpt_id == selection.head().excerpt_id
14758                                && highlight.end.excerpt_id == selection.head().excerpt_id
14759                        });
14760                    buffer_highlights
14761                        .next()
14762                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14763                })?
14764            };
14765            if let Some(rename_range) = rename_range {
14766                this.update_in(cx, |this, window, cx| {
14767                    let snapshot = cursor_buffer.read(cx).snapshot();
14768                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14769                    let cursor_offset_in_rename_range =
14770                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14771                    let cursor_offset_in_rename_range_end =
14772                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14773
14774                    this.take_rename(false, window, cx);
14775                    let buffer = this.buffer.read(cx).read(cx);
14776                    let cursor_offset = selection.head().to_offset(&buffer);
14777                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14778                    let rename_end = rename_start + rename_buffer_range.len();
14779                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14780                    let mut old_highlight_id = None;
14781                    let old_name: Arc<str> = buffer
14782                        .chunks(rename_start..rename_end, true)
14783                        .map(|chunk| {
14784                            if old_highlight_id.is_none() {
14785                                old_highlight_id = chunk.syntax_highlight_id;
14786                            }
14787                            chunk.text
14788                        })
14789                        .collect::<String>()
14790                        .into();
14791
14792                    drop(buffer);
14793
14794                    // Position the selection in the rename editor so that it matches the current selection.
14795                    this.show_local_selections = false;
14796                    let rename_editor = cx.new(|cx| {
14797                        let mut editor = Editor::single_line(window, cx);
14798                        editor.buffer.update(cx, |buffer, cx| {
14799                            buffer.edit([(0..0, old_name.clone())], None, cx)
14800                        });
14801                        let rename_selection_range = match cursor_offset_in_rename_range
14802                            .cmp(&cursor_offset_in_rename_range_end)
14803                        {
14804                            Ordering::Equal => {
14805                                editor.select_all(&SelectAll, window, cx);
14806                                return editor;
14807                            }
14808                            Ordering::Less => {
14809                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14810                            }
14811                            Ordering::Greater => {
14812                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14813                            }
14814                        };
14815                        if rename_selection_range.end > old_name.len() {
14816                            editor.select_all(&SelectAll, window, cx);
14817                        } else {
14818                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14819                                s.select_ranges([rename_selection_range]);
14820                            });
14821                        }
14822                        editor
14823                    });
14824                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14825                        if e == &EditorEvent::Focused {
14826                            cx.emit(EditorEvent::FocusedIn)
14827                        }
14828                    })
14829                    .detach();
14830
14831                    let write_highlights =
14832                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14833                    let read_highlights =
14834                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14835                    let ranges = write_highlights
14836                        .iter()
14837                        .flat_map(|(_, ranges)| ranges.iter())
14838                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14839                        .cloned()
14840                        .collect();
14841
14842                    this.highlight_text::<Rename>(
14843                        ranges,
14844                        HighlightStyle {
14845                            fade_out: Some(0.6),
14846                            ..Default::default()
14847                        },
14848                        cx,
14849                    );
14850                    let rename_focus_handle = rename_editor.focus_handle(cx);
14851                    window.focus(&rename_focus_handle);
14852                    let block_id = this.insert_blocks(
14853                        [BlockProperties {
14854                            style: BlockStyle::Flex,
14855                            placement: BlockPlacement::Below(range.start),
14856                            height: Some(1),
14857                            render: Arc::new({
14858                                let rename_editor = rename_editor.clone();
14859                                move |cx: &mut BlockContext| {
14860                                    let mut text_style = cx.editor_style.text.clone();
14861                                    if let Some(highlight_style) = old_highlight_id
14862                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14863                                    {
14864                                        text_style = text_style.highlight(highlight_style);
14865                                    }
14866                                    div()
14867                                        .block_mouse_down()
14868                                        .pl(cx.anchor_x)
14869                                        .child(EditorElement::new(
14870                                            &rename_editor,
14871                                            EditorStyle {
14872                                                background: cx.theme().system().transparent,
14873                                                local_player: cx.editor_style.local_player,
14874                                                text: text_style,
14875                                                scrollbar_width: cx.editor_style.scrollbar_width,
14876                                                syntax: cx.editor_style.syntax.clone(),
14877                                                status: cx.editor_style.status.clone(),
14878                                                inlay_hints_style: HighlightStyle {
14879                                                    font_weight: Some(FontWeight::BOLD),
14880                                                    ..make_inlay_hints_style(cx.app)
14881                                                },
14882                                                inline_completion_styles: make_suggestion_styles(
14883                                                    cx.app,
14884                                                ),
14885                                                ..EditorStyle::default()
14886                                            },
14887                                        ))
14888                                        .into_any_element()
14889                                }
14890                            }),
14891                            priority: 0,
14892                            render_in_minimap: true,
14893                        }],
14894                        Some(Autoscroll::fit()),
14895                        cx,
14896                    )[0];
14897                    this.pending_rename = Some(RenameState {
14898                        range,
14899                        old_name,
14900                        editor: rename_editor,
14901                        block_id,
14902                    });
14903                })?;
14904            }
14905
14906            Ok(())
14907        }))
14908    }
14909
14910    pub fn confirm_rename(
14911        &mut self,
14912        _: &ConfirmRename,
14913        window: &mut Window,
14914        cx: &mut Context<Self>,
14915    ) -> Option<Task<Result<()>>> {
14916        let rename = self.take_rename(false, window, cx)?;
14917        let workspace = self.workspace()?.downgrade();
14918        let (buffer, start) = self
14919            .buffer
14920            .read(cx)
14921            .text_anchor_for_position(rename.range.start, cx)?;
14922        let (end_buffer, _) = self
14923            .buffer
14924            .read(cx)
14925            .text_anchor_for_position(rename.range.end, cx)?;
14926        if buffer != end_buffer {
14927            return None;
14928        }
14929
14930        let old_name = rename.old_name;
14931        let new_name = rename.editor.read(cx).text(cx);
14932
14933        let rename = self.semantics_provider.as_ref()?.perform_rename(
14934            &buffer,
14935            start,
14936            new_name.clone(),
14937            cx,
14938        )?;
14939
14940        Some(cx.spawn_in(window, async move |editor, cx| {
14941            let project_transaction = rename.await?;
14942            Self::open_project_transaction(
14943                &editor,
14944                workspace,
14945                project_transaction,
14946                format!("Rename: {}{}", old_name, new_name),
14947                cx,
14948            )
14949            .await?;
14950
14951            editor.update(cx, |editor, cx| {
14952                editor.refresh_document_highlights(cx);
14953            })?;
14954            Ok(())
14955        }))
14956    }
14957
14958    fn take_rename(
14959        &mut self,
14960        moving_cursor: bool,
14961        window: &mut Window,
14962        cx: &mut Context<Self>,
14963    ) -> Option<RenameState> {
14964        let rename = self.pending_rename.take()?;
14965        if rename.editor.focus_handle(cx).is_focused(window) {
14966            window.focus(&self.focus_handle);
14967        }
14968
14969        self.remove_blocks(
14970            [rename.block_id].into_iter().collect(),
14971            Some(Autoscroll::fit()),
14972            cx,
14973        );
14974        self.clear_highlights::<Rename>(cx);
14975        self.show_local_selections = true;
14976
14977        if moving_cursor {
14978            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14979                editor.selections.newest::<usize>(cx).head()
14980            });
14981
14982            // Update the selection to match the position of the selection inside
14983            // the rename editor.
14984            let snapshot = self.buffer.read(cx).read(cx);
14985            let rename_range = rename.range.to_offset(&snapshot);
14986            let cursor_in_editor = snapshot
14987                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14988                .min(rename_range.end);
14989            drop(snapshot);
14990
14991            self.change_selections(None, window, cx, |s| {
14992                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14993            });
14994        } else {
14995            self.refresh_document_highlights(cx);
14996        }
14997
14998        Some(rename)
14999    }
15000
15001    pub fn pending_rename(&self) -> Option<&RenameState> {
15002        self.pending_rename.as_ref()
15003    }
15004
15005    fn format(
15006        &mut self,
15007        _: &Format,
15008        window: &mut Window,
15009        cx: &mut Context<Self>,
15010    ) -> Option<Task<Result<()>>> {
15011        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15012
15013        let project = match &self.project {
15014            Some(project) => project.clone(),
15015            None => return None,
15016        };
15017
15018        Some(self.perform_format(
15019            project,
15020            FormatTrigger::Manual,
15021            FormatTarget::Buffers,
15022            window,
15023            cx,
15024        ))
15025    }
15026
15027    fn format_selections(
15028        &mut self,
15029        _: &FormatSelections,
15030        window: &mut Window,
15031        cx: &mut Context<Self>,
15032    ) -> Option<Task<Result<()>>> {
15033        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15034
15035        let project = match &self.project {
15036            Some(project) => project.clone(),
15037            None => return None,
15038        };
15039
15040        let ranges = self
15041            .selections
15042            .all_adjusted(cx)
15043            .into_iter()
15044            .map(|selection| selection.range())
15045            .collect_vec();
15046
15047        Some(self.perform_format(
15048            project,
15049            FormatTrigger::Manual,
15050            FormatTarget::Ranges(ranges),
15051            window,
15052            cx,
15053        ))
15054    }
15055
15056    fn perform_format(
15057        &mut self,
15058        project: Entity<Project>,
15059        trigger: FormatTrigger,
15060        target: FormatTarget,
15061        window: &mut Window,
15062        cx: &mut Context<Self>,
15063    ) -> Task<Result<()>> {
15064        let buffer = self.buffer.clone();
15065        let (buffers, target) = match target {
15066            FormatTarget::Buffers => {
15067                let mut buffers = buffer.read(cx).all_buffers();
15068                if trigger == FormatTrigger::Save {
15069                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15070                }
15071                (buffers, LspFormatTarget::Buffers)
15072            }
15073            FormatTarget::Ranges(selection_ranges) => {
15074                let multi_buffer = buffer.read(cx);
15075                let snapshot = multi_buffer.read(cx);
15076                let mut buffers = HashSet::default();
15077                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15078                    BTreeMap::new();
15079                for selection_range in selection_ranges {
15080                    for (buffer, buffer_range, _) in
15081                        snapshot.range_to_buffer_ranges(selection_range)
15082                    {
15083                        let buffer_id = buffer.remote_id();
15084                        let start = buffer.anchor_before(buffer_range.start);
15085                        let end = buffer.anchor_after(buffer_range.end);
15086                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15087                        buffer_id_to_ranges
15088                            .entry(buffer_id)
15089                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15090                            .or_insert_with(|| vec![start..end]);
15091                    }
15092                }
15093                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15094            }
15095        };
15096
15097        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15098        let selections_prev = transaction_id_prev
15099            .and_then(|transaction_id_prev| {
15100                // default to selections as they were after the last edit, if we have them,
15101                // instead of how they are now.
15102                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15103                // will take you back to where you made the last edit, instead of staying where you scrolled
15104                self.selection_history
15105                    .transaction(transaction_id_prev)
15106                    .map(|t| t.0.clone())
15107            })
15108            .unwrap_or_else(|| {
15109                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15110                self.selections.disjoint_anchors()
15111            });
15112
15113        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15114        let format = project.update(cx, |project, cx| {
15115            project.format(buffers, target, true, trigger, cx)
15116        });
15117
15118        cx.spawn_in(window, async move |editor, cx| {
15119            let transaction = futures::select_biased! {
15120                transaction = format.log_err().fuse() => transaction,
15121                () = timeout => {
15122                    log::warn!("timed out waiting for formatting");
15123                    None
15124                }
15125            };
15126
15127            buffer
15128                .update(cx, |buffer, cx| {
15129                    if let Some(transaction) = transaction {
15130                        if !buffer.is_singleton() {
15131                            buffer.push_transaction(&transaction.0, cx);
15132                        }
15133                    }
15134                    cx.notify();
15135                })
15136                .ok();
15137
15138            if let Some(transaction_id_now) =
15139                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15140            {
15141                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15142                if has_new_transaction {
15143                    _ = editor.update(cx, |editor, _| {
15144                        editor
15145                            .selection_history
15146                            .insert_transaction(transaction_id_now, selections_prev);
15147                    });
15148                }
15149            }
15150
15151            Ok(())
15152        })
15153    }
15154
15155    fn organize_imports(
15156        &mut self,
15157        _: &OrganizeImports,
15158        window: &mut Window,
15159        cx: &mut Context<Self>,
15160    ) -> Option<Task<Result<()>>> {
15161        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15162        let project = match &self.project {
15163            Some(project) => project.clone(),
15164            None => return None,
15165        };
15166        Some(self.perform_code_action_kind(
15167            project,
15168            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15169            window,
15170            cx,
15171        ))
15172    }
15173
15174    fn perform_code_action_kind(
15175        &mut self,
15176        project: Entity<Project>,
15177        kind: CodeActionKind,
15178        window: &mut Window,
15179        cx: &mut Context<Self>,
15180    ) -> Task<Result<()>> {
15181        let buffer = self.buffer.clone();
15182        let buffers = buffer.read(cx).all_buffers();
15183        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15184        let apply_action = project.update(cx, |project, cx| {
15185            project.apply_code_action_kind(buffers, kind, true, cx)
15186        });
15187        cx.spawn_in(window, async move |_, cx| {
15188            let transaction = futures::select_biased! {
15189                () = timeout => {
15190                    log::warn!("timed out waiting for executing code action");
15191                    None
15192                }
15193                transaction = apply_action.log_err().fuse() => transaction,
15194            };
15195            buffer
15196                .update(cx, |buffer, cx| {
15197                    // check if we need this
15198                    if let Some(transaction) = transaction {
15199                        if !buffer.is_singleton() {
15200                            buffer.push_transaction(&transaction.0, cx);
15201                        }
15202                    }
15203                    cx.notify();
15204                })
15205                .ok();
15206            Ok(())
15207        })
15208    }
15209
15210    fn restart_language_server(
15211        &mut self,
15212        _: &RestartLanguageServer,
15213        _: &mut Window,
15214        cx: &mut Context<Self>,
15215    ) {
15216        if let Some(project) = self.project.clone() {
15217            self.buffer.update(cx, |multi_buffer, cx| {
15218                project.update(cx, |project, cx| {
15219                    project.restart_language_servers_for_buffers(
15220                        multi_buffer.all_buffers().into_iter().collect(),
15221                        cx,
15222                    );
15223                });
15224            })
15225        }
15226    }
15227
15228    fn stop_language_server(
15229        &mut self,
15230        _: &StopLanguageServer,
15231        _: &mut Window,
15232        cx: &mut Context<Self>,
15233    ) {
15234        if let Some(project) = self.project.clone() {
15235            self.buffer.update(cx, |multi_buffer, cx| {
15236                project.update(cx, |project, cx| {
15237                    project.stop_language_servers_for_buffers(
15238                        multi_buffer.all_buffers().into_iter().collect(),
15239                        cx,
15240                    );
15241                    cx.emit(project::Event::RefreshInlayHints);
15242                });
15243            });
15244        }
15245    }
15246
15247    fn cancel_language_server_work(
15248        workspace: &mut Workspace,
15249        _: &actions::CancelLanguageServerWork,
15250        _: &mut Window,
15251        cx: &mut Context<Workspace>,
15252    ) {
15253        let project = workspace.project();
15254        let buffers = workspace
15255            .active_item(cx)
15256            .and_then(|item| item.act_as::<Editor>(cx))
15257            .map_or(HashSet::default(), |editor| {
15258                editor.read(cx).buffer.read(cx).all_buffers()
15259            });
15260        project.update(cx, |project, cx| {
15261            project.cancel_language_server_work_for_buffers(buffers, cx);
15262        });
15263    }
15264
15265    fn show_character_palette(
15266        &mut self,
15267        _: &ShowCharacterPalette,
15268        window: &mut Window,
15269        _: &mut Context<Self>,
15270    ) {
15271        window.show_character_palette();
15272    }
15273
15274    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15275        if self.mode.is_minimap() {
15276            return;
15277        }
15278
15279        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15280            let buffer = self.buffer.read(cx).snapshot(cx);
15281            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15282            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15283            let is_valid = buffer
15284                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15285                .any(|entry| {
15286                    entry.diagnostic.is_primary
15287                        && !entry.range.is_empty()
15288                        && entry.range.start == primary_range_start
15289                        && entry.diagnostic.message == active_diagnostics.active_message
15290                });
15291
15292            if !is_valid {
15293                self.dismiss_diagnostics(cx);
15294            }
15295        }
15296    }
15297
15298    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15299        match &self.active_diagnostics {
15300            ActiveDiagnostic::Group(group) => Some(group),
15301            _ => None,
15302        }
15303    }
15304
15305    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15306        self.dismiss_diagnostics(cx);
15307        self.active_diagnostics = ActiveDiagnostic::All;
15308    }
15309
15310    fn activate_diagnostics(
15311        &mut self,
15312        buffer_id: BufferId,
15313        diagnostic: DiagnosticEntry<usize>,
15314        window: &mut Window,
15315        cx: &mut Context<Self>,
15316    ) {
15317        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15318            return;
15319        }
15320        self.dismiss_diagnostics(cx);
15321        let snapshot = self.snapshot(window, cx);
15322        let buffer = self.buffer.read(cx).snapshot(cx);
15323        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15324            return;
15325        };
15326
15327        let diagnostic_group = buffer
15328            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15329            .collect::<Vec<_>>();
15330
15331        let blocks =
15332            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15333
15334        let blocks = self.display_map.update(cx, |display_map, cx| {
15335            display_map.insert_blocks(blocks, cx).into_iter().collect()
15336        });
15337        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15338            active_range: buffer.anchor_before(diagnostic.range.start)
15339                ..buffer.anchor_after(diagnostic.range.end),
15340            active_message: diagnostic.diagnostic.message.clone(),
15341            group_id: diagnostic.diagnostic.group_id,
15342            blocks,
15343        });
15344        cx.notify();
15345    }
15346
15347    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15348        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15349            return;
15350        };
15351
15352        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15353        if let ActiveDiagnostic::Group(group) = prev {
15354            self.display_map.update(cx, |display_map, cx| {
15355                display_map.remove_blocks(group.blocks, cx);
15356            });
15357            cx.notify();
15358        }
15359    }
15360
15361    /// Disable inline diagnostics rendering for this editor.
15362    pub fn disable_inline_diagnostics(&mut self) {
15363        self.inline_diagnostics_enabled = false;
15364        self.inline_diagnostics_update = Task::ready(());
15365        self.inline_diagnostics.clear();
15366    }
15367
15368    pub fn diagnostics_enabled(&self) -> bool {
15369        self.mode.is_full()
15370    }
15371
15372    pub fn inline_diagnostics_enabled(&self) -> bool {
15373        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15374    }
15375
15376    pub fn show_inline_diagnostics(&self) -> bool {
15377        self.show_inline_diagnostics
15378    }
15379
15380    pub fn toggle_inline_diagnostics(
15381        &mut self,
15382        _: &ToggleInlineDiagnostics,
15383        window: &mut Window,
15384        cx: &mut Context<Editor>,
15385    ) {
15386        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15387        self.refresh_inline_diagnostics(false, window, cx);
15388    }
15389
15390    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15391        self.diagnostics_max_severity = severity;
15392        self.display_map.update(cx, |display_map, _| {
15393            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15394        });
15395    }
15396
15397    pub fn toggle_diagnostics(
15398        &mut self,
15399        _: &ToggleDiagnostics,
15400        window: &mut Window,
15401        cx: &mut Context<Editor>,
15402    ) {
15403        if !self.diagnostics_enabled() {
15404            return;
15405        }
15406
15407        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15408            EditorSettings::get_global(cx)
15409                .diagnostics_max_severity
15410                .filter(|severity| severity != &DiagnosticSeverity::Off)
15411                .unwrap_or(DiagnosticSeverity::Hint)
15412        } else {
15413            DiagnosticSeverity::Off
15414        };
15415        self.set_max_diagnostics_severity(new_severity, cx);
15416        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15417            self.active_diagnostics = ActiveDiagnostic::None;
15418            self.inline_diagnostics_update = Task::ready(());
15419            self.inline_diagnostics.clear();
15420        } else {
15421            self.refresh_inline_diagnostics(false, window, cx);
15422        }
15423
15424        cx.notify();
15425    }
15426
15427    pub fn toggle_minimap(
15428        &mut self,
15429        _: &ToggleMinimap,
15430        window: &mut Window,
15431        cx: &mut Context<Editor>,
15432    ) {
15433        if self.supports_minimap(cx) {
15434            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15435        }
15436    }
15437
15438    fn refresh_inline_diagnostics(
15439        &mut self,
15440        debounce: bool,
15441        window: &mut Window,
15442        cx: &mut Context<Self>,
15443    ) {
15444        let max_severity = ProjectSettings::get_global(cx)
15445            .diagnostics
15446            .inline
15447            .max_severity
15448            .unwrap_or(self.diagnostics_max_severity);
15449
15450        if self.mode.is_minimap()
15451            || !self.inline_diagnostics_enabled()
15452            || !self.show_inline_diagnostics
15453            || max_severity == DiagnosticSeverity::Off
15454        {
15455            self.inline_diagnostics_update = Task::ready(());
15456            self.inline_diagnostics.clear();
15457            return;
15458        }
15459
15460        let debounce_ms = ProjectSettings::get_global(cx)
15461            .diagnostics
15462            .inline
15463            .update_debounce_ms;
15464        let debounce = if debounce && debounce_ms > 0 {
15465            Some(Duration::from_millis(debounce_ms))
15466        } else {
15467            None
15468        };
15469        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15470            let editor = editor.upgrade().unwrap();
15471
15472            if let Some(debounce) = debounce {
15473                cx.background_executor().timer(debounce).await;
15474            }
15475            let Some(snapshot) = editor
15476                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15477                .ok()
15478            else {
15479                return;
15480            };
15481
15482            let new_inline_diagnostics = cx
15483                .background_spawn(async move {
15484                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15485                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15486                        let message = diagnostic_entry
15487                            .diagnostic
15488                            .message
15489                            .split_once('\n')
15490                            .map(|(line, _)| line)
15491                            .map(SharedString::new)
15492                            .unwrap_or_else(|| {
15493                                SharedString::from(diagnostic_entry.diagnostic.message)
15494                            });
15495                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15496                        let (Ok(i) | Err(i)) = inline_diagnostics
15497                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15498                        inline_diagnostics.insert(
15499                            i,
15500                            (
15501                                start_anchor,
15502                                InlineDiagnostic {
15503                                    message,
15504                                    group_id: diagnostic_entry.diagnostic.group_id,
15505                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15506                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15507                                    severity: diagnostic_entry.diagnostic.severity,
15508                                },
15509                            ),
15510                        );
15511                    }
15512                    inline_diagnostics
15513                })
15514                .await;
15515
15516            editor
15517                .update(cx, |editor, cx| {
15518                    editor.inline_diagnostics = new_inline_diagnostics;
15519                    cx.notify();
15520                })
15521                .ok();
15522        });
15523    }
15524
15525    pub fn set_selections_from_remote(
15526        &mut self,
15527        selections: Vec<Selection<Anchor>>,
15528        pending_selection: Option<Selection<Anchor>>,
15529        window: &mut Window,
15530        cx: &mut Context<Self>,
15531    ) {
15532        let old_cursor_position = self.selections.newest_anchor().head();
15533        self.selections.change_with(cx, |s| {
15534            s.select_anchors(selections);
15535            if let Some(pending_selection) = pending_selection {
15536                s.set_pending(pending_selection, SelectMode::Character);
15537            } else {
15538                s.clear_pending();
15539            }
15540        });
15541        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15542    }
15543
15544    fn push_to_selection_history(&mut self) {
15545        self.selection_history.push(SelectionHistoryEntry {
15546            selections: self.selections.disjoint_anchors(),
15547            select_next_state: self.select_next_state.clone(),
15548            select_prev_state: self.select_prev_state.clone(),
15549            add_selections_state: self.add_selections_state.clone(),
15550        });
15551    }
15552
15553    pub fn transact(
15554        &mut self,
15555        window: &mut Window,
15556        cx: &mut Context<Self>,
15557        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15558    ) -> Option<TransactionId> {
15559        self.start_transaction_at(Instant::now(), window, cx);
15560        update(self, window, cx);
15561        self.end_transaction_at(Instant::now(), cx)
15562    }
15563
15564    pub fn start_transaction_at(
15565        &mut self,
15566        now: Instant,
15567        window: &mut Window,
15568        cx: &mut Context<Self>,
15569    ) {
15570        self.end_selection(window, cx);
15571        if let Some(tx_id) = self
15572            .buffer
15573            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15574        {
15575            self.selection_history
15576                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15577            cx.emit(EditorEvent::TransactionBegun {
15578                transaction_id: tx_id,
15579            })
15580        }
15581    }
15582
15583    pub fn end_transaction_at(
15584        &mut self,
15585        now: Instant,
15586        cx: &mut Context<Self>,
15587    ) -> Option<TransactionId> {
15588        if let Some(transaction_id) = self
15589            .buffer
15590            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15591        {
15592            if let Some((_, end_selections)) =
15593                self.selection_history.transaction_mut(transaction_id)
15594            {
15595                *end_selections = Some(self.selections.disjoint_anchors());
15596            } else {
15597                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15598            }
15599
15600            cx.emit(EditorEvent::Edited { transaction_id });
15601            Some(transaction_id)
15602        } else {
15603            None
15604        }
15605    }
15606
15607    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15608        if self.selection_mark_mode {
15609            self.change_selections(None, window, cx, |s| {
15610                s.move_with(|_, sel| {
15611                    sel.collapse_to(sel.head(), SelectionGoal::None);
15612                });
15613            })
15614        }
15615        self.selection_mark_mode = true;
15616        cx.notify();
15617    }
15618
15619    pub fn swap_selection_ends(
15620        &mut self,
15621        _: &actions::SwapSelectionEnds,
15622        window: &mut Window,
15623        cx: &mut Context<Self>,
15624    ) {
15625        self.change_selections(None, window, cx, |s| {
15626            s.move_with(|_, sel| {
15627                if sel.start != sel.end {
15628                    sel.reversed = !sel.reversed
15629                }
15630            });
15631        });
15632        self.request_autoscroll(Autoscroll::newest(), cx);
15633        cx.notify();
15634    }
15635
15636    pub fn toggle_fold(
15637        &mut self,
15638        _: &actions::ToggleFold,
15639        window: &mut Window,
15640        cx: &mut Context<Self>,
15641    ) {
15642        if self.is_singleton(cx) {
15643            let selection = self.selections.newest::<Point>(cx);
15644
15645            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15646            let range = if selection.is_empty() {
15647                let point = selection.head().to_display_point(&display_map);
15648                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15649                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15650                    .to_point(&display_map);
15651                start..end
15652            } else {
15653                selection.range()
15654            };
15655            if display_map.folds_in_range(range).next().is_some() {
15656                self.unfold_lines(&Default::default(), window, cx)
15657            } else {
15658                self.fold(&Default::default(), window, cx)
15659            }
15660        } else {
15661            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15662            let buffer_ids: HashSet<_> = self
15663                .selections
15664                .disjoint_anchor_ranges()
15665                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15666                .collect();
15667
15668            let should_unfold = buffer_ids
15669                .iter()
15670                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15671
15672            for buffer_id in buffer_ids {
15673                if should_unfold {
15674                    self.unfold_buffer(buffer_id, cx);
15675                } else {
15676                    self.fold_buffer(buffer_id, cx);
15677                }
15678            }
15679        }
15680    }
15681
15682    pub fn toggle_fold_recursive(
15683        &mut self,
15684        _: &actions::ToggleFoldRecursive,
15685        window: &mut Window,
15686        cx: &mut Context<Self>,
15687    ) {
15688        let selection = self.selections.newest::<Point>(cx);
15689
15690        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15691        let range = if selection.is_empty() {
15692            let point = selection.head().to_display_point(&display_map);
15693            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15694            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15695                .to_point(&display_map);
15696            start..end
15697        } else {
15698            selection.range()
15699        };
15700        if display_map.folds_in_range(range).next().is_some() {
15701            self.unfold_recursive(&Default::default(), window, cx)
15702        } else {
15703            self.fold_recursive(&Default::default(), window, cx)
15704        }
15705    }
15706
15707    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15708        if self.is_singleton(cx) {
15709            let mut to_fold = Vec::new();
15710            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15711            let selections = self.selections.all_adjusted(cx);
15712
15713            for selection in selections {
15714                let range = selection.range().sorted();
15715                let buffer_start_row = range.start.row;
15716
15717                if range.start.row != range.end.row {
15718                    let mut found = false;
15719                    let mut row = range.start.row;
15720                    while row <= range.end.row {
15721                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15722                        {
15723                            found = true;
15724                            row = crease.range().end.row + 1;
15725                            to_fold.push(crease);
15726                        } else {
15727                            row += 1
15728                        }
15729                    }
15730                    if found {
15731                        continue;
15732                    }
15733                }
15734
15735                for row in (0..=range.start.row).rev() {
15736                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15737                        if crease.range().end.row >= buffer_start_row {
15738                            to_fold.push(crease);
15739                            if row <= range.start.row {
15740                                break;
15741                            }
15742                        }
15743                    }
15744                }
15745            }
15746
15747            self.fold_creases(to_fold, true, window, cx);
15748        } else {
15749            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15750            let buffer_ids = self
15751                .selections
15752                .disjoint_anchor_ranges()
15753                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15754                .collect::<HashSet<_>>();
15755            for buffer_id in buffer_ids {
15756                self.fold_buffer(buffer_id, cx);
15757            }
15758        }
15759    }
15760
15761    fn fold_at_level(
15762        &mut self,
15763        fold_at: &FoldAtLevel,
15764        window: &mut Window,
15765        cx: &mut Context<Self>,
15766    ) {
15767        if !self.buffer.read(cx).is_singleton() {
15768            return;
15769        }
15770
15771        let fold_at_level = fold_at.0;
15772        let snapshot = self.buffer.read(cx).snapshot(cx);
15773        let mut to_fold = Vec::new();
15774        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15775
15776        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15777            while start_row < end_row {
15778                match self
15779                    .snapshot(window, cx)
15780                    .crease_for_buffer_row(MultiBufferRow(start_row))
15781                {
15782                    Some(crease) => {
15783                        let nested_start_row = crease.range().start.row + 1;
15784                        let nested_end_row = crease.range().end.row;
15785
15786                        if current_level < fold_at_level {
15787                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15788                        } else if current_level == fold_at_level {
15789                            to_fold.push(crease);
15790                        }
15791
15792                        start_row = nested_end_row + 1;
15793                    }
15794                    None => start_row += 1,
15795                }
15796            }
15797        }
15798
15799        self.fold_creases(to_fold, true, window, cx);
15800    }
15801
15802    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15803        if self.buffer.read(cx).is_singleton() {
15804            let mut fold_ranges = Vec::new();
15805            let snapshot = self.buffer.read(cx).snapshot(cx);
15806
15807            for row in 0..snapshot.max_row().0 {
15808                if let Some(foldable_range) = self
15809                    .snapshot(window, cx)
15810                    .crease_for_buffer_row(MultiBufferRow(row))
15811                {
15812                    fold_ranges.push(foldable_range);
15813                }
15814            }
15815
15816            self.fold_creases(fold_ranges, true, window, cx);
15817        } else {
15818            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15819                editor
15820                    .update_in(cx, |editor, _, cx| {
15821                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15822                            editor.fold_buffer(buffer_id, cx);
15823                        }
15824                    })
15825                    .ok();
15826            });
15827        }
15828    }
15829
15830    pub fn fold_function_bodies(
15831        &mut self,
15832        _: &actions::FoldFunctionBodies,
15833        window: &mut Window,
15834        cx: &mut Context<Self>,
15835    ) {
15836        let snapshot = self.buffer.read(cx).snapshot(cx);
15837
15838        let ranges = snapshot
15839            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15840            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15841            .collect::<Vec<_>>();
15842
15843        let creases = ranges
15844            .into_iter()
15845            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15846            .collect();
15847
15848        self.fold_creases(creases, true, window, cx);
15849    }
15850
15851    pub fn fold_recursive(
15852        &mut self,
15853        _: &actions::FoldRecursive,
15854        window: &mut Window,
15855        cx: &mut Context<Self>,
15856    ) {
15857        let mut to_fold = Vec::new();
15858        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15859        let selections = self.selections.all_adjusted(cx);
15860
15861        for selection in selections {
15862            let range = selection.range().sorted();
15863            let buffer_start_row = range.start.row;
15864
15865            if range.start.row != range.end.row {
15866                let mut found = false;
15867                for row in range.start.row..=range.end.row {
15868                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15869                        found = true;
15870                        to_fold.push(crease);
15871                    }
15872                }
15873                if found {
15874                    continue;
15875                }
15876            }
15877
15878            for row in (0..=range.start.row).rev() {
15879                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15880                    if crease.range().end.row >= buffer_start_row {
15881                        to_fold.push(crease);
15882                    } else {
15883                        break;
15884                    }
15885                }
15886            }
15887        }
15888
15889        self.fold_creases(to_fold, true, window, cx);
15890    }
15891
15892    pub fn fold_at(
15893        &mut self,
15894        buffer_row: MultiBufferRow,
15895        window: &mut Window,
15896        cx: &mut Context<Self>,
15897    ) {
15898        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15899
15900        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15901            let autoscroll = self
15902                .selections
15903                .all::<Point>(cx)
15904                .iter()
15905                .any(|selection| crease.range().overlaps(&selection.range()));
15906
15907            self.fold_creases(vec![crease], autoscroll, window, cx);
15908        }
15909    }
15910
15911    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15912        if self.is_singleton(cx) {
15913            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15914            let buffer = &display_map.buffer_snapshot;
15915            let selections = self.selections.all::<Point>(cx);
15916            let ranges = selections
15917                .iter()
15918                .map(|s| {
15919                    let range = s.display_range(&display_map).sorted();
15920                    let mut start = range.start.to_point(&display_map);
15921                    let mut end = range.end.to_point(&display_map);
15922                    start.column = 0;
15923                    end.column = buffer.line_len(MultiBufferRow(end.row));
15924                    start..end
15925                })
15926                .collect::<Vec<_>>();
15927
15928            self.unfold_ranges(&ranges, true, true, cx);
15929        } else {
15930            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15931            let buffer_ids = self
15932                .selections
15933                .disjoint_anchor_ranges()
15934                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15935                .collect::<HashSet<_>>();
15936            for buffer_id in buffer_ids {
15937                self.unfold_buffer(buffer_id, cx);
15938            }
15939        }
15940    }
15941
15942    pub fn unfold_recursive(
15943        &mut self,
15944        _: &UnfoldRecursive,
15945        _window: &mut Window,
15946        cx: &mut Context<Self>,
15947    ) {
15948        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15949        let selections = self.selections.all::<Point>(cx);
15950        let ranges = selections
15951            .iter()
15952            .map(|s| {
15953                let mut range = s.display_range(&display_map).sorted();
15954                *range.start.column_mut() = 0;
15955                *range.end.column_mut() = display_map.line_len(range.end.row());
15956                let start = range.start.to_point(&display_map);
15957                let end = range.end.to_point(&display_map);
15958                start..end
15959            })
15960            .collect::<Vec<_>>();
15961
15962        self.unfold_ranges(&ranges, true, true, cx);
15963    }
15964
15965    pub fn unfold_at(
15966        &mut self,
15967        buffer_row: MultiBufferRow,
15968        _window: &mut Window,
15969        cx: &mut Context<Self>,
15970    ) {
15971        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15972
15973        let intersection_range = Point::new(buffer_row.0, 0)
15974            ..Point::new(
15975                buffer_row.0,
15976                display_map.buffer_snapshot.line_len(buffer_row),
15977            );
15978
15979        let autoscroll = self
15980            .selections
15981            .all::<Point>(cx)
15982            .iter()
15983            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15984
15985        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15986    }
15987
15988    pub fn unfold_all(
15989        &mut self,
15990        _: &actions::UnfoldAll,
15991        _window: &mut Window,
15992        cx: &mut Context<Self>,
15993    ) {
15994        if self.buffer.read(cx).is_singleton() {
15995            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15996            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15997        } else {
15998            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15999                editor
16000                    .update(cx, |editor, cx| {
16001                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16002                            editor.unfold_buffer(buffer_id, cx);
16003                        }
16004                    })
16005                    .ok();
16006            });
16007        }
16008    }
16009
16010    pub fn fold_selected_ranges(
16011        &mut self,
16012        _: &FoldSelectedRanges,
16013        window: &mut Window,
16014        cx: &mut Context<Self>,
16015    ) {
16016        let selections = self.selections.all_adjusted(cx);
16017        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16018        let ranges = selections
16019            .into_iter()
16020            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16021            .collect::<Vec<_>>();
16022        self.fold_creases(ranges, true, window, cx);
16023    }
16024
16025    pub fn fold_ranges<T: ToOffset + Clone>(
16026        &mut self,
16027        ranges: Vec<Range<T>>,
16028        auto_scroll: bool,
16029        window: &mut Window,
16030        cx: &mut Context<Self>,
16031    ) {
16032        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16033        let ranges = ranges
16034            .into_iter()
16035            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16036            .collect::<Vec<_>>();
16037        self.fold_creases(ranges, auto_scroll, window, cx);
16038    }
16039
16040    pub fn fold_creases<T: ToOffset + Clone>(
16041        &mut self,
16042        creases: Vec<Crease<T>>,
16043        auto_scroll: bool,
16044        _window: &mut Window,
16045        cx: &mut Context<Self>,
16046    ) {
16047        if creases.is_empty() {
16048            return;
16049        }
16050
16051        let mut buffers_affected = HashSet::default();
16052        let multi_buffer = self.buffer().read(cx);
16053        for crease in &creases {
16054            if let Some((_, buffer, _)) =
16055                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16056            {
16057                buffers_affected.insert(buffer.read(cx).remote_id());
16058            };
16059        }
16060
16061        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16062
16063        if auto_scroll {
16064            self.request_autoscroll(Autoscroll::fit(), cx);
16065        }
16066
16067        cx.notify();
16068
16069        self.scrollbar_marker_state.dirty = true;
16070        self.folds_did_change(cx);
16071    }
16072
16073    /// Removes any folds whose ranges intersect any of the given ranges.
16074    pub fn unfold_ranges<T: ToOffset + Clone>(
16075        &mut self,
16076        ranges: &[Range<T>],
16077        inclusive: bool,
16078        auto_scroll: bool,
16079        cx: &mut Context<Self>,
16080    ) {
16081        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16082            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16083        });
16084        self.folds_did_change(cx);
16085    }
16086
16087    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16088        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16089            return;
16090        }
16091        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16092        self.display_map.update(cx, |display_map, cx| {
16093            display_map.fold_buffers([buffer_id], cx)
16094        });
16095        cx.emit(EditorEvent::BufferFoldToggled {
16096            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16097            folded: true,
16098        });
16099        cx.notify();
16100    }
16101
16102    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16103        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16104            return;
16105        }
16106        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16107        self.display_map.update(cx, |display_map, cx| {
16108            display_map.unfold_buffers([buffer_id], cx);
16109        });
16110        cx.emit(EditorEvent::BufferFoldToggled {
16111            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16112            folded: false,
16113        });
16114        cx.notify();
16115    }
16116
16117    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16118        self.display_map.read(cx).is_buffer_folded(buffer)
16119    }
16120
16121    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16122        self.display_map.read(cx).folded_buffers()
16123    }
16124
16125    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16126        self.display_map.update(cx, |display_map, cx| {
16127            display_map.disable_header_for_buffer(buffer_id, cx);
16128        });
16129        cx.notify();
16130    }
16131
16132    /// Removes any folds with the given ranges.
16133    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16134        &mut self,
16135        ranges: &[Range<T>],
16136        type_id: TypeId,
16137        auto_scroll: bool,
16138        cx: &mut Context<Self>,
16139    ) {
16140        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16141            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16142        });
16143        self.folds_did_change(cx);
16144    }
16145
16146    fn remove_folds_with<T: ToOffset + Clone>(
16147        &mut self,
16148        ranges: &[Range<T>],
16149        auto_scroll: bool,
16150        cx: &mut Context<Self>,
16151        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16152    ) {
16153        if ranges.is_empty() {
16154            return;
16155        }
16156
16157        let mut buffers_affected = HashSet::default();
16158        let multi_buffer = self.buffer().read(cx);
16159        for range in ranges {
16160            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16161                buffers_affected.insert(buffer.read(cx).remote_id());
16162            };
16163        }
16164
16165        self.display_map.update(cx, update);
16166
16167        if auto_scroll {
16168            self.request_autoscroll(Autoscroll::fit(), cx);
16169        }
16170
16171        cx.notify();
16172        self.scrollbar_marker_state.dirty = true;
16173        self.active_indent_guides_state.dirty = true;
16174    }
16175
16176    pub fn update_fold_widths(
16177        &mut self,
16178        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16179        cx: &mut Context<Self>,
16180    ) -> bool {
16181        self.display_map
16182            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16183    }
16184
16185    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16186        self.display_map.read(cx).fold_placeholder.clone()
16187    }
16188
16189    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16190        self.buffer.update(cx, |buffer, cx| {
16191            buffer.set_all_diff_hunks_expanded(cx);
16192        });
16193    }
16194
16195    pub fn expand_all_diff_hunks(
16196        &mut self,
16197        _: &ExpandAllDiffHunks,
16198        _window: &mut Window,
16199        cx: &mut Context<Self>,
16200    ) {
16201        self.buffer.update(cx, |buffer, cx| {
16202            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16203        });
16204    }
16205
16206    pub fn toggle_selected_diff_hunks(
16207        &mut self,
16208        _: &ToggleSelectedDiffHunks,
16209        _window: &mut Window,
16210        cx: &mut Context<Self>,
16211    ) {
16212        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16213        self.toggle_diff_hunks_in_ranges(ranges, cx);
16214    }
16215
16216    pub fn diff_hunks_in_ranges<'a>(
16217        &'a self,
16218        ranges: &'a [Range<Anchor>],
16219        buffer: &'a MultiBufferSnapshot,
16220    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16221        ranges.iter().flat_map(move |range| {
16222            let end_excerpt_id = range.end.excerpt_id;
16223            let range = range.to_point(buffer);
16224            let mut peek_end = range.end;
16225            if range.end.row < buffer.max_row().0 {
16226                peek_end = Point::new(range.end.row + 1, 0);
16227            }
16228            buffer
16229                .diff_hunks_in_range(range.start..peek_end)
16230                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16231        })
16232    }
16233
16234    pub fn has_stageable_diff_hunks_in_ranges(
16235        &self,
16236        ranges: &[Range<Anchor>],
16237        snapshot: &MultiBufferSnapshot,
16238    ) -> bool {
16239        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16240        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16241    }
16242
16243    pub fn toggle_staged_selected_diff_hunks(
16244        &mut self,
16245        _: &::git::ToggleStaged,
16246        _: &mut Window,
16247        cx: &mut Context<Self>,
16248    ) {
16249        let snapshot = self.buffer.read(cx).snapshot(cx);
16250        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16251        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16252        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16253    }
16254
16255    pub fn set_render_diff_hunk_controls(
16256        &mut self,
16257        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16258        cx: &mut Context<Self>,
16259    ) {
16260        self.render_diff_hunk_controls = render_diff_hunk_controls;
16261        cx.notify();
16262    }
16263
16264    pub fn stage_and_next(
16265        &mut self,
16266        _: &::git::StageAndNext,
16267        window: &mut Window,
16268        cx: &mut Context<Self>,
16269    ) {
16270        self.do_stage_or_unstage_and_next(true, window, cx);
16271    }
16272
16273    pub fn unstage_and_next(
16274        &mut self,
16275        _: &::git::UnstageAndNext,
16276        window: &mut Window,
16277        cx: &mut Context<Self>,
16278    ) {
16279        self.do_stage_or_unstage_and_next(false, window, cx);
16280    }
16281
16282    pub fn stage_or_unstage_diff_hunks(
16283        &mut self,
16284        stage: bool,
16285        ranges: Vec<Range<Anchor>>,
16286        cx: &mut Context<Self>,
16287    ) {
16288        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16289        cx.spawn(async move |this, cx| {
16290            task.await?;
16291            this.update(cx, |this, cx| {
16292                let snapshot = this.buffer.read(cx).snapshot(cx);
16293                let chunk_by = this
16294                    .diff_hunks_in_ranges(&ranges, &snapshot)
16295                    .chunk_by(|hunk| hunk.buffer_id);
16296                for (buffer_id, hunks) in &chunk_by {
16297                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16298                }
16299            })
16300        })
16301        .detach_and_log_err(cx);
16302    }
16303
16304    fn save_buffers_for_ranges_if_needed(
16305        &mut self,
16306        ranges: &[Range<Anchor>],
16307        cx: &mut Context<Editor>,
16308    ) -> Task<Result<()>> {
16309        let multibuffer = self.buffer.read(cx);
16310        let snapshot = multibuffer.read(cx);
16311        let buffer_ids: HashSet<_> = ranges
16312            .iter()
16313            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16314            .collect();
16315        drop(snapshot);
16316
16317        let mut buffers = HashSet::default();
16318        for buffer_id in buffer_ids {
16319            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16320                let buffer = buffer_entity.read(cx);
16321                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16322                {
16323                    buffers.insert(buffer_entity);
16324                }
16325            }
16326        }
16327
16328        if let Some(project) = &self.project {
16329            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16330        } else {
16331            Task::ready(Ok(()))
16332        }
16333    }
16334
16335    fn do_stage_or_unstage_and_next(
16336        &mut self,
16337        stage: bool,
16338        window: &mut Window,
16339        cx: &mut Context<Self>,
16340    ) {
16341        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16342
16343        if ranges.iter().any(|range| range.start != range.end) {
16344            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16345            return;
16346        }
16347
16348        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16349        let snapshot = self.snapshot(window, cx);
16350        let position = self.selections.newest::<Point>(cx).head();
16351        let mut row = snapshot
16352            .buffer_snapshot
16353            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16354            .find(|hunk| hunk.row_range.start.0 > position.row)
16355            .map(|hunk| hunk.row_range.start);
16356
16357        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16358        // Outside of the project diff editor, wrap around to the beginning.
16359        if !all_diff_hunks_expanded {
16360            row = row.or_else(|| {
16361                snapshot
16362                    .buffer_snapshot
16363                    .diff_hunks_in_range(Point::zero()..position)
16364                    .find(|hunk| hunk.row_range.end.0 < position.row)
16365                    .map(|hunk| hunk.row_range.start)
16366            });
16367        }
16368
16369        if let Some(row) = row {
16370            let destination = Point::new(row.0, 0);
16371            let autoscroll = Autoscroll::center();
16372
16373            self.unfold_ranges(&[destination..destination], false, false, cx);
16374            self.change_selections(Some(autoscroll), window, cx, |s| {
16375                s.select_ranges([destination..destination]);
16376            });
16377        }
16378    }
16379
16380    fn do_stage_or_unstage(
16381        &self,
16382        stage: bool,
16383        buffer_id: BufferId,
16384        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16385        cx: &mut App,
16386    ) -> Option<()> {
16387        let project = self.project.as_ref()?;
16388        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16389        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16390        let buffer_snapshot = buffer.read(cx).snapshot();
16391        let file_exists = buffer_snapshot
16392            .file()
16393            .is_some_and(|file| file.disk_state().exists());
16394        diff.update(cx, |diff, cx| {
16395            diff.stage_or_unstage_hunks(
16396                stage,
16397                &hunks
16398                    .map(|hunk| buffer_diff::DiffHunk {
16399                        buffer_range: hunk.buffer_range,
16400                        diff_base_byte_range: hunk.diff_base_byte_range,
16401                        secondary_status: hunk.secondary_status,
16402                        range: Point::zero()..Point::zero(), // unused
16403                    })
16404                    .collect::<Vec<_>>(),
16405                &buffer_snapshot,
16406                file_exists,
16407                cx,
16408            )
16409        });
16410        None
16411    }
16412
16413    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16414        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16415        self.buffer
16416            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16417    }
16418
16419    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16420        self.buffer.update(cx, |buffer, cx| {
16421            let ranges = vec![Anchor::min()..Anchor::max()];
16422            if !buffer.all_diff_hunks_expanded()
16423                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16424            {
16425                buffer.collapse_diff_hunks(ranges, cx);
16426                true
16427            } else {
16428                false
16429            }
16430        })
16431    }
16432
16433    fn toggle_diff_hunks_in_ranges(
16434        &mut self,
16435        ranges: Vec<Range<Anchor>>,
16436        cx: &mut Context<Editor>,
16437    ) {
16438        self.buffer.update(cx, |buffer, cx| {
16439            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16440            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16441        })
16442    }
16443
16444    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16445        self.buffer.update(cx, |buffer, cx| {
16446            let snapshot = buffer.snapshot(cx);
16447            let excerpt_id = range.end.excerpt_id;
16448            let point_range = range.to_point(&snapshot);
16449            let expand = !buffer.single_hunk_is_expanded(range, cx);
16450            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16451        })
16452    }
16453
16454    pub(crate) fn apply_all_diff_hunks(
16455        &mut self,
16456        _: &ApplyAllDiffHunks,
16457        window: &mut Window,
16458        cx: &mut Context<Self>,
16459    ) {
16460        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16461
16462        let buffers = self.buffer.read(cx).all_buffers();
16463        for branch_buffer in buffers {
16464            branch_buffer.update(cx, |branch_buffer, cx| {
16465                branch_buffer.merge_into_base(Vec::new(), cx);
16466            });
16467        }
16468
16469        if let Some(project) = self.project.clone() {
16470            self.save(true, project, window, cx).detach_and_log_err(cx);
16471        }
16472    }
16473
16474    pub(crate) fn apply_selected_diff_hunks(
16475        &mut self,
16476        _: &ApplyDiffHunk,
16477        window: &mut Window,
16478        cx: &mut Context<Self>,
16479    ) {
16480        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16481        let snapshot = self.snapshot(window, cx);
16482        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16483        let mut ranges_by_buffer = HashMap::default();
16484        self.transact(window, cx, |editor, _window, cx| {
16485            for hunk in hunks {
16486                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16487                    ranges_by_buffer
16488                        .entry(buffer.clone())
16489                        .or_insert_with(Vec::new)
16490                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16491                }
16492            }
16493
16494            for (buffer, ranges) in ranges_by_buffer {
16495                buffer.update(cx, |buffer, cx| {
16496                    buffer.merge_into_base(ranges, cx);
16497                });
16498            }
16499        });
16500
16501        if let Some(project) = self.project.clone() {
16502            self.save(true, project, window, cx).detach_and_log_err(cx);
16503        }
16504    }
16505
16506    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16507        if hovered != self.gutter_hovered {
16508            self.gutter_hovered = hovered;
16509            cx.notify();
16510        }
16511    }
16512
16513    pub fn insert_blocks(
16514        &mut self,
16515        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16516        autoscroll: Option<Autoscroll>,
16517        cx: &mut Context<Self>,
16518    ) -> Vec<CustomBlockId> {
16519        let blocks = self
16520            .display_map
16521            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16522        if let Some(autoscroll) = autoscroll {
16523            self.request_autoscroll(autoscroll, cx);
16524        }
16525        cx.notify();
16526        blocks
16527    }
16528
16529    pub fn resize_blocks(
16530        &mut self,
16531        heights: HashMap<CustomBlockId, u32>,
16532        autoscroll: Option<Autoscroll>,
16533        cx: &mut Context<Self>,
16534    ) {
16535        self.display_map
16536            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16537        if let Some(autoscroll) = autoscroll {
16538            self.request_autoscroll(autoscroll, cx);
16539        }
16540        cx.notify();
16541    }
16542
16543    pub fn replace_blocks(
16544        &mut self,
16545        renderers: HashMap<CustomBlockId, RenderBlock>,
16546        autoscroll: Option<Autoscroll>,
16547        cx: &mut Context<Self>,
16548    ) {
16549        self.display_map
16550            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16551        if let Some(autoscroll) = autoscroll {
16552            self.request_autoscroll(autoscroll, cx);
16553        }
16554        cx.notify();
16555    }
16556
16557    pub fn remove_blocks(
16558        &mut self,
16559        block_ids: HashSet<CustomBlockId>,
16560        autoscroll: Option<Autoscroll>,
16561        cx: &mut Context<Self>,
16562    ) {
16563        self.display_map.update(cx, |display_map, cx| {
16564            display_map.remove_blocks(block_ids, cx)
16565        });
16566        if let Some(autoscroll) = autoscroll {
16567            self.request_autoscroll(autoscroll, cx);
16568        }
16569        cx.notify();
16570    }
16571
16572    pub fn row_for_block(
16573        &self,
16574        block_id: CustomBlockId,
16575        cx: &mut Context<Self>,
16576    ) -> Option<DisplayRow> {
16577        self.display_map
16578            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16579    }
16580
16581    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16582        self.focused_block = Some(focused_block);
16583    }
16584
16585    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16586        self.focused_block.take()
16587    }
16588
16589    pub fn insert_creases(
16590        &mut self,
16591        creases: impl IntoIterator<Item = Crease<Anchor>>,
16592        cx: &mut Context<Self>,
16593    ) -> Vec<CreaseId> {
16594        self.display_map
16595            .update(cx, |map, cx| map.insert_creases(creases, cx))
16596    }
16597
16598    pub fn remove_creases(
16599        &mut self,
16600        ids: impl IntoIterator<Item = CreaseId>,
16601        cx: &mut Context<Self>,
16602    ) -> Vec<(CreaseId, Range<Anchor>)> {
16603        self.display_map
16604            .update(cx, |map, cx| map.remove_creases(ids, cx))
16605    }
16606
16607    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16608        self.display_map
16609            .update(cx, |map, cx| map.snapshot(cx))
16610            .longest_row()
16611    }
16612
16613    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16614        self.display_map
16615            .update(cx, |map, cx| map.snapshot(cx))
16616            .max_point()
16617    }
16618
16619    pub fn text(&self, cx: &App) -> String {
16620        self.buffer.read(cx).read(cx).text()
16621    }
16622
16623    pub fn is_empty(&self, cx: &App) -> bool {
16624        self.buffer.read(cx).read(cx).is_empty()
16625    }
16626
16627    pub fn text_option(&self, cx: &App) -> Option<String> {
16628        let text = self.text(cx);
16629        let text = text.trim();
16630
16631        if text.is_empty() {
16632            return None;
16633        }
16634
16635        Some(text.to_string())
16636    }
16637
16638    pub fn set_text(
16639        &mut self,
16640        text: impl Into<Arc<str>>,
16641        window: &mut Window,
16642        cx: &mut Context<Self>,
16643    ) {
16644        self.transact(window, cx, |this, _, cx| {
16645            this.buffer
16646                .read(cx)
16647                .as_singleton()
16648                .expect("you can only call set_text on editors for singleton buffers")
16649                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16650        });
16651    }
16652
16653    pub fn display_text(&self, cx: &mut App) -> String {
16654        self.display_map
16655            .update(cx, |map, cx| map.snapshot(cx))
16656            .text()
16657    }
16658
16659    fn create_minimap(
16660        &self,
16661        minimap_settings: MinimapSettings,
16662        window: &mut Window,
16663        cx: &mut Context<Self>,
16664    ) -> Option<Entity<Self>> {
16665        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16666            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16667    }
16668
16669    fn initialize_new_minimap(
16670        &self,
16671        minimap_settings: MinimapSettings,
16672        window: &mut Window,
16673        cx: &mut Context<Self>,
16674    ) -> Entity<Self> {
16675        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16676
16677        let mut minimap = Editor::new_internal(
16678            EditorMode::Minimap {
16679                parent: cx.weak_entity(),
16680            },
16681            self.buffer.clone(),
16682            self.project.clone(),
16683            Some(self.display_map.clone()),
16684            window,
16685            cx,
16686        );
16687        minimap.scroll_manager.clone_state(&self.scroll_manager);
16688        minimap.set_text_style_refinement(TextStyleRefinement {
16689            font_size: Some(MINIMAP_FONT_SIZE),
16690            font_weight: Some(MINIMAP_FONT_WEIGHT),
16691            ..Default::default()
16692        });
16693        minimap.update_minimap_configuration(minimap_settings, cx);
16694        cx.new(|_| minimap)
16695    }
16696
16697    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16698        let current_line_highlight = minimap_settings
16699            .current_line_highlight
16700            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16701        self.set_current_line_highlight(Some(current_line_highlight));
16702    }
16703
16704    pub fn minimap(&self) -> Option<&Entity<Self>> {
16705        self.minimap
16706            .as_ref()
16707            .filter(|_| self.minimap_visibility.visible())
16708    }
16709
16710    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16711        let mut wrap_guides = smallvec::smallvec![];
16712
16713        if self.show_wrap_guides == Some(false) {
16714            return wrap_guides;
16715        }
16716
16717        let settings = self.buffer.read(cx).language_settings(cx);
16718        if settings.show_wrap_guides {
16719            match self.soft_wrap_mode(cx) {
16720                SoftWrap::Column(soft_wrap) => {
16721                    wrap_guides.push((soft_wrap as usize, true));
16722                }
16723                SoftWrap::Bounded(soft_wrap) => {
16724                    wrap_guides.push((soft_wrap as usize, true));
16725                }
16726                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16727            }
16728            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16729        }
16730
16731        wrap_guides
16732    }
16733
16734    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16735        let settings = self.buffer.read(cx).language_settings(cx);
16736        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16737        match mode {
16738            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16739                SoftWrap::None
16740            }
16741            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16742            language_settings::SoftWrap::PreferredLineLength => {
16743                SoftWrap::Column(settings.preferred_line_length)
16744            }
16745            language_settings::SoftWrap::Bounded => {
16746                SoftWrap::Bounded(settings.preferred_line_length)
16747            }
16748        }
16749    }
16750
16751    pub fn set_soft_wrap_mode(
16752        &mut self,
16753        mode: language_settings::SoftWrap,
16754
16755        cx: &mut Context<Self>,
16756    ) {
16757        self.soft_wrap_mode_override = Some(mode);
16758        cx.notify();
16759    }
16760
16761    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16762        self.hard_wrap = hard_wrap;
16763        cx.notify();
16764    }
16765
16766    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16767        self.text_style_refinement = Some(style);
16768    }
16769
16770    /// called by the Element so we know what style we were most recently rendered with.
16771    pub(crate) fn set_style(
16772        &mut self,
16773        style: EditorStyle,
16774        window: &mut Window,
16775        cx: &mut Context<Self>,
16776    ) {
16777        // We intentionally do not inform the display map about the minimap style
16778        // so that wrapping is not recalculated and stays consistent for the editor
16779        // and its linked minimap.
16780        if !self.mode.is_minimap() {
16781            let rem_size = window.rem_size();
16782            self.display_map.update(cx, |map, cx| {
16783                map.set_font(
16784                    style.text.font(),
16785                    style.text.font_size.to_pixels(rem_size),
16786                    cx,
16787                )
16788            });
16789        }
16790        self.style = Some(style);
16791    }
16792
16793    pub fn style(&self) -> Option<&EditorStyle> {
16794        self.style.as_ref()
16795    }
16796
16797    // Called by the element. This method is not designed to be called outside of the editor
16798    // element's layout code because it does not notify when rewrapping is computed synchronously.
16799    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16800        self.display_map
16801            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16802    }
16803
16804    pub fn set_soft_wrap(&mut self) {
16805        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16806    }
16807
16808    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16809        if self.soft_wrap_mode_override.is_some() {
16810            self.soft_wrap_mode_override.take();
16811        } else {
16812            let soft_wrap = match self.soft_wrap_mode(cx) {
16813                SoftWrap::GitDiff => return,
16814                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16815                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16816                    language_settings::SoftWrap::None
16817                }
16818            };
16819            self.soft_wrap_mode_override = Some(soft_wrap);
16820        }
16821        cx.notify();
16822    }
16823
16824    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16825        let Some(workspace) = self.workspace() else {
16826            return;
16827        };
16828        let fs = workspace.read(cx).app_state().fs.clone();
16829        let current_show = TabBarSettings::get_global(cx).show;
16830        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16831            setting.show = Some(!current_show);
16832        });
16833    }
16834
16835    pub fn toggle_indent_guides(
16836        &mut self,
16837        _: &ToggleIndentGuides,
16838        _: &mut Window,
16839        cx: &mut Context<Self>,
16840    ) {
16841        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16842            self.buffer
16843                .read(cx)
16844                .language_settings(cx)
16845                .indent_guides
16846                .enabled
16847        });
16848        self.show_indent_guides = Some(!currently_enabled);
16849        cx.notify();
16850    }
16851
16852    fn should_show_indent_guides(&self) -> Option<bool> {
16853        self.show_indent_guides
16854    }
16855
16856    pub fn toggle_line_numbers(
16857        &mut self,
16858        _: &ToggleLineNumbers,
16859        _: &mut Window,
16860        cx: &mut Context<Self>,
16861    ) {
16862        let mut editor_settings = EditorSettings::get_global(cx).clone();
16863        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16864        EditorSettings::override_global(editor_settings, cx);
16865    }
16866
16867    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16868        if let Some(show_line_numbers) = self.show_line_numbers {
16869            return show_line_numbers;
16870        }
16871        EditorSettings::get_global(cx).gutter.line_numbers
16872    }
16873
16874    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16875        self.use_relative_line_numbers
16876            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16877    }
16878
16879    pub fn toggle_relative_line_numbers(
16880        &mut self,
16881        _: &ToggleRelativeLineNumbers,
16882        _: &mut Window,
16883        cx: &mut Context<Self>,
16884    ) {
16885        let is_relative = self.should_use_relative_line_numbers(cx);
16886        self.set_relative_line_number(Some(!is_relative), cx)
16887    }
16888
16889    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16890        self.use_relative_line_numbers = is_relative;
16891        cx.notify();
16892    }
16893
16894    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16895        self.show_gutter = show_gutter;
16896        cx.notify();
16897    }
16898
16899    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16900        self.show_scrollbars = show_scrollbars;
16901        cx.notify();
16902    }
16903
16904    pub fn set_minimap_visibility(
16905        &mut self,
16906        minimap_visibility: MinimapVisibility,
16907        window: &mut Window,
16908        cx: &mut Context<Self>,
16909    ) {
16910        if self.minimap_visibility != minimap_visibility {
16911            if minimap_visibility.visible() && self.minimap.is_none() {
16912                let minimap_settings = EditorSettings::get_global(cx).minimap;
16913                self.minimap =
16914                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16915            }
16916            self.minimap_visibility = minimap_visibility;
16917            cx.notify();
16918        }
16919    }
16920
16921    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16922        self.set_show_scrollbars(false, cx);
16923        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16924    }
16925
16926    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16927        self.show_line_numbers = Some(show_line_numbers);
16928        cx.notify();
16929    }
16930
16931    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16932        self.disable_expand_excerpt_buttons = true;
16933        cx.notify();
16934    }
16935
16936    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16937        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16938        cx.notify();
16939    }
16940
16941    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16942        self.show_code_actions = Some(show_code_actions);
16943        cx.notify();
16944    }
16945
16946    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16947        self.show_runnables = Some(show_runnables);
16948        cx.notify();
16949    }
16950
16951    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16952        self.show_breakpoints = Some(show_breakpoints);
16953        cx.notify();
16954    }
16955
16956    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16957        if self.display_map.read(cx).masked != masked {
16958            self.display_map.update(cx, |map, _| map.masked = masked);
16959        }
16960        cx.notify()
16961    }
16962
16963    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16964        self.show_wrap_guides = Some(show_wrap_guides);
16965        cx.notify();
16966    }
16967
16968    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16969        self.show_indent_guides = Some(show_indent_guides);
16970        cx.notify();
16971    }
16972
16973    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16974        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16975            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16976                if let Some(dir) = file.abs_path(cx).parent() {
16977                    return Some(dir.to_owned());
16978                }
16979            }
16980
16981            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16982                return Some(project_path.path.to_path_buf());
16983            }
16984        }
16985
16986        None
16987    }
16988
16989    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16990        self.active_excerpt(cx)?
16991            .1
16992            .read(cx)
16993            .file()
16994            .and_then(|f| f.as_local())
16995    }
16996
16997    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16998        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16999            let buffer = buffer.read(cx);
17000            if let Some(project_path) = buffer.project_path(cx) {
17001                let project = self.project.as_ref()?.read(cx);
17002                project.absolute_path(&project_path, cx)
17003            } else {
17004                buffer
17005                    .file()
17006                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17007            }
17008        })
17009    }
17010
17011    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17012        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17013            let project_path = buffer.read(cx).project_path(cx)?;
17014            let project = self.project.as_ref()?.read(cx);
17015            let entry = project.entry_for_path(&project_path, cx)?;
17016            let path = entry.path.to_path_buf();
17017            Some(path)
17018        })
17019    }
17020
17021    pub fn reveal_in_finder(
17022        &mut self,
17023        _: &RevealInFileManager,
17024        _window: &mut Window,
17025        cx: &mut Context<Self>,
17026    ) {
17027        if let Some(target) = self.target_file(cx) {
17028            cx.reveal_path(&target.abs_path(cx));
17029        }
17030    }
17031
17032    pub fn copy_path(
17033        &mut self,
17034        _: &zed_actions::workspace::CopyPath,
17035        _window: &mut Window,
17036        cx: &mut Context<Self>,
17037    ) {
17038        if let Some(path) = self.target_file_abs_path(cx) {
17039            if let Some(path) = path.to_str() {
17040                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17041            }
17042        }
17043    }
17044
17045    pub fn copy_relative_path(
17046        &mut self,
17047        _: &zed_actions::workspace::CopyRelativePath,
17048        _window: &mut Window,
17049        cx: &mut Context<Self>,
17050    ) {
17051        if let Some(path) = self.target_file_path(cx) {
17052            if let Some(path) = path.to_str() {
17053                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17054            }
17055        }
17056    }
17057
17058    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17059        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17060            buffer.read(cx).project_path(cx)
17061        } else {
17062            None
17063        }
17064    }
17065
17066    // Returns true if the editor handled a go-to-line request
17067    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17068        maybe!({
17069            let breakpoint_store = self.breakpoint_store.as_ref()?;
17070
17071            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17072            else {
17073                self.clear_row_highlights::<ActiveDebugLine>();
17074                return None;
17075            };
17076
17077            let position = active_stack_frame.position;
17078            let buffer_id = position.buffer_id?;
17079            let snapshot = self
17080                .project
17081                .as_ref()?
17082                .read(cx)
17083                .buffer_for_id(buffer_id, cx)?
17084                .read(cx)
17085                .snapshot();
17086
17087            let mut handled = false;
17088            for (id, ExcerptRange { context, .. }) in
17089                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17090            {
17091                if context.start.cmp(&position, &snapshot).is_ge()
17092                    || context.end.cmp(&position, &snapshot).is_lt()
17093                {
17094                    continue;
17095                }
17096                let snapshot = self.buffer.read(cx).snapshot(cx);
17097                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17098
17099                handled = true;
17100                self.clear_row_highlights::<ActiveDebugLine>();
17101
17102                self.go_to_line::<ActiveDebugLine>(
17103                    multibuffer_anchor,
17104                    Some(cx.theme().colors().editor_debugger_active_line_background),
17105                    window,
17106                    cx,
17107                );
17108
17109                cx.notify();
17110            }
17111
17112            handled.then_some(())
17113        })
17114        .is_some()
17115    }
17116
17117    pub fn copy_file_name_without_extension(
17118        &mut self,
17119        _: &CopyFileNameWithoutExtension,
17120        _: &mut Window,
17121        cx: &mut Context<Self>,
17122    ) {
17123        if let Some(file) = self.target_file(cx) {
17124            if let Some(file_stem) = file.path().file_stem() {
17125                if let Some(name) = file_stem.to_str() {
17126                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17127                }
17128            }
17129        }
17130    }
17131
17132    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17133        if let Some(file) = self.target_file(cx) {
17134            if let Some(file_name) = file.path().file_name() {
17135                if let Some(name) = file_name.to_str() {
17136                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17137                }
17138            }
17139        }
17140    }
17141
17142    pub fn toggle_git_blame(
17143        &mut self,
17144        _: &::git::Blame,
17145        window: &mut Window,
17146        cx: &mut Context<Self>,
17147    ) {
17148        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17149
17150        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17151            self.start_git_blame(true, window, cx);
17152        }
17153
17154        cx.notify();
17155    }
17156
17157    pub fn toggle_git_blame_inline(
17158        &mut self,
17159        _: &ToggleGitBlameInline,
17160        window: &mut Window,
17161        cx: &mut Context<Self>,
17162    ) {
17163        self.toggle_git_blame_inline_internal(true, window, cx);
17164        cx.notify();
17165    }
17166
17167    pub fn open_git_blame_commit(
17168        &mut self,
17169        _: &OpenGitBlameCommit,
17170        window: &mut Window,
17171        cx: &mut Context<Self>,
17172    ) {
17173        self.open_git_blame_commit_internal(window, cx);
17174    }
17175
17176    fn open_git_blame_commit_internal(
17177        &mut self,
17178        window: &mut Window,
17179        cx: &mut Context<Self>,
17180    ) -> Option<()> {
17181        let blame = self.blame.as_ref()?;
17182        let snapshot = self.snapshot(window, cx);
17183        let cursor = self.selections.newest::<Point>(cx).head();
17184        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17185        let blame_entry = blame
17186            .update(cx, |blame, cx| {
17187                blame
17188                    .blame_for_rows(
17189                        &[RowInfo {
17190                            buffer_id: Some(buffer.remote_id()),
17191                            buffer_row: Some(point.row),
17192                            ..Default::default()
17193                        }],
17194                        cx,
17195                    )
17196                    .next()
17197            })
17198            .flatten()?;
17199        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17200        let repo = blame.read(cx).repository(cx)?;
17201        let workspace = self.workspace()?.downgrade();
17202        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17203        None
17204    }
17205
17206    pub fn git_blame_inline_enabled(&self) -> bool {
17207        self.git_blame_inline_enabled
17208    }
17209
17210    pub fn toggle_selection_menu(
17211        &mut self,
17212        _: &ToggleSelectionMenu,
17213        _: &mut Window,
17214        cx: &mut Context<Self>,
17215    ) {
17216        self.show_selection_menu = self
17217            .show_selection_menu
17218            .map(|show_selections_menu| !show_selections_menu)
17219            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17220
17221        cx.notify();
17222    }
17223
17224    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17225        self.show_selection_menu
17226            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17227    }
17228
17229    fn start_git_blame(
17230        &mut self,
17231        user_triggered: bool,
17232        window: &mut Window,
17233        cx: &mut Context<Self>,
17234    ) {
17235        if let Some(project) = self.project.as_ref() {
17236            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17237                return;
17238            };
17239
17240            if buffer.read(cx).file().is_none() {
17241                return;
17242            }
17243
17244            let focused = self.focus_handle(cx).contains_focused(window, cx);
17245
17246            let project = project.clone();
17247            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17248            self.blame_subscription =
17249                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17250            self.blame = Some(blame);
17251        }
17252    }
17253
17254    fn toggle_git_blame_inline_internal(
17255        &mut self,
17256        user_triggered: bool,
17257        window: &mut Window,
17258        cx: &mut Context<Self>,
17259    ) {
17260        if self.git_blame_inline_enabled {
17261            self.git_blame_inline_enabled = false;
17262            self.show_git_blame_inline = false;
17263            self.show_git_blame_inline_delay_task.take();
17264        } else {
17265            self.git_blame_inline_enabled = true;
17266            self.start_git_blame_inline(user_triggered, window, cx);
17267        }
17268
17269        cx.notify();
17270    }
17271
17272    fn start_git_blame_inline(
17273        &mut self,
17274        user_triggered: bool,
17275        window: &mut Window,
17276        cx: &mut Context<Self>,
17277    ) {
17278        self.start_git_blame(user_triggered, window, cx);
17279
17280        if ProjectSettings::get_global(cx)
17281            .git
17282            .inline_blame_delay()
17283            .is_some()
17284        {
17285            self.start_inline_blame_timer(window, cx);
17286        } else {
17287            self.show_git_blame_inline = true
17288        }
17289    }
17290
17291    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17292        self.blame.as_ref()
17293    }
17294
17295    pub fn show_git_blame_gutter(&self) -> bool {
17296        self.show_git_blame_gutter
17297    }
17298
17299    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17300        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17301    }
17302
17303    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17304        self.show_git_blame_inline
17305            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17306            && !self.newest_selection_head_on_empty_line(cx)
17307            && self.has_blame_entries(cx)
17308    }
17309
17310    fn has_blame_entries(&self, cx: &App) -> bool {
17311        self.blame()
17312            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17313    }
17314
17315    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17316        let cursor_anchor = self.selections.newest_anchor().head();
17317
17318        let snapshot = self.buffer.read(cx).snapshot(cx);
17319        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17320
17321        snapshot.line_len(buffer_row) == 0
17322    }
17323
17324    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17325        let buffer_and_selection = maybe!({
17326            let selection = self.selections.newest::<Point>(cx);
17327            let selection_range = selection.range();
17328
17329            let multi_buffer = self.buffer().read(cx);
17330            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17331            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17332
17333            let (buffer, range, _) = if selection.reversed {
17334                buffer_ranges.first()
17335            } else {
17336                buffer_ranges.last()
17337            }?;
17338
17339            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17340                ..text::ToPoint::to_point(&range.end, &buffer).row;
17341            Some((
17342                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17343                selection,
17344            ))
17345        });
17346
17347        let Some((buffer, selection)) = buffer_and_selection else {
17348            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17349        };
17350
17351        let Some(project) = self.project.as_ref() else {
17352            return Task::ready(Err(anyhow!("editor does not have project")));
17353        };
17354
17355        project.update(cx, |project, cx| {
17356            project.get_permalink_to_line(&buffer, selection, cx)
17357        })
17358    }
17359
17360    pub fn copy_permalink_to_line(
17361        &mut self,
17362        _: &CopyPermalinkToLine,
17363        window: &mut Window,
17364        cx: &mut Context<Self>,
17365    ) {
17366        let permalink_task = self.get_permalink_to_line(cx);
17367        let workspace = self.workspace();
17368
17369        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17370            Ok(permalink) => {
17371                cx.update(|_, cx| {
17372                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17373                })
17374                .ok();
17375            }
17376            Err(err) => {
17377                let message = format!("Failed to copy permalink: {err}");
17378
17379                anyhow::Result::<()>::Err(err).log_err();
17380
17381                if let Some(workspace) = workspace {
17382                    workspace
17383                        .update_in(cx, |workspace, _, cx| {
17384                            struct CopyPermalinkToLine;
17385
17386                            workspace.show_toast(
17387                                Toast::new(
17388                                    NotificationId::unique::<CopyPermalinkToLine>(),
17389                                    message,
17390                                ),
17391                                cx,
17392                            )
17393                        })
17394                        .ok();
17395                }
17396            }
17397        })
17398        .detach();
17399    }
17400
17401    pub fn copy_file_location(
17402        &mut self,
17403        _: &CopyFileLocation,
17404        _: &mut Window,
17405        cx: &mut Context<Self>,
17406    ) {
17407        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17408        if let Some(file) = self.target_file(cx) {
17409            if let Some(path) = file.path().to_str() {
17410                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17411            }
17412        }
17413    }
17414
17415    pub fn open_permalink_to_line(
17416        &mut self,
17417        _: &OpenPermalinkToLine,
17418        window: &mut Window,
17419        cx: &mut Context<Self>,
17420    ) {
17421        let permalink_task = self.get_permalink_to_line(cx);
17422        let workspace = self.workspace();
17423
17424        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17425            Ok(permalink) => {
17426                cx.update(|_, cx| {
17427                    cx.open_url(permalink.as_ref());
17428                })
17429                .ok();
17430            }
17431            Err(err) => {
17432                let message = format!("Failed to open permalink: {err}");
17433
17434                anyhow::Result::<()>::Err(err).log_err();
17435
17436                if let Some(workspace) = workspace {
17437                    workspace
17438                        .update(cx, |workspace, cx| {
17439                            struct OpenPermalinkToLine;
17440
17441                            workspace.show_toast(
17442                                Toast::new(
17443                                    NotificationId::unique::<OpenPermalinkToLine>(),
17444                                    message,
17445                                ),
17446                                cx,
17447                            )
17448                        })
17449                        .ok();
17450                }
17451            }
17452        })
17453        .detach();
17454    }
17455
17456    pub fn insert_uuid_v4(
17457        &mut self,
17458        _: &InsertUuidV4,
17459        window: &mut Window,
17460        cx: &mut Context<Self>,
17461    ) {
17462        self.insert_uuid(UuidVersion::V4, window, cx);
17463    }
17464
17465    pub fn insert_uuid_v7(
17466        &mut self,
17467        _: &InsertUuidV7,
17468        window: &mut Window,
17469        cx: &mut Context<Self>,
17470    ) {
17471        self.insert_uuid(UuidVersion::V7, window, cx);
17472    }
17473
17474    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17475        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17476        self.transact(window, cx, |this, window, cx| {
17477            let edits = this
17478                .selections
17479                .all::<Point>(cx)
17480                .into_iter()
17481                .map(|selection| {
17482                    let uuid = match version {
17483                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17484                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17485                    };
17486
17487                    (selection.range(), uuid.to_string())
17488                });
17489            this.edit(edits, cx);
17490            this.refresh_inline_completion(true, false, window, cx);
17491        });
17492    }
17493
17494    pub fn open_selections_in_multibuffer(
17495        &mut self,
17496        _: &OpenSelectionsInMultibuffer,
17497        window: &mut Window,
17498        cx: &mut Context<Self>,
17499    ) {
17500        let multibuffer = self.buffer.read(cx);
17501
17502        let Some(buffer) = multibuffer.as_singleton() else {
17503            return;
17504        };
17505
17506        let Some(workspace) = self.workspace() else {
17507            return;
17508        };
17509
17510        let locations = self
17511            .selections
17512            .disjoint_anchors()
17513            .iter()
17514            .map(|range| Location {
17515                buffer: buffer.clone(),
17516                range: range.start.text_anchor..range.end.text_anchor,
17517            })
17518            .collect::<Vec<_>>();
17519
17520        let title = multibuffer.title(cx).to_string();
17521
17522        cx.spawn_in(window, async move |_, cx| {
17523            workspace.update_in(cx, |workspace, window, cx| {
17524                Self::open_locations_in_multibuffer(
17525                    workspace,
17526                    locations,
17527                    format!("Selections for '{title}'"),
17528                    false,
17529                    MultibufferSelectionMode::All,
17530                    window,
17531                    cx,
17532                );
17533            })
17534        })
17535        .detach();
17536    }
17537
17538    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17539    /// last highlight added will be used.
17540    ///
17541    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17542    pub fn highlight_rows<T: 'static>(
17543        &mut self,
17544        range: Range<Anchor>,
17545        color: Hsla,
17546        options: RowHighlightOptions,
17547        cx: &mut Context<Self>,
17548    ) {
17549        let snapshot = self.buffer().read(cx).snapshot(cx);
17550        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17551        let ix = row_highlights.binary_search_by(|highlight| {
17552            Ordering::Equal
17553                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17554                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17555        });
17556
17557        if let Err(mut ix) = ix {
17558            let index = post_inc(&mut self.highlight_order);
17559
17560            // If this range intersects with the preceding highlight, then merge it with
17561            // the preceding highlight. Otherwise insert a new highlight.
17562            let mut merged = false;
17563            if ix > 0 {
17564                let prev_highlight = &mut row_highlights[ix - 1];
17565                if prev_highlight
17566                    .range
17567                    .end
17568                    .cmp(&range.start, &snapshot)
17569                    .is_ge()
17570                {
17571                    ix -= 1;
17572                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17573                        prev_highlight.range.end = range.end;
17574                    }
17575                    merged = true;
17576                    prev_highlight.index = index;
17577                    prev_highlight.color = color;
17578                    prev_highlight.options = options;
17579                }
17580            }
17581
17582            if !merged {
17583                row_highlights.insert(
17584                    ix,
17585                    RowHighlight {
17586                        range: range.clone(),
17587                        index,
17588                        color,
17589                        options,
17590                        type_id: TypeId::of::<T>(),
17591                    },
17592                );
17593            }
17594
17595            // If any of the following highlights intersect with this one, merge them.
17596            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17597                let highlight = &row_highlights[ix];
17598                if next_highlight
17599                    .range
17600                    .start
17601                    .cmp(&highlight.range.end, &snapshot)
17602                    .is_le()
17603                {
17604                    if next_highlight
17605                        .range
17606                        .end
17607                        .cmp(&highlight.range.end, &snapshot)
17608                        .is_gt()
17609                    {
17610                        row_highlights[ix].range.end = next_highlight.range.end;
17611                    }
17612                    row_highlights.remove(ix + 1);
17613                } else {
17614                    break;
17615                }
17616            }
17617        }
17618    }
17619
17620    /// Remove any highlighted row ranges of the given type that intersect the
17621    /// given ranges.
17622    pub fn remove_highlighted_rows<T: 'static>(
17623        &mut self,
17624        ranges_to_remove: Vec<Range<Anchor>>,
17625        cx: &mut Context<Self>,
17626    ) {
17627        let snapshot = self.buffer().read(cx).snapshot(cx);
17628        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17629        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17630        row_highlights.retain(|highlight| {
17631            while let Some(range_to_remove) = ranges_to_remove.peek() {
17632                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17633                    Ordering::Less | Ordering::Equal => {
17634                        ranges_to_remove.next();
17635                    }
17636                    Ordering::Greater => {
17637                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17638                            Ordering::Less | Ordering::Equal => {
17639                                return false;
17640                            }
17641                            Ordering::Greater => break,
17642                        }
17643                    }
17644                }
17645            }
17646
17647            true
17648        })
17649    }
17650
17651    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17652    pub fn clear_row_highlights<T: 'static>(&mut self) {
17653        self.highlighted_rows.remove(&TypeId::of::<T>());
17654    }
17655
17656    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17657    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17658        self.highlighted_rows
17659            .get(&TypeId::of::<T>())
17660            .map_or(&[] as &[_], |vec| vec.as_slice())
17661            .iter()
17662            .map(|highlight| (highlight.range.clone(), highlight.color))
17663    }
17664
17665    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17666    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17667    /// Allows to ignore certain kinds of highlights.
17668    pub fn highlighted_display_rows(
17669        &self,
17670        window: &mut Window,
17671        cx: &mut App,
17672    ) -> BTreeMap<DisplayRow, LineHighlight> {
17673        let snapshot = self.snapshot(window, cx);
17674        let mut used_highlight_orders = HashMap::default();
17675        self.highlighted_rows
17676            .iter()
17677            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17678            .fold(
17679                BTreeMap::<DisplayRow, LineHighlight>::new(),
17680                |mut unique_rows, highlight| {
17681                    let start = highlight.range.start.to_display_point(&snapshot);
17682                    let end = highlight.range.end.to_display_point(&snapshot);
17683                    let start_row = start.row().0;
17684                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17685                        && end.column() == 0
17686                    {
17687                        end.row().0.saturating_sub(1)
17688                    } else {
17689                        end.row().0
17690                    };
17691                    for row in start_row..=end_row {
17692                        let used_index =
17693                            used_highlight_orders.entry(row).or_insert(highlight.index);
17694                        if highlight.index >= *used_index {
17695                            *used_index = highlight.index;
17696                            unique_rows.insert(
17697                                DisplayRow(row),
17698                                LineHighlight {
17699                                    include_gutter: highlight.options.include_gutter,
17700                                    border: None,
17701                                    background: highlight.color.into(),
17702                                    type_id: Some(highlight.type_id),
17703                                },
17704                            );
17705                        }
17706                    }
17707                    unique_rows
17708                },
17709            )
17710    }
17711
17712    pub fn highlighted_display_row_for_autoscroll(
17713        &self,
17714        snapshot: &DisplaySnapshot,
17715    ) -> Option<DisplayRow> {
17716        self.highlighted_rows
17717            .values()
17718            .flat_map(|highlighted_rows| highlighted_rows.iter())
17719            .filter_map(|highlight| {
17720                if highlight.options.autoscroll {
17721                    Some(highlight.range.start.to_display_point(snapshot).row())
17722                } else {
17723                    None
17724                }
17725            })
17726            .min()
17727    }
17728
17729    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17730        self.highlight_background::<SearchWithinRange>(
17731            ranges,
17732            |colors| colors.editor_document_highlight_read_background,
17733            cx,
17734        )
17735    }
17736
17737    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17738        self.breadcrumb_header = Some(new_header);
17739    }
17740
17741    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17742        self.clear_background_highlights::<SearchWithinRange>(cx);
17743    }
17744
17745    pub fn highlight_background<T: 'static>(
17746        &mut self,
17747        ranges: &[Range<Anchor>],
17748        color_fetcher: fn(&ThemeColors) -> Hsla,
17749        cx: &mut Context<Self>,
17750    ) {
17751        self.background_highlights
17752            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17753        self.scrollbar_marker_state.dirty = true;
17754        cx.notify();
17755    }
17756
17757    pub fn clear_background_highlights<T: 'static>(
17758        &mut self,
17759        cx: &mut Context<Self>,
17760    ) -> Option<BackgroundHighlight> {
17761        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17762        if !text_highlights.1.is_empty() {
17763            self.scrollbar_marker_state.dirty = true;
17764            cx.notify();
17765        }
17766        Some(text_highlights)
17767    }
17768
17769    pub fn highlight_gutter<T: 'static>(
17770        &mut self,
17771        ranges: &[Range<Anchor>],
17772        color_fetcher: fn(&App) -> Hsla,
17773        cx: &mut Context<Self>,
17774    ) {
17775        self.gutter_highlights
17776            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17777        cx.notify();
17778    }
17779
17780    pub fn clear_gutter_highlights<T: 'static>(
17781        &mut self,
17782        cx: &mut Context<Self>,
17783    ) -> Option<GutterHighlight> {
17784        cx.notify();
17785        self.gutter_highlights.remove(&TypeId::of::<T>())
17786    }
17787
17788    #[cfg(feature = "test-support")]
17789    pub fn all_text_background_highlights(
17790        &self,
17791        window: &mut Window,
17792        cx: &mut Context<Self>,
17793    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17794        let snapshot = self.snapshot(window, cx);
17795        let buffer = &snapshot.buffer_snapshot;
17796        let start = buffer.anchor_before(0);
17797        let end = buffer.anchor_after(buffer.len());
17798        let theme = cx.theme().colors();
17799        self.background_highlights_in_range(start..end, &snapshot, theme)
17800    }
17801
17802    #[cfg(feature = "test-support")]
17803    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17804        let snapshot = self.buffer().read(cx).snapshot(cx);
17805
17806        let highlights = self
17807            .background_highlights
17808            .get(&TypeId::of::<items::BufferSearchHighlights>());
17809
17810        if let Some((_color, ranges)) = highlights {
17811            ranges
17812                .iter()
17813                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17814                .collect_vec()
17815        } else {
17816            vec![]
17817        }
17818    }
17819
17820    fn document_highlights_for_position<'a>(
17821        &'a self,
17822        position: Anchor,
17823        buffer: &'a MultiBufferSnapshot,
17824    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17825        let read_highlights = self
17826            .background_highlights
17827            .get(&TypeId::of::<DocumentHighlightRead>())
17828            .map(|h| &h.1);
17829        let write_highlights = self
17830            .background_highlights
17831            .get(&TypeId::of::<DocumentHighlightWrite>())
17832            .map(|h| &h.1);
17833        let left_position = position.bias_left(buffer);
17834        let right_position = position.bias_right(buffer);
17835        read_highlights
17836            .into_iter()
17837            .chain(write_highlights)
17838            .flat_map(move |ranges| {
17839                let start_ix = match ranges.binary_search_by(|probe| {
17840                    let cmp = probe.end.cmp(&left_position, buffer);
17841                    if cmp.is_ge() {
17842                        Ordering::Greater
17843                    } else {
17844                        Ordering::Less
17845                    }
17846                }) {
17847                    Ok(i) | Err(i) => i,
17848                };
17849
17850                ranges[start_ix..]
17851                    .iter()
17852                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17853            })
17854    }
17855
17856    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17857        self.background_highlights
17858            .get(&TypeId::of::<T>())
17859            .map_or(false, |(_, highlights)| !highlights.is_empty())
17860    }
17861
17862    pub fn background_highlights_in_range(
17863        &self,
17864        search_range: Range<Anchor>,
17865        display_snapshot: &DisplaySnapshot,
17866        theme: &ThemeColors,
17867    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17868        let mut results = Vec::new();
17869        for (color_fetcher, ranges) in self.background_highlights.values() {
17870            let color = color_fetcher(theme);
17871            let start_ix = match ranges.binary_search_by(|probe| {
17872                let cmp = probe
17873                    .end
17874                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17875                if cmp.is_gt() {
17876                    Ordering::Greater
17877                } else {
17878                    Ordering::Less
17879                }
17880            }) {
17881                Ok(i) | Err(i) => i,
17882            };
17883            for range in &ranges[start_ix..] {
17884                if range
17885                    .start
17886                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17887                    .is_ge()
17888                {
17889                    break;
17890                }
17891
17892                let start = range.start.to_display_point(display_snapshot);
17893                let end = range.end.to_display_point(display_snapshot);
17894                results.push((start..end, color))
17895            }
17896        }
17897        results
17898    }
17899
17900    pub fn background_highlight_row_ranges<T: 'static>(
17901        &self,
17902        search_range: Range<Anchor>,
17903        display_snapshot: &DisplaySnapshot,
17904        count: usize,
17905    ) -> Vec<RangeInclusive<DisplayPoint>> {
17906        let mut results = Vec::new();
17907        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17908            return vec![];
17909        };
17910
17911        let start_ix = match ranges.binary_search_by(|probe| {
17912            let cmp = probe
17913                .end
17914                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17915            if cmp.is_gt() {
17916                Ordering::Greater
17917            } else {
17918                Ordering::Less
17919            }
17920        }) {
17921            Ok(i) | Err(i) => i,
17922        };
17923        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17924            if let (Some(start_display), Some(end_display)) = (start, end) {
17925                results.push(
17926                    start_display.to_display_point(display_snapshot)
17927                        ..=end_display.to_display_point(display_snapshot),
17928                );
17929            }
17930        };
17931        let mut start_row: Option<Point> = None;
17932        let mut end_row: Option<Point> = None;
17933        if ranges.len() > count {
17934            return Vec::new();
17935        }
17936        for range in &ranges[start_ix..] {
17937            if range
17938                .start
17939                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17940                .is_ge()
17941            {
17942                break;
17943            }
17944            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17945            if let Some(current_row) = &end_row {
17946                if end.row == current_row.row {
17947                    continue;
17948                }
17949            }
17950            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17951            if start_row.is_none() {
17952                assert_eq!(end_row, None);
17953                start_row = Some(start);
17954                end_row = Some(end);
17955                continue;
17956            }
17957            if let Some(current_end) = end_row.as_mut() {
17958                if start.row > current_end.row + 1 {
17959                    push_region(start_row, end_row);
17960                    start_row = Some(start);
17961                    end_row = Some(end);
17962                } else {
17963                    // Merge two hunks.
17964                    *current_end = end;
17965                }
17966            } else {
17967                unreachable!();
17968            }
17969        }
17970        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17971        push_region(start_row, end_row);
17972        results
17973    }
17974
17975    pub fn gutter_highlights_in_range(
17976        &self,
17977        search_range: Range<Anchor>,
17978        display_snapshot: &DisplaySnapshot,
17979        cx: &App,
17980    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17981        let mut results = Vec::new();
17982        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17983            let color = color_fetcher(cx);
17984            let start_ix = match ranges.binary_search_by(|probe| {
17985                let cmp = probe
17986                    .end
17987                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17988                if cmp.is_gt() {
17989                    Ordering::Greater
17990                } else {
17991                    Ordering::Less
17992                }
17993            }) {
17994                Ok(i) | Err(i) => i,
17995            };
17996            for range in &ranges[start_ix..] {
17997                if range
17998                    .start
17999                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18000                    .is_ge()
18001                {
18002                    break;
18003                }
18004
18005                let start = range.start.to_display_point(display_snapshot);
18006                let end = range.end.to_display_point(display_snapshot);
18007                results.push((start..end, color))
18008            }
18009        }
18010        results
18011    }
18012
18013    /// Get the text ranges corresponding to the redaction query
18014    pub fn redacted_ranges(
18015        &self,
18016        search_range: Range<Anchor>,
18017        display_snapshot: &DisplaySnapshot,
18018        cx: &App,
18019    ) -> Vec<Range<DisplayPoint>> {
18020        display_snapshot
18021            .buffer_snapshot
18022            .redacted_ranges(search_range, |file| {
18023                if let Some(file) = file {
18024                    file.is_private()
18025                        && EditorSettings::get(
18026                            Some(SettingsLocation {
18027                                worktree_id: file.worktree_id(cx),
18028                                path: file.path().as_ref(),
18029                            }),
18030                            cx,
18031                        )
18032                        .redact_private_values
18033                } else {
18034                    false
18035                }
18036            })
18037            .map(|range| {
18038                range.start.to_display_point(display_snapshot)
18039                    ..range.end.to_display_point(display_snapshot)
18040            })
18041            .collect()
18042    }
18043
18044    pub fn highlight_text<T: 'static>(
18045        &mut self,
18046        ranges: Vec<Range<Anchor>>,
18047        style: HighlightStyle,
18048        cx: &mut Context<Self>,
18049    ) {
18050        self.display_map.update(cx, |map, _| {
18051            map.highlight_text(TypeId::of::<T>(), ranges, style)
18052        });
18053        cx.notify();
18054    }
18055
18056    pub(crate) fn highlight_inlays<T: 'static>(
18057        &mut self,
18058        highlights: Vec<InlayHighlight>,
18059        style: HighlightStyle,
18060        cx: &mut Context<Self>,
18061    ) {
18062        self.display_map.update(cx, |map, _| {
18063            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18064        });
18065        cx.notify();
18066    }
18067
18068    pub fn text_highlights<'a, T: 'static>(
18069        &'a self,
18070        cx: &'a App,
18071    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18072        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18073    }
18074
18075    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18076        let cleared = self
18077            .display_map
18078            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18079        if cleared {
18080            cx.notify();
18081        }
18082    }
18083
18084    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18085        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18086            && self.focus_handle.is_focused(window)
18087    }
18088
18089    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18090        self.show_cursor_when_unfocused = is_enabled;
18091        cx.notify();
18092    }
18093
18094    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18095        cx.notify();
18096    }
18097
18098    fn on_debug_session_event(
18099        &mut self,
18100        _session: Entity<Session>,
18101        event: &SessionEvent,
18102        cx: &mut Context<Self>,
18103    ) {
18104        match event {
18105            SessionEvent::InvalidateInlineValue => {
18106                self.refresh_inline_values(cx);
18107            }
18108            _ => {}
18109        }
18110    }
18111
18112    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18113        let Some(project) = self.project.clone() else {
18114            return;
18115        };
18116
18117        if !self.inline_value_cache.enabled {
18118            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18119            self.splice_inlays(&inlays, Vec::new(), cx);
18120            return;
18121        }
18122
18123        let current_execution_position = self
18124            .highlighted_rows
18125            .get(&TypeId::of::<ActiveDebugLine>())
18126            .and_then(|lines| lines.last().map(|line| line.range.start));
18127
18128        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18129            let inline_values = editor
18130                .update(cx, |editor, cx| {
18131                    let Some(current_execution_position) = current_execution_position else {
18132                        return Some(Task::ready(Ok(Vec::new())));
18133                    };
18134
18135                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18136                        let snapshot = buffer.snapshot(cx);
18137
18138                        let excerpt = snapshot.excerpt_containing(
18139                            current_execution_position..current_execution_position,
18140                        )?;
18141
18142                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18143                    })?;
18144
18145                    let range =
18146                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18147
18148                    project.inline_values(buffer, range, cx)
18149                })
18150                .ok()
18151                .flatten()?
18152                .await
18153                .context("refreshing debugger inlays")
18154                .log_err()?;
18155
18156            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18157
18158            for (buffer_id, inline_value) in inline_values
18159                .into_iter()
18160                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18161            {
18162                buffer_inline_values
18163                    .entry(buffer_id)
18164                    .or_default()
18165                    .push(inline_value);
18166            }
18167
18168            editor
18169                .update(cx, |editor, cx| {
18170                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18171                    let mut new_inlays = Vec::default();
18172
18173                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18174                        let buffer_id = buffer_snapshot.remote_id();
18175                        buffer_inline_values
18176                            .get(&buffer_id)
18177                            .into_iter()
18178                            .flatten()
18179                            .for_each(|hint| {
18180                                let inlay = Inlay::debugger_hint(
18181                                    post_inc(&mut editor.next_inlay_id),
18182                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18183                                    hint.text(),
18184                                );
18185
18186                                new_inlays.push(inlay);
18187                            });
18188                    }
18189
18190                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18191                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18192
18193                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18194                })
18195                .ok()?;
18196            Some(())
18197        });
18198    }
18199
18200    fn on_buffer_event(
18201        &mut self,
18202        multibuffer: &Entity<MultiBuffer>,
18203        event: &multi_buffer::Event,
18204        window: &mut Window,
18205        cx: &mut Context<Self>,
18206    ) {
18207        match event {
18208            multi_buffer::Event::Edited {
18209                singleton_buffer_edited,
18210                edited_buffer: buffer_edited,
18211            } => {
18212                self.scrollbar_marker_state.dirty = true;
18213                self.active_indent_guides_state.dirty = true;
18214                self.refresh_active_diagnostics(cx);
18215                self.refresh_code_actions(window, cx);
18216                self.refresh_selected_text_highlights(true, window, cx);
18217                refresh_matching_bracket_highlights(self, window, cx);
18218                if self.has_active_inline_completion() {
18219                    self.update_visible_inline_completion(window, cx);
18220                }
18221                if let Some(buffer) = buffer_edited {
18222                    let buffer_id = buffer.read(cx).remote_id();
18223                    if !self.registered_buffers.contains_key(&buffer_id) {
18224                        if let Some(project) = self.project.as_ref() {
18225                            project.update(cx, |project, cx| {
18226                                self.registered_buffers.insert(
18227                                    buffer_id,
18228                                    project.register_buffer_with_language_servers(&buffer, cx),
18229                                );
18230                            })
18231                        }
18232                    }
18233                }
18234                cx.emit(EditorEvent::BufferEdited);
18235                cx.emit(SearchEvent::MatchesInvalidated);
18236                if *singleton_buffer_edited {
18237                    if let Some(project) = &self.project {
18238                        #[allow(clippy::mutable_key_type)]
18239                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18240                            multibuffer
18241                                .all_buffers()
18242                                .into_iter()
18243                                .filter_map(|buffer| {
18244                                    buffer.update(cx, |buffer, cx| {
18245                                        let language = buffer.language()?;
18246                                        let should_discard = project.update(cx, |project, cx| {
18247                                            project.is_local()
18248                                                && !project.has_language_servers_for(buffer, cx)
18249                                        });
18250                                        should_discard.not().then_some(language.clone())
18251                                    })
18252                                })
18253                                .collect::<HashSet<_>>()
18254                        });
18255                        if !languages_affected.is_empty() {
18256                            self.refresh_inlay_hints(
18257                                InlayHintRefreshReason::BufferEdited(languages_affected),
18258                                cx,
18259                            );
18260                        }
18261                    }
18262                }
18263
18264                let Some(project) = &self.project else { return };
18265                let (telemetry, is_via_ssh) = {
18266                    let project = project.read(cx);
18267                    let telemetry = project.client().telemetry().clone();
18268                    let is_via_ssh = project.is_via_ssh();
18269                    (telemetry, is_via_ssh)
18270                };
18271                refresh_linked_ranges(self, window, cx);
18272                telemetry.log_edit_event("editor", is_via_ssh);
18273            }
18274            multi_buffer::Event::ExcerptsAdded {
18275                buffer,
18276                predecessor,
18277                excerpts,
18278            } => {
18279                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18280                let buffer_id = buffer.read(cx).remote_id();
18281                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18282                    if let Some(project) = &self.project {
18283                        update_uncommitted_diff_for_buffer(
18284                            cx.entity(),
18285                            project,
18286                            [buffer.clone()],
18287                            self.buffer.clone(),
18288                            cx,
18289                        )
18290                        .detach();
18291                    }
18292                }
18293                cx.emit(EditorEvent::ExcerptsAdded {
18294                    buffer: buffer.clone(),
18295                    predecessor: *predecessor,
18296                    excerpts: excerpts.clone(),
18297                });
18298                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18299            }
18300            multi_buffer::Event::ExcerptsRemoved {
18301                ids,
18302                removed_buffer_ids,
18303            } => {
18304                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18305                let buffer = self.buffer.read(cx);
18306                self.registered_buffers
18307                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18308                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18309                cx.emit(EditorEvent::ExcerptsRemoved {
18310                    ids: ids.clone(),
18311                    removed_buffer_ids: removed_buffer_ids.clone(),
18312                })
18313            }
18314            multi_buffer::Event::ExcerptsEdited {
18315                excerpt_ids,
18316                buffer_ids,
18317            } => {
18318                self.display_map.update(cx, |map, cx| {
18319                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18320                });
18321                cx.emit(EditorEvent::ExcerptsEdited {
18322                    ids: excerpt_ids.clone(),
18323                })
18324            }
18325            multi_buffer::Event::ExcerptsExpanded { ids } => {
18326                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18327                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18328            }
18329            multi_buffer::Event::Reparsed(buffer_id) => {
18330                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18331                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18332
18333                cx.emit(EditorEvent::Reparsed(*buffer_id));
18334            }
18335            multi_buffer::Event::DiffHunksToggled => {
18336                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18337            }
18338            multi_buffer::Event::LanguageChanged(buffer_id) => {
18339                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18340                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18341                cx.emit(EditorEvent::Reparsed(*buffer_id));
18342                cx.notify();
18343            }
18344            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18345            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18346            multi_buffer::Event::FileHandleChanged
18347            | multi_buffer::Event::Reloaded
18348            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18349            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18350            multi_buffer::Event::DiagnosticsUpdated => {
18351                self.refresh_active_diagnostics(cx);
18352                self.refresh_inline_diagnostics(true, window, cx);
18353                self.scrollbar_marker_state.dirty = true;
18354                cx.notify();
18355            }
18356            _ => {}
18357        };
18358    }
18359
18360    pub fn start_temporary_diff_override(&mut self) {
18361        self.load_diff_task.take();
18362        self.temporary_diff_override = true;
18363    }
18364
18365    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18366        self.temporary_diff_override = false;
18367        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18368        self.buffer.update(cx, |buffer, cx| {
18369            buffer.set_all_diff_hunks_collapsed(cx);
18370        });
18371
18372        if let Some(project) = self.project.clone() {
18373            self.load_diff_task = Some(
18374                update_uncommitted_diff_for_buffer(
18375                    cx.entity(),
18376                    &project,
18377                    self.buffer.read(cx).all_buffers(),
18378                    self.buffer.clone(),
18379                    cx,
18380                )
18381                .shared(),
18382            );
18383        }
18384    }
18385
18386    fn on_display_map_changed(
18387        &mut self,
18388        _: Entity<DisplayMap>,
18389        _: &mut Window,
18390        cx: &mut Context<Self>,
18391    ) {
18392        cx.notify();
18393    }
18394
18395    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18396        let new_severity = if self.diagnostics_enabled() {
18397            EditorSettings::get_global(cx)
18398                .diagnostics_max_severity
18399                .unwrap_or(DiagnosticSeverity::Hint)
18400        } else {
18401            DiagnosticSeverity::Off
18402        };
18403        self.set_max_diagnostics_severity(new_severity, cx);
18404        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18405        self.update_edit_prediction_settings(cx);
18406        self.refresh_inline_completion(true, false, window, cx);
18407        self.refresh_inlay_hints(
18408            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18409                self.selections.newest_anchor().head(),
18410                &self.buffer.read(cx).snapshot(cx),
18411                cx,
18412            )),
18413            cx,
18414        );
18415
18416        let old_cursor_shape = self.cursor_shape;
18417
18418        {
18419            let editor_settings = EditorSettings::get_global(cx);
18420            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18421            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18422            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18423            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18424        }
18425
18426        if old_cursor_shape != self.cursor_shape {
18427            cx.emit(EditorEvent::CursorShapeChanged);
18428        }
18429
18430        let project_settings = ProjectSettings::get_global(cx);
18431        self.serialize_dirty_buffers =
18432            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18433
18434        if self.mode.is_full() {
18435            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18436            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18437            if self.show_inline_diagnostics != show_inline_diagnostics {
18438                self.show_inline_diagnostics = show_inline_diagnostics;
18439                self.refresh_inline_diagnostics(false, window, cx);
18440            }
18441
18442            if self.git_blame_inline_enabled != inline_blame_enabled {
18443                self.toggle_git_blame_inline_internal(false, window, cx);
18444            }
18445
18446            let minimap_settings = EditorSettings::get_global(cx).minimap;
18447            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18448                self.set_minimap_visibility(
18449                    self.minimap_visibility.toggle_visibility(),
18450                    window,
18451                    cx,
18452                );
18453            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18454                minimap_entity.update(cx, |minimap_editor, cx| {
18455                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18456                })
18457            }
18458        }
18459
18460        cx.notify();
18461    }
18462
18463    pub fn set_searchable(&mut self, searchable: bool) {
18464        self.searchable = searchable;
18465    }
18466
18467    pub fn searchable(&self) -> bool {
18468        self.searchable
18469    }
18470
18471    fn open_proposed_changes_editor(
18472        &mut self,
18473        _: &OpenProposedChangesEditor,
18474        window: &mut Window,
18475        cx: &mut Context<Self>,
18476    ) {
18477        let Some(workspace) = self.workspace() else {
18478            cx.propagate();
18479            return;
18480        };
18481
18482        let selections = self.selections.all::<usize>(cx);
18483        let multi_buffer = self.buffer.read(cx);
18484        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18485        let mut new_selections_by_buffer = HashMap::default();
18486        for selection in selections {
18487            for (buffer, range, _) in
18488                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18489            {
18490                let mut range = range.to_point(buffer);
18491                range.start.column = 0;
18492                range.end.column = buffer.line_len(range.end.row);
18493                new_selections_by_buffer
18494                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18495                    .or_insert(Vec::new())
18496                    .push(range)
18497            }
18498        }
18499
18500        let proposed_changes_buffers = new_selections_by_buffer
18501            .into_iter()
18502            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18503            .collect::<Vec<_>>();
18504        let proposed_changes_editor = cx.new(|cx| {
18505            ProposedChangesEditor::new(
18506                "Proposed changes",
18507                proposed_changes_buffers,
18508                self.project.clone(),
18509                window,
18510                cx,
18511            )
18512        });
18513
18514        window.defer(cx, move |window, cx| {
18515            workspace.update(cx, |workspace, cx| {
18516                workspace.active_pane().update(cx, |pane, cx| {
18517                    pane.add_item(
18518                        Box::new(proposed_changes_editor),
18519                        true,
18520                        true,
18521                        None,
18522                        window,
18523                        cx,
18524                    );
18525                });
18526            });
18527        });
18528    }
18529
18530    pub fn open_excerpts_in_split(
18531        &mut self,
18532        _: &OpenExcerptsSplit,
18533        window: &mut Window,
18534        cx: &mut Context<Self>,
18535    ) {
18536        self.open_excerpts_common(None, true, window, cx)
18537    }
18538
18539    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18540        self.open_excerpts_common(None, false, window, cx)
18541    }
18542
18543    fn open_excerpts_common(
18544        &mut self,
18545        jump_data: Option<JumpData>,
18546        split: bool,
18547        window: &mut Window,
18548        cx: &mut Context<Self>,
18549    ) {
18550        let Some(workspace) = self.workspace() else {
18551            cx.propagate();
18552            return;
18553        };
18554
18555        if self.buffer.read(cx).is_singleton() {
18556            cx.propagate();
18557            return;
18558        }
18559
18560        let mut new_selections_by_buffer = HashMap::default();
18561        match &jump_data {
18562            Some(JumpData::MultiBufferPoint {
18563                excerpt_id,
18564                position,
18565                anchor,
18566                line_offset_from_top,
18567            }) => {
18568                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18569                if let Some(buffer) = multi_buffer_snapshot
18570                    .buffer_id_for_excerpt(*excerpt_id)
18571                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18572                {
18573                    let buffer_snapshot = buffer.read(cx).snapshot();
18574                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18575                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18576                    } else {
18577                        buffer_snapshot.clip_point(*position, Bias::Left)
18578                    };
18579                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18580                    new_selections_by_buffer.insert(
18581                        buffer,
18582                        (
18583                            vec![jump_to_offset..jump_to_offset],
18584                            Some(*line_offset_from_top),
18585                        ),
18586                    );
18587                }
18588            }
18589            Some(JumpData::MultiBufferRow {
18590                row,
18591                line_offset_from_top,
18592            }) => {
18593                let point = MultiBufferPoint::new(row.0, 0);
18594                if let Some((buffer, buffer_point, _)) =
18595                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18596                {
18597                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18598                    new_selections_by_buffer
18599                        .entry(buffer)
18600                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18601                        .0
18602                        .push(buffer_offset..buffer_offset)
18603                }
18604            }
18605            None => {
18606                let selections = self.selections.all::<usize>(cx);
18607                let multi_buffer = self.buffer.read(cx);
18608                for selection in selections {
18609                    for (snapshot, range, _, anchor) in multi_buffer
18610                        .snapshot(cx)
18611                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18612                    {
18613                        if let Some(anchor) = anchor {
18614                            // selection is in a deleted hunk
18615                            let Some(buffer_id) = anchor.buffer_id else {
18616                                continue;
18617                            };
18618                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18619                                continue;
18620                            };
18621                            let offset = text::ToOffset::to_offset(
18622                                &anchor.text_anchor,
18623                                &buffer_handle.read(cx).snapshot(),
18624                            );
18625                            let range = offset..offset;
18626                            new_selections_by_buffer
18627                                .entry(buffer_handle)
18628                                .or_insert((Vec::new(), None))
18629                                .0
18630                                .push(range)
18631                        } else {
18632                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18633                            else {
18634                                continue;
18635                            };
18636                            new_selections_by_buffer
18637                                .entry(buffer_handle)
18638                                .or_insert((Vec::new(), None))
18639                                .0
18640                                .push(range)
18641                        }
18642                    }
18643                }
18644            }
18645        }
18646
18647        new_selections_by_buffer
18648            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18649
18650        if new_selections_by_buffer.is_empty() {
18651            return;
18652        }
18653
18654        // We defer the pane interaction because we ourselves are a workspace item
18655        // and activating a new item causes the pane to call a method on us reentrantly,
18656        // which panics if we're on the stack.
18657        window.defer(cx, move |window, cx| {
18658            workspace.update(cx, |workspace, cx| {
18659                let pane = if split {
18660                    workspace.adjacent_pane(window, cx)
18661                } else {
18662                    workspace.active_pane().clone()
18663                };
18664
18665                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18666                    let editor = buffer
18667                        .read(cx)
18668                        .file()
18669                        .is_none()
18670                        .then(|| {
18671                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18672                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18673                            // Instead, we try to activate the existing editor in the pane first.
18674                            let (editor, pane_item_index) =
18675                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18676                                    let editor = item.downcast::<Editor>()?;
18677                                    let singleton_buffer =
18678                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18679                                    if singleton_buffer == buffer {
18680                                        Some((editor, i))
18681                                    } else {
18682                                        None
18683                                    }
18684                                })?;
18685                            pane.update(cx, |pane, cx| {
18686                                pane.activate_item(pane_item_index, true, true, window, cx)
18687                            });
18688                            Some(editor)
18689                        })
18690                        .flatten()
18691                        .unwrap_or_else(|| {
18692                            workspace.open_project_item::<Self>(
18693                                pane.clone(),
18694                                buffer,
18695                                true,
18696                                true,
18697                                window,
18698                                cx,
18699                            )
18700                        });
18701
18702                    editor.update(cx, |editor, cx| {
18703                        let autoscroll = match scroll_offset {
18704                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18705                            None => Autoscroll::newest(),
18706                        };
18707                        let nav_history = editor.nav_history.take();
18708                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18709                            s.select_ranges(ranges);
18710                        });
18711                        editor.nav_history = nav_history;
18712                    });
18713                }
18714            })
18715        });
18716    }
18717
18718    // For now, don't allow opening excerpts in buffers that aren't backed by
18719    // regular project files.
18720    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18721        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18722    }
18723
18724    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18725        let snapshot = self.buffer.read(cx).read(cx);
18726        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18727        Some(
18728            ranges
18729                .iter()
18730                .map(move |range| {
18731                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18732                })
18733                .collect(),
18734        )
18735    }
18736
18737    fn selection_replacement_ranges(
18738        &self,
18739        range: Range<OffsetUtf16>,
18740        cx: &mut App,
18741    ) -> Vec<Range<OffsetUtf16>> {
18742        let selections = self.selections.all::<OffsetUtf16>(cx);
18743        let newest_selection = selections
18744            .iter()
18745            .max_by_key(|selection| selection.id)
18746            .unwrap();
18747        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18748        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18749        let snapshot = self.buffer.read(cx).read(cx);
18750        selections
18751            .into_iter()
18752            .map(|mut selection| {
18753                selection.start.0 =
18754                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18755                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18756                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18757                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18758            })
18759            .collect()
18760    }
18761
18762    fn report_editor_event(
18763        &self,
18764        event_type: &'static str,
18765        file_extension: Option<String>,
18766        cx: &App,
18767    ) {
18768        if cfg!(any(test, feature = "test-support")) {
18769            return;
18770        }
18771
18772        let Some(project) = &self.project else { return };
18773
18774        // If None, we are in a file without an extension
18775        let file = self
18776            .buffer
18777            .read(cx)
18778            .as_singleton()
18779            .and_then(|b| b.read(cx).file());
18780        let file_extension = file_extension.or(file
18781            .as_ref()
18782            .and_then(|file| Path::new(file.file_name(cx)).extension())
18783            .and_then(|e| e.to_str())
18784            .map(|a| a.to_string()));
18785
18786        let vim_mode = vim_enabled(cx);
18787
18788        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18789        let copilot_enabled = edit_predictions_provider
18790            == language::language_settings::EditPredictionProvider::Copilot;
18791        let copilot_enabled_for_language = self
18792            .buffer
18793            .read(cx)
18794            .language_settings(cx)
18795            .show_edit_predictions;
18796
18797        let project = project.read(cx);
18798        telemetry::event!(
18799            event_type,
18800            file_extension,
18801            vim_mode,
18802            copilot_enabled,
18803            copilot_enabled_for_language,
18804            edit_predictions_provider,
18805            is_via_ssh = project.is_via_ssh(),
18806        );
18807    }
18808
18809    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18810    /// with each line being an array of {text, highlight} objects.
18811    fn copy_highlight_json(
18812        &mut self,
18813        _: &CopyHighlightJson,
18814        window: &mut Window,
18815        cx: &mut Context<Self>,
18816    ) {
18817        #[derive(Serialize)]
18818        struct Chunk<'a> {
18819            text: String,
18820            highlight: Option<&'a str>,
18821        }
18822
18823        let snapshot = self.buffer.read(cx).snapshot(cx);
18824        let range = self
18825            .selected_text_range(false, window, cx)
18826            .and_then(|selection| {
18827                if selection.range.is_empty() {
18828                    None
18829                } else {
18830                    Some(selection.range)
18831                }
18832            })
18833            .unwrap_or_else(|| 0..snapshot.len());
18834
18835        let chunks = snapshot.chunks(range, true);
18836        let mut lines = Vec::new();
18837        let mut line: VecDeque<Chunk> = VecDeque::new();
18838
18839        let Some(style) = self.style.as_ref() else {
18840            return;
18841        };
18842
18843        for chunk in chunks {
18844            let highlight = chunk
18845                .syntax_highlight_id
18846                .and_then(|id| id.name(&style.syntax));
18847            let mut chunk_lines = chunk.text.split('\n').peekable();
18848            while let Some(text) = chunk_lines.next() {
18849                let mut merged_with_last_token = false;
18850                if let Some(last_token) = line.back_mut() {
18851                    if last_token.highlight == highlight {
18852                        last_token.text.push_str(text);
18853                        merged_with_last_token = true;
18854                    }
18855                }
18856
18857                if !merged_with_last_token {
18858                    line.push_back(Chunk {
18859                        text: text.into(),
18860                        highlight,
18861                    });
18862                }
18863
18864                if chunk_lines.peek().is_some() {
18865                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18866                        line.pop_front();
18867                    }
18868                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18869                        line.pop_back();
18870                    }
18871
18872                    lines.push(mem::take(&mut line));
18873                }
18874            }
18875        }
18876
18877        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18878            return;
18879        };
18880        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18881    }
18882
18883    pub fn open_context_menu(
18884        &mut self,
18885        _: &OpenContextMenu,
18886        window: &mut Window,
18887        cx: &mut Context<Self>,
18888    ) {
18889        self.request_autoscroll(Autoscroll::newest(), cx);
18890        let position = self.selections.newest_display(cx).start;
18891        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18892    }
18893
18894    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18895        &self.inlay_hint_cache
18896    }
18897
18898    pub fn replay_insert_event(
18899        &mut self,
18900        text: &str,
18901        relative_utf16_range: Option<Range<isize>>,
18902        window: &mut Window,
18903        cx: &mut Context<Self>,
18904    ) {
18905        if !self.input_enabled {
18906            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18907            return;
18908        }
18909        if let Some(relative_utf16_range) = relative_utf16_range {
18910            let selections = self.selections.all::<OffsetUtf16>(cx);
18911            self.change_selections(None, window, cx, |s| {
18912                let new_ranges = selections.into_iter().map(|range| {
18913                    let start = OffsetUtf16(
18914                        range
18915                            .head()
18916                            .0
18917                            .saturating_add_signed(relative_utf16_range.start),
18918                    );
18919                    let end = OffsetUtf16(
18920                        range
18921                            .head()
18922                            .0
18923                            .saturating_add_signed(relative_utf16_range.end),
18924                    );
18925                    start..end
18926                });
18927                s.select_ranges(new_ranges);
18928            });
18929        }
18930
18931        self.handle_input(text, window, cx);
18932    }
18933
18934    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18935        let Some(provider) = self.semantics_provider.as_ref() else {
18936            return false;
18937        };
18938
18939        let mut supports = false;
18940        self.buffer().update(cx, |this, cx| {
18941            this.for_each_buffer(|buffer| {
18942                supports |= provider.supports_inlay_hints(buffer, cx);
18943            });
18944        });
18945
18946        supports
18947    }
18948
18949    pub fn is_focused(&self, window: &Window) -> bool {
18950        self.focus_handle.is_focused(window)
18951    }
18952
18953    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18954        cx.emit(EditorEvent::Focused);
18955
18956        if let Some(descendant) = self
18957            .last_focused_descendant
18958            .take()
18959            .and_then(|descendant| descendant.upgrade())
18960        {
18961            window.focus(&descendant);
18962        } else {
18963            if let Some(blame) = self.blame.as_ref() {
18964                blame.update(cx, GitBlame::focus)
18965            }
18966
18967            self.blink_manager.update(cx, BlinkManager::enable);
18968            self.show_cursor_names(window, cx);
18969            self.buffer.update(cx, |buffer, cx| {
18970                buffer.finalize_last_transaction(cx);
18971                if self.leader_id.is_none() {
18972                    buffer.set_active_selections(
18973                        &self.selections.disjoint_anchors(),
18974                        self.selections.line_mode,
18975                        self.cursor_shape,
18976                        cx,
18977                    );
18978                }
18979            });
18980        }
18981    }
18982
18983    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18984        cx.emit(EditorEvent::FocusedIn)
18985    }
18986
18987    fn handle_focus_out(
18988        &mut self,
18989        event: FocusOutEvent,
18990        _window: &mut Window,
18991        cx: &mut Context<Self>,
18992    ) {
18993        if event.blurred != self.focus_handle {
18994            self.last_focused_descendant = Some(event.blurred);
18995        }
18996        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18997    }
18998
18999    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19000        self.blink_manager.update(cx, BlinkManager::disable);
19001        self.buffer
19002            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19003
19004        if let Some(blame) = self.blame.as_ref() {
19005            blame.update(cx, GitBlame::blur)
19006        }
19007        if !self.hover_state.focused(window, cx) {
19008            hide_hover(self, cx);
19009        }
19010        if !self
19011            .context_menu
19012            .borrow()
19013            .as_ref()
19014            .is_some_and(|context_menu| context_menu.focused(window, cx))
19015        {
19016            self.hide_context_menu(window, cx);
19017        }
19018        self.discard_inline_completion(false, cx);
19019        cx.emit(EditorEvent::Blurred);
19020        cx.notify();
19021    }
19022
19023    pub fn register_action<A: Action>(
19024        &mut self,
19025        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19026    ) -> Subscription {
19027        let id = self.next_editor_action_id.post_inc();
19028        let listener = Arc::new(listener);
19029        self.editor_actions.borrow_mut().insert(
19030            id,
19031            Box::new(move |window, _| {
19032                let listener = listener.clone();
19033                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19034                    let action = action.downcast_ref().unwrap();
19035                    if phase == DispatchPhase::Bubble {
19036                        listener(action, window, cx)
19037                    }
19038                })
19039            }),
19040        );
19041
19042        let editor_actions = self.editor_actions.clone();
19043        Subscription::new(move || {
19044            editor_actions.borrow_mut().remove(&id);
19045        })
19046    }
19047
19048    pub fn file_header_size(&self) -> u32 {
19049        FILE_HEADER_HEIGHT
19050    }
19051
19052    pub fn restore(
19053        &mut self,
19054        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19055        window: &mut Window,
19056        cx: &mut Context<Self>,
19057    ) {
19058        let workspace = self.workspace();
19059        let project = self.project.as_ref();
19060        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19061            let mut tasks = Vec::new();
19062            for (buffer_id, changes) in revert_changes {
19063                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19064                    buffer.update(cx, |buffer, cx| {
19065                        buffer.edit(
19066                            changes
19067                                .into_iter()
19068                                .map(|(range, text)| (range, text.to_string())),
19069                            None,
19070                            cx,
19071                        );
19072                    });
19073
19074                    if let Some(project) =
19075                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19076                    {
19077                        project.update(cx, |project, cx| {
19078                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19079                        })
19080                    }
19081                }
19082            }
19083            tasks
19084        });
19085        cx.spawn_in(window, async move |_, cx| {
19086            for (buffer, task) in save_tasks {
19087                let result = task.await;
19088                if result.is_err() {
19089                    let Some(path) = buffer
19090                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19091                        .ok()
19092                    else {
19093                        continue;
19094                    };
19095                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19096                        let Some(task) = cx
19097                            .update_window_entity(&workspace, |workspace, window, cx| {
19098                                workspace
19099                                    .open_path_preview(path, None, false, false, false, window, cx)
19100                            })
19101                            .ok()
19102                        else {
19103                            continue;
19104                        };
19105                        task.await.log_err();
19106                    }
19107                }
19108            }
19109        })
19110        .detach();
19111        self.change_selections(None, window, cx, |selections| selections.refresh());
19112    }
19113
19114    pub fn to_pixel_point(
19115        &self,
19116        source: multi_buffer::Anchor,
19117        editor_snapshot: &EditorSnapshot,
19118        window: &mut Window,
19119    ) -> Option<gpui::Point<Pixels>> {
19120        let source_point = source.to_display_point(editor_snapshot);
19121        self.display_to_pixel_point(source_point, editor_snapshot, window)
19122    }
19123
19124    pub fn display_to_pixel_point(
19125        &self,
19126        source: DisplayPoint,
19127        editor_snapshot: &EditorSnapshot,
19128        window: &mut Window,
19129    ) -> Option<gpui::Point<Pixels>> {
19130        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19131        let text_layout_details = self.text_layout_details(window);
19132        let scroll_top = text_layout_details
19133            .scroll_anchor
19134            .scroll_position(editor_snapshot)
19135            .y;
19136
19137        if source.row().as_f32() < scroll_top.floor() {
19138            return None;
19139        }
19140        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19141        let source_y = line_height * (source.row().as_f32() - scroll_top);
19142        Some(gpui::Point::new(source_x, source_y))
19143    }
19144
19145    pub fn has_visible_completions_menu(&self) -> bool {
19146        !self.edit_prediction_preview_is_active()
19147            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19148                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19149            })
19150    }
19151
19152    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19153        if self.mode.is_minimap() {
19154            return;
19155        }
19156        self.addons
19157            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19158    }
19159
19160    pub fn unregister_addon<T: Addon>(&mut self) {
19161        self.addons.remove(&std::any::TypeId::of::<T>());
19162    }
19163
19164    pub fn addon<T: Addon>(&self) -> Option<&T> {
19165        let type_id = std::any::TypeId::of::<T>();
19166        self.addons
19167            .get(&type_id)
19168            .and_then(|item| item.to_any().downcast_ref::<T>())
19169    }
19170
19171    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19172        let type_id = std::any::TypeId::of::<T>();
19173        self.addons
19174            .get_mut(&type_id)
19175            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19176    }
19177
19178    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19179        let text_layout_details = self.text_layout_details(window);
19180        let style = &text_layout_details.editor_style;
19181        let font_id = window.text_system().resolve_font(&style.text.font());
19182        let font_size = style.text.font_size.to_pixels(window.rem_size());
19183        let line_height = style.text.line_height_in_pixels(window.rem_size());
19184        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19185
19186        gpui::Size::new(em_width, line_height)
19187    }
19188
19189    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19190        self.load_diff_task.clone()
19191    }
19192
19193    fn read_metadata_from_db(
19194        &mut self,
19195        item_id: u64,
19196        workspace_id: WorkspaceId,
19197        window: &mut Window,
19198        cx: &mut Context<Editor>,
19199    ) {
19200        if self.is_singleton(cx)
19201            && !self.mode.is_minimap()
19202            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19203        {
19204            let buffer_snapshot = OnceCell::new();
19205
19206            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19207                if !folds.is_empty() {
19208                    let snapshot =
19209                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19210                    self.fold_ranges(
19211                        folds
19212                            .into_iter()
19213                            .map(|(start, end)| {
19214                                snapshot.clip_offset(start, Bias::Left)
19215                                    ..snapshot.clip_offset(end, Bias::Right)
19216                            })
19217                            .collect(),
19218                        false,
19219                        window,
19220                        cx,
19221                    );
19222                }
19223            }
19224
19225            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19226                if !selections.is_empty() {
19227                    let snapshot =
19228                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19229                    self.change_selections(None, window, cx, |s| {
19230                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19231                            snapshot.clip_offset(start, Bias::Left)
19232                                ..snapshot.clip_offset(end, Bias::Right)
19233                        }));
19234                    });
19235                }
19236            };
19237        }
19238
19239        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19240    }
19241}
19242
19243fn vim_enabled(cx: &App) -> bool {
19244    cx.global::<SettingsStore>()
19245        .raw_user_settings()
19246        .get("vim_mode")
19247        == Some(&serde_json::Value::Bool(true))
19248}
19249
19250// Consider user intent and default settings
19251fn choose_completion_range(
19252    completion: &Completion,
19253    intent: CompletionIntent,
19254    buffer: &Entity<Buffer>,
19255    cx: &mut Context<Editor>,
19256) -> Range<usize> {
19257    fn should_replace(
19258        completion: &Completion,
19259        insert_range: &Range<text::Anchor>,
19260        intent: CompletionIntent,
19261        completion_mode_setting: LspInsertMode,
19262        buffer: &Buffer,
19263    ) -> bool {
19264        // specific actions take precedence over settings
19265        match intent {
19266            CompletionIntent::CompleteWithInsert => return false,
19267            CompletionIntent::CompleteWithReplace => return true,
19268            CompletionIntent::Complete | CompletionIntent::Compose => {}
19269        }
19270
19271        match completion_mode_setting {
19272            LspInsertMode::Insert => false,
19273            LspInsertMode::Replace => true,
19274            LspInsertMode::ReplaceSubsequence => {
19275                let mut text_to_replace = buffer.chars_for_range(
19276                    buffer.anchor_before(completion.replace_range.start)
19277                        ..buffer.anchor_after(completion.replace_range.end),
19278                );
19279                let mut completion_text = completion.new_text.chars();
19280
19281                // is `text_to_replace` a subsequence of `completion_text`
19282                text_to_replace
19283                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19284            }
19285            LspInsertMode::ReplaceSuffix => {
19286                let range_after_cursor = insert_range.end..completion.replace_range.end;
19287
19288                let text_after_cursor = buffer
19289                    .text_for_range(
19290                        buffer.anchor_before(range_after_cursor.start)
19291                            ..buffer.anchor_after(range_after_cursor.end),
19292                    )
19293                    .collect::<String>();
19294                completion.new_text.ends_with(&text_after_cursor)
19295            }
19296        }
19297    }
19298
19299    let buffer = buffer.read(cx);
19300
19301    if let CompletionSource::Lsp {
19302        insert_range: Some(insert_range),
19303        ..
19304    } = &completion.source
19305    {
19306        let completion_mode_setting =
19307            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19308                .completions
19309                .lsp_insert_mode;
19310
19311        if !should_replace(
19312            completion,
19313            &insert_range,
19314            intent,
19315            completion_mode_setting,
19316            buffer,
19317        ) {
19318            return insert_range.to_offset(buffer);
19319        }
19320    }
19321
19322    completion.replace_range.to_offset(buffer)
19323}
19324
19325fn insert_extra_newline_brackets(
19326    buffer: &MultiBufferSnapshot,
19327    range: Range<usize>,
19328    language: &language::LanguageScope,
19329) -> bool {
19330    let leading_whitespace_len = buffer
19331        .reversed_chars_at(range.start)
19332        .take_while(|c| c.is_whitespace() && *c != '\n')
19333        .map(|c| c.len_utf8())
19334        .sum::<usize>();
19335    let trailing_whitespace_len = buffer
19336        .chars_at(range.end)
19337        .take_while(|c| c.is_whitespace() && *c != '\n')
19338        .map(|c| c.len_utf8())
19339        .sum::<usize>();
19340    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19341
19342    language.brackets().any(|(pair, enabled)| {
19343        let pair_start = pair.start.trim_end();
19344        let pair_end = pair.end.trim_start();
19345
19346        enabled
19347            && pair.newline
19348            && buffer.contains_str_at(range.end, pair_end)
19349            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19350    })
19351}
19352
19353fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19354    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19355        [(buffer, range, _)] => (*buffer, range.clone()),
19356        _ => return false,
19357    };
19358    let pair = {
19359        let mut result: Option<BracketMatch> = None;
19360
19361        for pair in buffer
19362            .all_bracket_ranges(range.clone())
19363            .filter(move |pair| {
19364                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19365            })
19366        {
19367            let len = pair.close_range.end - pair.open_range.start;
19368
19369            if let Some(existing) = &result {
19370                let existing_len = existing.close_range.end - existing.open_range.start;
19371                if len > existing_len {
19372                    continue;
19373                }
19374            }
19375
19376            result = Some(pair);
19377        }
19378
19379        result
19380    };
19381    let Some(pair) = pair else {
19382        return false;
19383    };
19384    pair.newline_only
19385        && buffer
19386            .chars_for_range(pair.open_range.end..range.start)
19387            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19388            .all(|c| c.is_whitespace() && c != '\n')
19389}
19390
19391fn update_uncommitted_diff_for_buffer(
19392    editor: Entity<Editor>,
19393    project: &Entity<Project>,
19394    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19395    buffer: Entity<MultiBuffer>,
19396    cx: &mut App,
19397) -> Task<()> {
19398    let mut tasks = Vec::new();
19399    project.update(cx, |project, cx| {
19400        for buffer in buffers {
19401            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19402                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19403            }
19404        }
19405    });
19406    cx.spawn(async move |cx| {
19407        let diffs = future::join_all(tasks).await;
19408        if editor
19409            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19410            .unwrap_or(false)
19411        {
19412            return;
19413        }
19414
19415        buffer
19416            .update(cx, |buffer, cx| {
19417                for diff in diffs.into_iter().flatten() {
19418                    buffer.add_diff(diff, cx);
19419                }
19420            })
19421            .ok();
19422    })
19423}
19424
19425fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19426    let tab_size = tab_size.get() as usize;
19427    let mut width = offset;
19428
19429    for ch in text.chars() {
19430        width += if ch == '\t' {
19431            tab_size - (width % tab_size)
19432        } else {
19433            1
19434        };
19435    }
19436
19437    width - offset
19438}
19439
19440#[cfg(test)]
19441mod tests {
19442    use super::*;
19443
19444    #[test]
19445    fn test_string_size_with_expanded_tabs() {
19446        let nz = |val| NonZeroU32::new(val).unwrap();
19447        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19448        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19449        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19450        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19451        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19452        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19453        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19454        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19455    }
19456}
19457
19458/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19459struct WordBreakingTokenizer<'a> {
19460    input: &'a str,
19461}
19462
19463impl<'a> WordBreakingTokenizer<'a> {
19464    fn new(input: &'a str) -> Self {
19465        Self { input }
19466    }
19467}
19468
19469fn is_char_ideographic(ch: char) -> bool {
19470    use unicode_script::Script::*;
19471    use unicode_script::UnicodeScript;
19472    matches!(ch.script(), Han | Tangut | Yi)
19473}
19474
19475fn is_grapheme_ideographic(text: &str) -> bool {
19476    text.chars().any(is_char_ideographic)
19477}
19478
19479fn is_grapheme_whitespace(text: &str) -> bool {
19480    text.chars().any(|x| x.is_whitespace())
19481}
19482
19483fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19484    text.chars().next().map_or(false, |ch| {
19485        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19486    })
19487}
19488
19489#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19490enum WordBreakToken<'a> {
19491    Word { token: &'a str, grapheme_len: usize },
19492    InlineWhitespace { token: &'a str, grapheme_len: usize },
19493    Newline,
19494}
19495
19496impl<'a> Iterator for WordBreakingTokenizer<'a> {
19497    /// Yields a span, the count of graphemes in the token, and whether it was
19498    /// whitespace. Note that it also breaks at word boundaries.
19499    type Item = WordBreakToken<'a>;
19500
19501    fn next(&mut self) -> Option<Self::Item> {
19502        use unicode_segmentation::UnicodeSegmentation;
19503        if self.input.is_empty() {
19504            return None;
19505        }
19506
19507        let mut iter = self.input.graphemes(true).peekable();
19508        let mut offset = 0;
19509        let mut grapheme_len = 0;
19510        if let Some(first_grapheme) = iter.next() {
19511            let is_newline = first_grapheme == "\n";
19512            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19513            offset += first_grapheme.len();
19514            grapheme_len += 1;
19515            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19516                if let Some(grapheme) = iter.peek().copied() {
19517                    if should_stay_with_preceding_ideograph(grapheme) {
19518                        offset += grapheme.len();
19519                        grapheme_len += 1;
19520                    }
19521                }
19522            } else {
19523                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19524                let mut next_word_bound = words.peek().copied();
19525                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19526                    next_word_bound = words.next();
19527                }
19528                while let Some(grapheme) = iter.peek().copied() {
19529                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19530                        break;
19531                    };
19532                    if is_grapheme_whitespace(grapheme) != is_whitespace
19533                        || (grapheme == "\n") != is_newline
19534                    {
19535                        break;
19536                    };
19537                    offset += grapheme.len();
19538                    grapheme_len += 1;
19539                    iter.next();
19540                }
19541            }
19542            let token = &self.input[..offset];
19543            self.input = &self.input[offset..];
19544            if token == "\n" {
19545                Some(WordBreakToken::Newline)
19546            } else if is_whitespace {
19547                Some(WordBreakToken::InlineWhitespace {
19548                    token,
19549                    grapheme_len,
19550                })
19551            } else {
19552                Some(WordBreakToken::Word {
19553                    token,
19554                    grapheme_len,
19555                })
19556            }
19557        } else {
19558            None
19559        }
19560    }
19561}
19562
19563#[test]
19564fn test_word_breaking_tokenizer() {
19565    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19566        ("", &[]),
19567        ("  ", &[whitespace("  ", 2)]),
19568        ("Ʒ", &[word("Ʒ", 1)]),
19569        ("Ǽ", &[word("Ǽ", 1)]),
19570        ("", &[word("", 1)]),
19571        ("⋑⋑", &[word("⋑⋑", 2)]),
19572        (
19573            "原理,进而",
19574            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19575        ),
19576        (
19577            "hello world",
19578            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19579        ),
19580        (
19581            "hello, world",
19582            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19583        ),
19584        (
19585            "  hello world",
19586            &[
19587                whitespace("  ", 2),
19588                word("hello", 5),
19589                whitespace(" ", 1),
19590                word("world", 5),
19591            ],
19592        ),
19593        (
19594            "这是什么 \n 钢笔",
19595            &[
19596                word("", 1),
19597                word("", 1),
19598                word("", 1),
19599                word("", 1),
19600                whitespace(" ", 1),
19601                newline(),
19602                whitespace(" ", 1),
19603                word("", 1),
19604                word("", 1),
19605            ],
19606        ),
19607        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19608    ];
19609
19610    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19611        WordBreakToken::Word {
19612            token,
19613            grapheme_len,
19614        }
19615    }
19616
19617    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19618        WordBreakToken::InlineWhitespace {
19619            token,
19620            grapheme_len,
19621        }
19622    }
19623
19624    fn newline() -> WordBreakToken<'static> {
19625        WordBreakToken::Newline
19626    }
19627
19628    for (input, result) in tests {
19629        assert_eq!(
19630            WordBreakingTokenizer::new(input)
19631                .collect::<Vec<_>>()
19632                .as_slice(),
19633            *result,
19634        );
19635    }
19636}
19637
19638fn wrap_with_prefix(
19639    line_prefix: String,
19640    unwrapped_text: String,
19641    wrap_column: usize,
19642    tab_size: NonZeroU32,
19643    preserve_existing_whitespace: bool,
19644) -> String {
19645    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19646    let mut wrapped_text = String::new();
19647    let mut current_line = line_prefix.clone();
19648
19649    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19650    let mut current_line_len = line_prefix_len;
19651    let mut in_whitespace = false;
19652    for token in tokenizer {
19653        let have_preceding_whitespace = in_whitespace;
19654        match token {
19655            WordBreakToken::Word {
19656                token,
19657                grapheme_len,
19658            } => {
19659                in_whitespace = false;
19660                if current_line_len + grapheme_len > wrap_column
19661                    && current_line_len != line_prefix_len
19662                {
19663                    wrapped_text.push_str(current_line.trim_end());
19664                    wrapped_text.push('\n');
19665                    current_line.truncate(line_prefix.len());
19666                    current_line_len = line_prefix_len;
19667                }
19668                current_line.push_str(token);
19669                current_line_len += grapheme_len;
19670            }
19671            WordBreakToken::InlineWhitespace {
19672                mut token,
19673                mut grapheme_len,
19674            } => {
19675                in_whitespace = true;
19676                if have_preceding_whitespace && !preserve_existing_whitespace {
19677                    continue;
19678                }
19679                if !preserve_existing_whitespace {
19680                    token = " ";
19681                    grapheme_len = 1;
19682                }
19683                if current_line_len + grapheme_len > wrap_column {
19684                    wrapped_text.push_str(current_line.trim_end());
19685                    wrapped_text.push('\n');
19686                    current_line.truncate(line_prefix.len());
19687                    current_line_len = line_prefix_len;
19688                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19689                    current_line.push_str(token);
19690                    current_line_len += grapheme_len;
19691                }
19692            }
19693            WordBreakToken::Newline => {
19694                in_whitespace = true;
19695                if preserve_existing_whitespace {
19696                    wrapped_text.push_str(current_line.trim_end());
19697                    wrapped_text.push('\n');
19698                    current_line.truncate(line_prefix.len());
19699                    current_line_len = line_prefix_len;
19700                } else if have_preceding_whitespace {
19701                    continue;
19702                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19703                {
19704                    wrapped_text.push_str(current_line.trim_end());
19705                    wrapped_text.push('\n');
19706                    current_line.truncate(line_prefix.len());
19707                    current_line_len = line_prefix_len;
19708                } else if current_line_len != line_prefix_len {
19709                    current_line.push(' ');
19710                    current_line_len += 1;
19711                }
19712            }
19713        }
19714    }
19715
19716    if !current_line.is_empty() {
19717        wrapped_text.push_str(&current_line);
19718    }
19719    wrapped_text
19720}
19721
19722#[test]
19723fn test_wrap_with_prefix() {
19724    assert_eq!(
19725        wrap_with_prefix(
19726            "# ".to_string(),
19727            "abcdefg".to_string(),
19728            4,
19729            NonZeroU32::new(4).unwrap(),
19730            false,
19731        ),
19732        "# abcdefg"
19733    );
19734    assert_eq!(
19735        wrap_with_prefix(
19736            "".to_string(),
19737            "\thello world".to_string(),
19738            8,
19739            NonZeroU32::new(4).unwrap(),
19740            false,
19741        ),
19742        "hello\nworld"
19743    );
19744    assert_eq!(
19745        wrap_with_prefix(
19746            "// ".to_string(),
19747            "xx \nyy zz aa bb cc".to_string(),
19748            12,
19749            NonZeroU32::new(4).unwrap(),
19750            false,
19751        ),
19752        "// xx yy zz\n// aa bb cc"
19753    );
19754    assert_eq!(
19755        wrap_with_prefix(
19756            String::new(),
19757            "这是什么 \n 钢笔".to_string(),
19758            3,
19759            NonZeroU32::new(4).unwrap(),
19760            false,
19761        ),
19762        "这是什\n么 钢\n"
19763    );
19764}
19765
19766pub trait CollaborationHub {
19767    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19768    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19769    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19770}
19771
19772impl CollaborationHub for Entity<Project> {
19773    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19774        self.read(cx).collaborators()
19775    }
19776
19777    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19778        self.read(cx).user_store().read(cx).participant_indices()
19779    }
19780
19781    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19782        let this = self.read(cx);
19783        let user_ids = this.collaborators().values().map(|c| c.user_id);
19784        this.user_store().read_with(cx, |user_store, cx| {
19785            user_store.participant_names(user_ids, cx)
19786        })
19787    }
19788}
19789
19790pub trait SemanticsProvider {
19791    fn hover(
19792        &self,
19793        buffer: &Entity<Buffer>,
19794        position: text::Anchor,
19795        cx: &mut App,
19796    ) -> Option<Task<Vec<project::Hover>>>;
19797
19798    fn inline_values(
19799        &self,
19800        buffer_handle: Entity<Buffer>,
19801        range: Range<text::Anchor>,
19802        cx: &mut App,
19803    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19804
19805    fn inlay_hints(
19806        &self,
19807        buffer_handle: Entity<Buffer>,
19808        range: Range<text::Anchor>,
19809        cx: &mut App,
19810    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19811
19812    fn resolve_inlay_hint(
19813        &self,
19814        hint: InlayHint,
19815        buffer_handle: Entity<Buffer>,
19816        server_id: LanguageServerId,
19817        cx: &mut App,
19818    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19819
19820    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19821
19822    fn document_highlights(
19823        &self,
19824        buffer: &Entity<Buffer>,
19825        position: text::Anchor,
19826        cx: &mut App,
19827    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19828
19829    fn definitions(
19830        &self,
19831        buffer: &Entity<Buffer>,
19832        position: text::Anchor,
19833        kind: GotoDefinitionKind,
19834        cx: &mut App,
19835    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19836
19837    fn range_for_rename(
19838        &self,
19839        buffer: &Entity<Buffer>,
19840        position: text::Anchor,
19841        cx: &mut App,
19842    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19843
19844    fn perform_rename(
19845        &self,
19846        buffer: &Entity<Buffer>,
19847        position: text::Anchor,
19848        new_name: String,
19849        cx: &mut App,
19850    ) -> Option<Task<Result<ProjectTransaction>>>;
19851}
19852
19853pub trait CompletionProvider {
19854    fn completions(
19855        &self,
19856        excerpt_id: ExcerptId,
19857        buffer: &Entity<Buffer>,
19858        buffer_position: text::Anchor,
19859        trigger: CompletionContext,
19860        window: &mut Window,
19861        cx: &mut Context<Editor>,
19862    ) -> Task<Result<Option<Vec<Completion>>>>;
19863
19864    fn resolve_completions(
19865        &self,
19866        buffer: Entity<Buffer>,
19867        completion_indices: Vec<usize>,
19868        completions: Rc<RefCell<Box<[Completion]>>>,
19869        cx: &mut Context<Editor>,
19870    ) -> Task<Result<bool>>;
19871
19872    fn apply_additional_edits_for_completion(
19873        &self,
19874        _buffer: Entity<Buffer>,
19875        _completions: Rc<RefCell<Box<[Completion]>>>,
19876        _completion_index: usize,
19877        _push_to_history: bool,
19878        _cx: &mut Context<Editor>,
19879    ) -> Task<Result<Option<language::Transaction>>> {
19880        Task::ready(Ok(None))
19881    }
19882
19883    fn is_completion_trigger(
19884        &self,
19885        buffer: &Entity<Buffer>,
19886        position: language::Anchor,
19887        text: &str,
19888        trigger_in_words: bool,
19889        cx: &mut Context<Editor>,
19890    ) -> bool;
19891
19892    fn sort_completions(&self) -> bool {
19893        true
19894    }
19895
19896    fn filter_completions(&self) -> bool {
19897        true
19898    }
19899}
19900
19901pub trait CodeActionProvider {
19902    fn id(&self) -> Arc<str>;
19903
19904    fn code_actions(
19905        &self,
19906        buffer: &Entity<Buffer>,
19907        range: Range<text::Anchor>,
19908        window: &mut Window,
19909        cx: &mut App,
19910    ) -> Task<Result<Vec<CodeAction>>>;
19911
19912    fn apply_code_action(
19913        &self,
19914        buffer_handle: Entity<Buffer>,
19915        action: CodeAction,
19916        excerpt_id: ExcerptId,
19917        push_to_history: bool,
19918        window: &mut Window,
19919        cx: &mut App,
19920    ) -> Task<Result<ProjectTransaction>>;
19921}
19922
19923impl CodeActionProvider for Entity<Project> {
19924    fn id(&self) -> Arc<str> {
19925        "project".into()
19926    }
19927
19928    fn code_actions(
19929        &self,
19930        buffer: &Entity<Buffer>,
19931        range: Range<text::Anchor>,
19932        _window: &mut Window,
19933        cx: &mut App,
19934    ) -> Task<Result<Vec<CodeAction>>> {
19935        self.update(cx, |project, cx| {
19936            let code_lens = project.code_lens(buffer, range.clone(), cx);
19937            let code_actions = project.code_actions(buffer, range, None, cx);
19938            cx.background_spawn(async move {
19939                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19940                Ok(code_lens
19941                    .context("code lens fetch")?
19942                    .into_iter()
19943                    .chain(code_actions.context("code action fetch")?)
19944                    .collect())
19945            })
19946        })
19947    }
19948
19949    fn apply_code_action(
19950        &self,
19951        buffer_handle: Entity<Buffer>,
19952        action: CodeAction,
19953        _excerpt_id: ExcerptId,
19954        push_to_history: bool,
19955        _window: &mut Window,
19956        cx: &mut App,
19957    ) -> Task<Result<ProjectTransaction>> {
19958        self.update(cx, |project, cx| {
19959            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19960        })
19961    }
19962}
19963
19964fn snippet_completions(
19965    project: &Project,
19966    buffer: &Entity<Buffer>,
19967    buffer_position: text::Anchor,
19968    cx: &mut App,
19969) -> Task<Result<Vec<Completion>>> {
19970    let languages = buffer.read(cx).languages_at(buffer_position);
19971    let snippet_store = project.snippets().read(cx);
19972
19973    let scopes: Vec<_> = languages
19974        .iter()
19975        .filter_map(|language| {
19976            let language_name = language.lsp_id();
19977            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19978
19979            if snippets.is_empty() {
19980                None
19981            } else {
19982                Some((language.default_scope(), snippets))
19983            }
19984        })
19985        .collect();
19986
19987    if scopes.is_empty() {
19988        return Task::ready(Ok(vec![]));
19989    }
19990
19991    let snapshot = buffer.read(cx).text_snapshot();
19992    let chars: String = snapshot
19993        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19994        .collect();
19995    let executor = cx.background_executor().clone();
19996
19997    cx.background_spawn(async move {
19998        let mut all_results: Vec<Completion> = Vec::new();
19999        for (scope, snippets) in scopes.into_iter() {
20000            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20001            let mut last_word = chars
20002                .chars()
20003                .take_while(|c| classifier.is_word(*c))
20004                .collect::<String>();
20005            last_word = last_word.chars().rev().collect();
20006
20007            if last_word.is_empty() {
20008                return Ok(vec![]);
20009            }
20010
20011            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20012            let to_lsp = |point: &text::Anchor| {
20013                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20014                point_to_lsp(end)
20015            };
20016            let lsp_end = to_lsp(&buffer_position);
20017
20018            let candidates = snippets
20019                .iter()
20020                .enumerate()
20021                .flat_map(|(ix, snippet)| {
20022                    snippet
20023                        .prefix
20024                        .iter()
20025                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20026                })
20027                .collect::<Vec<StringMatchCandidate>>();
20028
20029            let mut matches = fuzzy::match_strings(
20030                &candidates,
20031                &last_word,
20032                last_word.chars().any(|c| c.is_uppercase()),
20033                100,
20034                &Default::default(),
20035                executor.clone(),
20036            )
20037            .await;
20038
20039            // Remove all candidates where the query's start does not match the start of any word in the candidate
20040            if let Some(query_start) = last_word.chars().next() {
20041                matches.retain(|string_match| {
20042                    split_words(&string_match.string).any(|word| {
20043                        // Check that the first codepoint of the word as lowercase matches the first
20044                        // codepoint of the query as lowercase
20045                        word.chars()
20046                            .flat_map(|codepoint| codepoint.to_lowercase())
20047                            .zip(query_start.to_lowercase())
20048                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20049                    })
20050                });
20051            }
20052
20053            let matched_strings = matches
20054                .into_iter()
20055                .map(|m| m.string)
20056                .collect::<HashSet<_>>();
20057
20058            let mut result: Vec<Completion> = snippets
20059                .iter()
20060                .filter_map(|snippet| {
20061                    let matching_prefix = snippet
20062                        .prefix
20063                        .iter()
20064                        .find(|prefix| matched_strings.contains(*prefix))?;
20065                    let start = as_offset - last_word.len();
20066                    let start = snapshot.anchor_before(start);
20067                    let range = start..buffer_position;
20068                    let lsp_start = to_lsp(&start);
20069                    let lsp_range = lsp::Range {
20070                        start: lsp_start,
20071                        end: lsp_end,
20072                    };
20073                    Some(Completion {
20074                        replace_range: range,
20075                        new_text: snippet.body.clone(),
20076                        source: CompletionSource::Lsp {
20077                            insert_range: None,
20078                            server_id: LanguageServerId(usize::MAX),
20079                            resolved: true,
20080                            lsp_completion: Box::new(lsp::CompletionItem {
20081                                label: snippet.prefix.first().unwrap().clone(),
20082                                kind: Some(CompletionItemKind::SNIPPET),
20083                                label_details: snippet.description.as_ref().map(|description| {
20084                                    lsp::CompletionItemLabelDetails {
20085                                        detail: Some(description.clone()),
20086                                        description: None,
20087                                    }
20088                                }),
20089                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20090                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20091                                    lsp::InsertReplaceEdit {
20092                                        new_text: snippet.body.clone(),
20093                                        insert: lsp_range,
20094                                        replace: lsp_range,
20095                                    },
20096                                )),
20097                                filter_text: Some(snippet.body.clone()),
20098                                sort_text: Some(char::MAX.to_string()),
20099                                ..lsp::CompletionItem::default()
20100                            }),
20101                            lsp_defaults: None,
20102                        },
20103                        label: CodeLabel {
20104                            text: matching_prefix.clone(),
20105                            runs: Vec::new(),
20106                            filter_range: 0..matching_prefix.len(),
20107                        },
20108                        icon_path: None,
20109                        documentation: Some(
20110                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20111                                single_line: snippet.name.clone().into(),
20112                                plain_text: snippet
20113                                    .description
20114                                    .clone()
20115                                    .map(|description| description.into()),
20116                            },
20117                        ),
20118                        insert_text_mode: None,
20119                        confirm: None,
20120                    })
20121                })
20122                .collect();
20123
20124            all_results.append(&mut result);
20125        }
20126
20127        Ok(all_results)
20128    })
20129}
20130
20131impl CompletionProvider for Entity<Project> {
20132    fn completions(
20133        &self,
20134        _excerpt_id: ExcerptId,
20135        buffer: &Entity<Buffer>,
20136        buffer_position: text::Anchor,
20137        options: CompletionContext,
20138        _window: &mut Window,
20139        cx: &mut Context<Editor>,
20140    ) -> Task<Result<Option<Vec<Completion>>>> {
20141        self.update(cx, |project, cx| {
20142            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20143            let project_completions = project.completions(buffer, buffer_position, options, cx);
20144            cx.background_spawn(async move {
20145                let snippets_completions = snippets.await?;
20146                match project_completions.await? {
20147                    Some(mut completions) => {
20148                        completions.extend(snippets_completions);
20149                        Ok(Some(completions))
20150                    }
20151                    None => {
20152                        if snippets_completions.is_empty() {
20153                            Ok(None)
20154                        } else {
20155                            Ok(Some(snippets_completions))
20156                        }
20157                    }
20158                }
20159            })
20160        })
20161    }
20162
20163    fn resolve_completions(
20164        &self,
20165        buffer: Entity<Buffer>,
20166        completion_indices: Vec<usize>,
20167        completions: Rc<RefCell<Box<[Completion]>>>,
20168        cx: &mut Context<Editor>,
20169    ) -> Task<Result<bool>> {
20170        self.update(cx, |project, cx| {
20171            project.lsp_store().update(cx, |lsp_store, cx| {
20172                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20173            })
20174        })
20175    }
20176
20177    fn apply_additional_edits_for_completion(
20178        &self,
20179        buffer: Entity<Buffer>,
20180        completions: Rc<RefCell<Box<[Completion]>>>,
20181        completion_index: usize,
20182        push_to_history: bool,
20183        cx: &mut Context<Editor>,
20184    ) -> Task<Result<Option<language::Transaction>>> {
20185        self.update(cx, |project, cx| {
20186            project.lsp_store().update(cx, |lsp_store, cx| {
20187                lsp_store.apply_additional_edits_for_completion(
20188                    buffer,
20189                    completions,
20190                    completion_index,
20191                    push_to_history,
20192                    cx,
20193                )
20194            })
20195        })
20196    }
20197
20198    fn is_completion_trigger(
20199        &self,
20200        buffer: &Entity<Buffer>,
20201        position: language::Anchor,
20202        text: &str,
20203        trigger_in_words: bool,
20204        cx: &mut Context<Editor>,
20205    ) -> bool {
20206        let mut chars = text.chars();
20207        let char = if let Some(char) = chars.next() {
20208            char
20209        } else {
20210            return false;
20211        };
20212        if chars.next().is_some() {
20213            return false;
20214        }
20215
20216        let buffer = buffer.read(cx);
20217        let snapshot = buffer.snapshot();
20218        if !snapshot.settings_at(position, cx).show_completions_on_input {
20219            return false;
20220        }
20221        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20222        if trigger_in_words && classifier.is_word(char) {
20223            return true;
20224        }
20225
20226        buffer.completion_triggers().contains(text)
20227    }
20228}
20229
20230impl SemanticsProvider for Entity<Project> {
20231    fn hover(
20232        &self,
20233        buffer: &Entity<Buffer>,
20234        position: text::Anchor,
20235        cx: &mut App,
20236    ) -> Option<Task<Vec<project::Hover>>> {
20237        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20238    }
20239
20240    fn document_highlights(
20241        &self,
20242        buffer: &Entity<Buffer>,
20243        position: text::Anchor,
20244        cx: &mut App,
20245    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20246        Some(self.update(cx, |project, cx| {
20247            project.document_highlights(buffer, position, cx)
20248        }))
20249    }
20250
20251    fn definitions(
20252        &self,
20253        buffer: &Entity<Buffer>,
20254        position: text::Anchor,
20255        kind: GotoDefinitionKind,
20256        cx: &mut App,
20257    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20258        Some(self.update(cx, |project, cx| match kind {
20259            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20260            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20261            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20262            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20263        }))
20264    }
20265
20266    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20267        // TODO: make this work for remote projects
20268        self.update(cx, |project, cx| {
20269            if project
20270                .active_debug_session(cx)
20271                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20272            {
20273                return true;
20274            }
20275
20276            buffer.update(cx, |buffer, cx| {
20277                project.any_language_server_supports_inlay_hints(buffer, cx)
20278            })
20279        })
20280    }
20281
20282    fn inline_values(
20283        &self,
20284        buffer_handle: Entity<Buffer>,
20285
20286        range: Range<text::Anchor>,
20287        cx: &mut App,
20288    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20289        self.update(cx, |project, cx| {
20290            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20291
20292            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20293        })
20294    }
20295
20296    fn inlay_hints(
20297        &self,
20298        buffer_handle: Entity<Buffer>,
20299        range: Range<text::Anchor>,
20300        cx: &mut App,
20301    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20302        Some(self.update(cx, |project, cx| {
20303            project.inlay_hints(buffer_handle, range, cx)
20304        }))
20305    }
20306
20307    fn resolve_inlay_hint(
20308        &self,
20309        hint: InlayHint,
20310        buffer_handle: Entity<Buffer>,
20311        server_id: LanguageServerId,
20312        cx: &mut App,
20313    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20314        Some(self.update(cx, |project, cx| {
20315            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20316        }))
20317    }
20318
20319    fn range_for_rename(
20320        &self,
20321        buffer: &Entity<Buffer>,
20322        position: text::Anchor,
20323        cx: &mut App,
20324    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20325        Some(self.update(cx, |project, cx| {
20326            let buffer = buffer.clone();
20327            let task = project.prepare_rename(buffer.clone(), position, cx);
20328            cx.spawn(async move |_, cx| {
20329                Ok(match task.await? {
20330                    PrepareRenameResponse::Success(range) => Some(range),
20331                    PrepareRenameResponse::InvalidPosition => None,
20332                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20333                        // Fallback on using TreeSitter info to determine identifier range
20334                        buffer.update(cx, |buffer, _| {
20335                            let snapshot = buffer.snapshot();
20336                            let (range, kind) = snapshot.surrounding_word(position);
20337                            if kind != Some(CharKind::Word) {
20338                                return None;
20339                            }
20340                            Some(
20341                                snapshot.anchor_before(range.start)
20342                                    ..snapshot.anchor_after(range.end),
20343                            )
20344                        })?
20345                    }
20346                })
20347            })
20348        }))
20349    }
20350
20351    fn perform_rename(
20352        &self,
20353        buffer: &Entity<Buffer>,
20354        position: text::Anchor,
20355        new_name: String,
20356        cx: &mut App,
20357    ) -> Option<Task<Result<ProjectTransaction>>> {
20358        Some(self.update(cx, |project, cx| {
20359            project.perform_rename(buffer.clone(), position, new_name, cx)
20360        }))
20361    }
20362}
20363
20364fn inlay_hint_settings(
20365    location: Anchor,
20366    snapshot: &MultiBufferSnapshot,
20367    cx: &mut Context<Editor>,
20368) -> InlayHintSettings {
20369    let file = snapshot.file_at(location);
20370    let language = snapshot.language_at(location).map(|l| l.name());
20371    language_settings(language, file, cx).inlay_hints
20372}
20373
20374fn consume_contiguous_rows(
20375    contiguous_row_selections: &mut Vec<Selection<Point>>,
20376    selection: &Selection<Point>,
20377    display_map: &DisplaySnapshot,
20378    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20379) -> (MultiBufferRow, MultiBufferRow) {
20380    contiguous_row_selections.push(selection.clone());
20381    let start_row = MultiBufferRow(selection.start.row);
20382    let mut end_row = ending_row(selection, display_map);
20383
20384    while let Some(next_selection) = selections.peek() {
20385        if next_selection.start.row <= end_row.0 {
20386            end_row = ending_row(next_selection, display_map);
20387            contiguous_row_selections.push(selections.next().unwrap().clone());
20388        } else {
20389            break;
20390        }
20391    }
20392    (start_row, end_row)
20393}
20394
20395fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20396    if next_selection.end.column > 0 || next_selection.is_empty() {
20397        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20398    } else {
20399        MultiBufferRow(next_selection.end.row)
20400    }
20401}
20402
20403impl EditorSnapshot {
20404    pub fn remote_selections_in_range<'a>(
20405        &'a self,
20406        range: &'a Range<Anchor>,
20407        collaboration_hub: &dyn CollaborationHub,
20408        cx: &'a App,
20409    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20410        let participant_names = collaboration_hub.user_names(cx);
20411        let participant_indices = collaboration_hub.user_participant_indices(cx);
20412        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20413        let collaborators_by_replica_id = collaborators_by_peer_id
20414            .values()
20415            .map(|collaborator| (collaborator.replica_id, collaborator))
20416            .collect::<HashMap<_, _>>();
20417        self.buffer_snapshot
20418            .selections_in_range(range, false)
20419            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20420                if replica_id == AGENT_REPLICA_ID {
20421                    Some(RemoteSelection {
20422                        replica_id,
20423                        selection,
20424                        cursor_shape,
20425                        line_mode,
20426                        collaborator_id: CollaboratorId::Agent,
20427                        user_name: Some("Agent".into()),
20428                        color: cx.theme().players().agent(),
20429                    })
20430                } else {
20431                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20432                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20433                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20434                    Some(RemoteSelection {
20435                        replica_id,
20436                        selection,
20437                        cursor_shape,
20438                        line_mode,
20439                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20440                        user_name,
20441                        color: if let Some(index) = participant_index {
20442                            cx.theme().players().color_for_participant(index.0)
20443                        } else {
20444                            cx.theme().players().absent()
20445                        },
20446                    })
20447                }
20448            })
20449    }
20450
20451    pub fn hunks_for_ranges(
20452        &self,
20453        ranges: impl IntoIterator<Item = Range<Point>>,
20454    ) -> Vec<MultiBufferDiffHunk> {
20455        let mut hunks = Vec::new();
20456        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20457            HashMap::default();
20458        for query_range in ranges {
20459            let query_rows =
20460                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20461            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20462                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20463            ) {
20464                // Include deleted hunks that are adjacent to the query range, because
20465                // otherwise they would be missed.
20466                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20467                if hunk.status().is_deleted() {
20468                    intersects_range |= hunk.row_range.start == query_rows.end;
20469                    intersects_range |= hunk.row_range.end == query_rows.start;
20470                }
20471                if intersects_range {
20472                    if !processed_buffer_rows
20473                        .entry(hunk.buffer_id)
20474                        .or_default()
20475                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20476                    {
20477                        continue;
20478                    }
20479                    hunks.push(hunk);
20480                }
20481            }
20482        }
20483
20484        hunks
20485    }
20486
20487    fn display_diff_hunks_for_rows<'a>(
20488        &'a self,
20489        display_rows: Range<DisplayRow>,
20490        folded_buffers: &'a HashSet<BufferId>,
20491    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20492        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20493        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20494
20495        self.buffer_snapshot
20496            .diff_hunks_in_range(buffer_start..buffer_end)
20497            .filter_map(|hunk| {
20498                if folded_buffers.contains(&hunk.buffer_id) {
20499                    return None;
20500                }
20501
20502                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20503                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20504
20505                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20506                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20507
20508                let display_hunk = if hunk_display_start.column() != 0 {
20509                    DisplayDiffHunk::Folded {
20510                        display_row: hunk_display_start.row(),
20511                    }
20512                } else {
20513                    let mut end_row = hunk_display_end.row();
20514                    if hunk_display_end.column() > 0 {
20515                        end_row.0 += 1;
20516                    }
20517                    let is_created_file = hunk.is_created_file();
20518                    DisplayDiffHunk::Unfolded {
20519                        status: hunk.status(),
20520                        diff_base_byte_range: hunk.diff_base_byte_range,
20521                        display_row_range: hunk_display_start.row()..end_row,
20522                        multi_buffer_range: Anchor::range_in_buffer(
20523                            hunk.excerpt_id,
20524                            hunk.buffer_id,
20525                            hunk.buffer_range,
20526                        ),
20527                        is_created_file,
20528                    }
20529                };
20530
20531                Some(display_hunk)
20532            })
20533    }
20534
20535    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20536        self.display_snapshot.buffer_snapshot.language_at(position)
20537    }
20538
20539    pub fn is_focused(&self) -> bool {
20540        self.is_focused
20541    }
20542
20543    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20544        self.placeholder_text.as_ref()
20545    }
20546
20547    pub fn scroll_position(&self) -> gpui::Point<f32> {
20548        self.scroll_anchor.scroll_position(&self.display_snapshot)
20549    }
20550
20551    fn gutter_dimensions(
20552        &self,
20553        font_id: FontId,
20554        font_size: Pixels,
20555        max_line_number_width: Pixels,
20556        cx: &App,
20557    ) -> Option<GutterDimensions> {
20558        if !self.show_gutter {
20559            return None;
20560        }
20561
20562        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20563        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20564
20565        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20566            matches!(
20567                ProjectSettings::get_global(cx).git.git_gutter,
20568                Some(GitGutterSetting::TrackedFiles)
20569            )
20570        });
20571        let gutter_settings = EditorSettings::get_global(cx).gutter;
20572        let show_line_numbers = self
20573            .show_line_numbers
20574            .unwrap_or(gutter_settings.line_numbers);
20575        let line_gutter_width = if show_line_numbers {
20576            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20577            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20578            max_line_number_width.max(min_width_for_number_on_gutter)
20579        } else {
20580            0.0.into()
20581        };
20582
20583        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20584        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20585
20586        let git_blame_entries_width =
20587            self.git_blame_gutter_max_author_length
20588                .map(|max_author_length| {
20589                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20590                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20591
20592                    /// The number of characters to dedicate to gaps and margins.
20593                    const SPACING_WIDTH: usize = 4;
20594
20595                    let max_char_count = max_author_length.min(renderer.max_author_length())
20596                        + ::git::SHORT_SHA_LENGTH
20597                        + MAX_RELATIVE_TIMESTAMP.len()
20598                        + SPACING_WIDTH;
20599
20600                    em_advance * max_char_count
20601                });
20602
20603        let is_singleton = self.buffer_snapshot.is_singleton();
20604
20605        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20606        left_padding += if !is_singleton {
20607            em_width * 4.0
20608        } else if show_runnables || show_breakpoints {
20609            em_width * 3.0
20610        } else if show_git_gutter && show_line_numbers {
20611            em_width * 2.0
20612        } else if show_git_gutter || show_line_numbers {
20613            em_width
20614        } else {
20615            px(0.)
20616        };
20617
20618        let shows_folds = is_singleton && gutter_settings.folds;
20619
20620        let right_padding = if shows_folds && show_line_numbers {
20621            em_width * 4.0
20622        } else if shows_folds || (!is_singleton && show_line_numbers) {
20623            em_width * 3.0
20624        } else if show_line_numbers {
20625            em_width
20626        } else {
20627            px(0.)
20628        };
20629
20630        Some(GutterDimensions {
20631            left_padding,
20632            right_padding,
20633            width: line_gutter_width + left_padding + right_padding,
20634            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20635            git_blame_entries_width,
20636        })
20637    }
20638
20639    pub fn render_crease_toggle(
20640        &self,
20641        buffer_row: MultiBufferRow,
20642        row_contains_cursor: bool,
20643        editor: Entity<Editor>,
20644        window: &mut Window,
20645        cx: &mut App,
20646    ) -> Option<AnyElement> {
20647        let folded = self.is_line_folded(buffer_row);
20648        let mut is_foldable = false;
20649
20650        if let Some(crease) = self
20651            .crease_snapshot
20652            .query_row(buffer_row, &self.buffer_snapshot)
20653        {
20654            is_foldable = true;
20655            match crease {
20656                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20657                    if let Some(render_toggle) = render_toggle {
20658                        let toggle_callback =
20659                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20660                                if folded {
20661                                    editor.update(cx, |editor, cx| {
20662                                        editor.fold_at(buffer_row, window, cx)
20663                                    });
20664                                } else {
20665                                    editor.update(cx, |editor, cx| {
20666                                        editor.unfold_at(buffer_row, window, cx)
20667                                    });
20668                                }
20669                            });
20670                        return Some((render_toggle)(
20671                            buffer_row,
20672                            folded,
20673                            toggle_callback,
20674                            window,
20675                            cx,
20676                        ));
20677                    }
20678                }
20679            }
20680        }
20681
20682        is_foldable |= self.starts_indent(buffer_row);
20683
20684        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20685            Some(
20686                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20687                    .toggle_state(folded)
20688                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20689                        if folded {
20690                            this.unfold_at(buffer_row, window, cx);
20691                        } else {
20692                            this.fold_at(buffer_row, window, cx);
20693                        }
20694                    }))
20695                    .into_any_element(),
20696            )
20697        } else {
20698            None
20699        }
20700    }
20701
20702    pub fn render_crease_trailer(
20703        &self,
20704        buffer_row: MultiBufferRow,
20705        window: &mut Window,
20706        cx: &mut App,
20707    ) -> Option<AnyElement> {
20708        let folded = self.is_line_folded(buffer_row);
20709        if let Crease::Inline { render_trailer, .. } = self
20710            .crease_snapshot
20711            .query_row(buffer_row, &self.buffer_snapshot)?
20712        {
20713            let render_trailer = render_trailer.as_ref()?;
20714            Some(render_trailer(buffer_row, folded, window, cx))
20715        } else {
20716            None
20717        }
20718    }
20719}
20720
20721impl Deref for EditorSnapshot {
20722    type Target = DisplaySnapshot;
20723
20724    fn deref(&self) -> &Self::Target {
20725        &self.display_snapshot
20726    }
20727}
20728
20729#[derive(Clone, Debug, PartialEq, Eq)]
20730pub enum EditorEvent {
20731    InputIgnored {
20732        text: Arc<str>,
20733    },
20734    InputHandled {
20735        utf16_range_to_replace: Option<Range<isize>>,
20736        text: Arc<str>,
20737    },
20738    ExcerptsAdded {
20739        buffer: Entity<Buffer>,
20740        predecessor: ExcerptId,
20741        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20742    },
20743    ExcerptsRemoved {
20744        ids: Vec<ExcerptId>,
20745        removed_buffer_ids: Vec<BufferId>,
20746    },
20747    BufferFoldToggled {
20748        ids: Vec<ExcerptId>,
20749        folded: bool,
20750    },
20751    ExcerptsEdited {
20752        ids: Vec<ExcerptId>,
20753    },
20754    ExcerptsExpanded {
20755        ids: Vec<ExcerptId>,
20756    },
20757    BufferEdited,
20758    Edited {
20759        transaction_id: clock::Lamport,
20760    },
20761    Reparsed(BufferId),
20762    Focused,
20763    FocusedIn,
20764    Blurred,
20765    DirtyChanged,
20766    Saved,
20767    TitleChanged,
20768    DiffBaseChanged,
20769    SelectionsChanged {
20770        local: bool,
20771    },
20772    ScrollPositionChanged {
20773        local: bool,
20774        autoscroll: bool,
20775    },
20776    Closed,
20777    TransactionUndone {
20778        transaction_id: clock::Lamport,
20779    },
20780    TransactionBegun {
20781        transaction_id: clock::Lamport,
20782    },
20783    Reloaded,
20784    CursorShapeChanged,
20785    PushedToNavHistory {
20786        anchor: Anchor,
20787        is_deactivate: bool,
20788    },
20789}
20790
20791impl EventEmitter<EditorEvent> for Editor {}
20792
20793impl Focusable for Editor {
20794    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20795        self.focus_handle.clone()
20796    }
20797}
20798
20799impl Render for Editor {
20800    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20801        let settings = ThemeSettings::get_global(cx);
20802
20803        let mut text_style = match self.mode {
20804            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20805                color: cx.theme().colors().editor_foreground,
20806                font_family: settings.ui_font.family.clone(),
20807                font_features: settings.ui_font.features.clone(),
20808                font_fallbacks: settings.ui_font.fallbacks.clone(),
20809                font_size: rems(0.875).into(),
20810                font_weight: settings.ui_font.weight,
20811                line_height: relative(settings.buffer_line_height.value()),
20812                ..Default::default()
20813            },
20814            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20815                color: cx.theme().colors().editor_foreground,
20816                font_family: settings.buffer_font.family.clone(),
20817                font_features: settings.buffer_font.features.clone(),
20818                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20819                font_size: settings.buffer_font_size(cx).into(),
20820                font_weight: settings.buffer_font.weight,
20821                line_height: relative(settings.buffer_line_height.value()),
20822                ..Default::default()
20823            },
20824        };
20825        if let Some(text_style_refinement) = &self.text_style_refinement {
20826            text_style.refine(text_style_refinement)
20827        }
20828
20829        let background = match self.mode {
20830            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20831            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20832            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20833            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20834        };
20835
20836        EditorElement::new(
20837            &cx.entity(),
20838            EditorStyle {
20839                background,
20840                local_player: cx.theme().players().local(),
20841                text: text_style,
20842                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20843                syntax: cx.theme().syntax().clone(),
20844                status: cx.theme().status().clone(),
20845                inlay_hints_style: make_inlay_hints_style(cx),
20846                inline_completion_styles: make_suggestion_styles(cx),
20847                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20848                show_underlines: !self.mode.is_minimap(),
20849            },
20850        )
20851    }
20852}
20853
20854impl EntityInputHandler for Editor {
20855    fn text_for_range(
20856        &mut self,
20857        range_utf16: Range<usize>,
20858        adjusted_range: &mut Option<Range<usize>>,
20859        _: &mut Window,
20860        cx: &mut Context<Self>,
20861    ) -> Option<String> {
20862        let snapshot = self.buffer.read(cx).read(cx);
20863        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20864        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20865        if (start.0..end.0) != range_utf16 {
20866            adjusted_range.replace(start.0..end.0);
20867        }
20868        Some(snapshot.text_for_range(start..end).collect())
20869    }
20870
20871    fn selected_text_range(
20872        &mut self,
20873        ignore_disabled_input: bool,
20874        _: &mut Window,
20875        cx: &mut Context<Self>,
20876    ) -> Option<UTF16Selection> {
20877        // Prevent the IME menu from appearing when holding down an alphabetic key
20878        // while input is disabled.
20879        if !ignore_disabled_input && !self.input_enabled {
20880            return None;
20881        }
20882
20883        let selection = self.selections.newest::<OffsetUtf16>(cx);
20884        let range = selection.range();
20885
20886        Some(UTF16Selection {
20887            range: range.start.0..range.end.0,
20888            reversed: selection.reversed,
20889        })
20890    }
20891
20892    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20893        let snapshot = self.buffer.read(cx).read(cx);
20894        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20895        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20896    }
20897
20898    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20899        self.clear_highlights::<InputComposition>(cx);
20900        self.ime_transaction.take();
20901    }
20902
20903    fn replace_text_in_range(
20904        &mut self,
20905        range_utf16: Option<Range<usize>>,
20906        text: &str,
20907        window: &mut Window,
20908        cx: &mut Context<Self>,
20909    ) {
20910        if !self.input_enabled {
20911            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20912            return;
20913        }
20914
20915        self.transact(window, cx, |this, window, cx| {
20916            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20917                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20918                Some(this.selection_replacement_ranges(range_utf16, cx))
20919            } else {
20920                this.marked_text_ranges(cx)
20921            };
20922
20923            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20924                let newest_selection_id = this.selections.newest_anchor().id;
20925                this.selections
20926                    .all::<OffsetUtf16>(cx)
20927                    .iter()
20928                    .zip(ranges_to_replace.iter())
20929                    .find_map(|(selection, range)| {
20930                        if selection.id == newest_selection_id {
20931                            Some(
20932                                (range.start.0 as isize - selection.head().0 as isize)
20933                                    ..(range.end.0 as isize - selection.head().0 as isize),
20934                            )
20935                        } else {
20936                            None
20937                        }
20938                    })
20939            });
20940
20941            cx.emit(EditorEvent::InputHandled {
20942                utf16_range_to_replace: range_to_replace,
20943                text: text.into(),
20944            });
20945
20946            if let Some(new_selected_ranges) = new_selected_ranges {
20947                this.change_selections(None, window, cx, |selections| {
20948                    selections.select_ranges(new_selected_ranges)
20949                });
20950                this.backspace(&Default::default(), window, cx);
20951            }
20952
20953            this.handle_input(text, window, cx);
20954        });
20955
20956        if let Some(transaction) = self.ime_transaction {
20957            self.buffer.update(cx, |buffer, cx| {
20958                buffer.group_until_transaction(transaction, cx);
20959            });
20960        }
20961
20962        self.unmark_text(window, cx);
20963    }
20964
20965    fn replace_and_mark_text_in_range(
20966        &mut self,
20967        range_utf16: Option<Range<usize>>,
20968        text: &str,
20969        new_selected_range_utf16: Option<Range<usize>>,
20970        window: &mut Window,
20971        cx: &mut Context<Self>,
20972    ) {
20973        if !self.input_enabled {
20974            return;
20975        }
20976
20977        let transaction = self.transact(window, cx, |this, window, cx| {
20978            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20979                let snapshot = this.buffer.read(cx).read(cx);
20980                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20981                    for marked_range in &mut marked_ranges {
20982                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20983                        marked_range.start.0 += relative_range_utf16.start;
20984                        marked_range.start =
20985                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20986                        marked_range.end =
20987                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20988                    }
20989                }
20990                Some(marked_ranges)
20991            } else if let Some(range_utf16) = range_utf16 {
20992                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20993                Some(this.selection_replacement_ranges(range_utf16, cx))
20994            } else {
20995                None
20996            };
20997
20998            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20999                let newest_selection_id = this.selections.newest_anchor().id;
21000                this.selections
21001                    .all::<OffsetUtf16>(cx)
21002                    .iter()
21003                    .zip(ranges_to_replace.iter())
21004                    .find_map(|(selection, range)| {
21005                        if selection.id == newest_selection_id {
21006                            Some(
21007                                (range.start.0 as isize - selection.head().0 as isize)
21008                                    ..(range.end.0 as isize - selection.head().0 as isize),
21009                            )
21010                        } else {
21011                            None
21012                        }
21013                    })
21014            });
21015
21016            cx.emit(EditorEvent::InputHandled {
21017                utf16_range_to_replace: range_to_replace,
21018                text: text.into(),
21019            });
21020
21021            if let Some(ranges) = ranges_to_replace {
21022                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21023            }
21024
21025            let marked_ranges = {
21026                let snapshot = this.buffer.read(cx).read(cx);
21027                this.selections
21028                    .disjoint_anchors()
21029                    .iter()
21030                    .map(|selection| {
21031                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21032                    })
21033                    .collect::<Vec<_>>()
21034            };
21035
21036            if text.is_empty() {
21037                this.unmark_text(window, cx);
21038            } else {
21039                this.highlight_text::<InputComposition>(
21040                    marked_ranges.clone(),
21041                    HighlightStyle {
21042                        underline: Some(UnderlineStyle {
21043                            thickness: px(1.),
21044                            color: None,
21045                            wavy: false,
21046                        }),
21047                        ..Default::default()
21048                    },
21049                    cx,
21050                );
21051            }
21052
21053            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21054            let use_autoclose = this.use_autoclose;
21055            let use_auto_surround = this.use_auto_surround;
21056            this.set_use_autoclose(false);
21057            this.set_use_auto_surround(false);
21058            this.handle_input(text, window, cx);
21059            this.set_use_autoclose(use_autoclose);
21060            this.set_use_auto_surround(use_auto_surround);
21061
21062            if let Some(new_selected_range) = new_selected_range_utf16 {
21063                let snapshot = this.buffer.read(cx).read(cx);
21064                let new_selected_ranges = marked_ranges
21065                    .into_iter()
21066                    .map(|marked_range| {
21067                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21068                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21069                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21070                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21071                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21072                    })
21073                    .collect::<Vec<_>>();
21074
21075                drop(snapshot);
21076                this.change_selections(None, window, cx, |selections| {
21077                    selections.select_ranges(new_selected_ranges)
21078                });
21079            }
21080        });
21081
21082        self.ime_transaction = self.ime_transaction.or(transaction);
21083        if let Some(transaction) = self.ime_transaction {
21084            self.buffer.update(cx, |buffer, cx| {
21085                buffer.group_until_transaction(transaction, cx);
21086            });
21087        }
21088
21089        if self.text_highlights::<InputComposition>(cx).is_none() {
21090            self.ime_transaction.take();
21091        }
21092    }
21093
21094    fn bounds_for_range(
21095        &mut self,
21096        range_utf16: Range<usize>,
21097        element_bounds: gpui::Bounds<Pixels>,
21098        window: &mut Window,
21099        cx: &mut Context<Self>,
21100    ) -> Option<gpui::Bounds<Pixels>> {
21101        let text_layout_details = self.text_layout_details(window);
21102        let gpui::Size {
21103            width: em_width,
21104            height: line_height,
21105        } = self.character_size(window);
21106
21107        let snapshot = self.snapshot(window, cx);
21108        let scroll_position = snapshot.scroll_position();
21109        let scroll_left = scroll_position.x * em_width;
21110
21111        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21112        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21113            + self.gutter_dimensions.width
21114            + self.gutter_dimensions.margin;
21115        let y = line_height * (start.row().as_f32() - scroll_position.y);
21116
21117        Some(Bounds {
21118            origin: element_bounds.origin + point(x, y),
21119            size: size(em_width, line_height),
21120        })
21121    }
21122
21123    fn character_index_for_point(
21124        &mut self,
21125        point: gpui::Point<Pixels>,
21126        _window: &mut Window,
21127        _cx: &mut Context<Self>,
21128    ) -> Option<usize> {
21129        let position_map = self.last_position_map.as_ref()?;
21130        if !position_map.text_hitbox.contains(&point) {
21131            return None;
21132        }
21133        let display_point = position_map.point_for_position(point).previous_valid;
21134        let anchor = position_map
21135            .snapshot
21136            .display_point_to_anchor(display_point, Bias::Left);
21137        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21138        Some(utf16_offset.0)
21139    }
21140}
21141
21142trait SelectionExt {
21143    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21144    fn spanned_rows(
21145        &self,
21146        include_end_if_at_line_start: bool,
21147        map: &DisplaySnapshot,
21148    ) -> Range<MultiBufferRow>;
21149}
21150
21151impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21152    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21153        let start = self
21154            .start
21155            .to_point(&map.buffer_snapshot)
21156            .to_display_point(map);
21157        let end = self
21158            .end
21159            .to_point(&map.buffer_snapshot)
21160            .to_display_point(map);
21161        if self.reversed {
21162            end..start
21163        } else {
21164            start..end
21165        }
21166    }
21167
21168    fn spanned_rows(
21169        &self,
21170        include_end_if_at_line_start: bool,
21171        map: &DisplaySnapshot,
21172    ) -> Range<MultiBufferRow> {
21173        let start = self.start.to_point(&map.buffer_snapshot);
21174        let mut end = self.end.to_point(&map.buffer_snapshot);
21175        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21176            end.row -= 1;
21177        }
21178
21179        let buffer_start = map.prev_line_boundary(start).0;
21180        let buffer_end = map.next_line_boundary(end).0;
21181        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21182    }
21183}
21184
21185impl<T: InvalidationRegion> InvalidationStack<T> {
21186    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21187    where
21188        S: Clone + ToOffset,
21189    {
21190        while let Some(region) = self.last() {
21191            let all_selections_inside_invalidation_ranges =
21192                if selections.len() == region.ranges().len() {
21193                    selections
21194                        .iter()
21195                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21196                        .all(|(selection, invalidation_range)| {
21197                            let head = selection.head().to_offset(buffer);
21198                            invalidation_range.start <= head && invalidation_range.end >= head
21199                        })
21200                } else {
21201                    false
21202                };
21203
21204            if all_selections_inside_invalidation_ranges {
21205                break;
21206            } else {
21207                self.pop();
21208            }
21209        }
21210    }
21211}
21212
21213impl<T> Default for InvalidationStack<T> {
21214    fn default() -> Self {
21215        Self(Default::default())
21216    }
21217}
21218
21219impl<T> Deref for InvalidationStack<T> {
21220    type Target = Vec<T>;
21221
21222    fn deref(&self) -> &Self::Target {
21223        &self.0
21224    }
21225}
21226
21227impl<T> DerefMut for InvalidationStack<T> {
21228    fn deref_mut(&mut self) -> &mut Self::Target {
21229        &mut self.0
21230    }
21231}
21232
21233impl InvalidationRegion for SnippetState {
21234    fn ranges(&self) -> &[Range<Anchor>] {
21235        &self.ranges[self.active_index]
21236    }
21237}
21238
21239fn inline_completion_edit_text(
21240    current_snapshot: &BufferSnapshot,
21241    edits: &[(Range<Anchor>, String)],
21242    edit_preview: &EditPreview,
21243    include_deletions: bool,
21244    cx: &App,
21245) -> HighlightedText {
21246    let edits = edits
21247        .iter()
21248        .map(|(anchor, text)| {
21249            (
21250                anchor.start.text_anchor..anchor.end.text_anchor,
21251                text.clone(),
21252            )
21253        })
21254        .collect::<Vec<_>>();
21255
21256    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21257}
21258
21259pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21260    match severity {
21261        lsp::DiagnosticSeverity::ERROR => colors.error,
21262        lsp::DiagnosticSeverity::WARNING => colors.warning,
21263        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21264        lsp::DiagnosticSeverity::HINT => colors.info,
21265        _ => colors.ignored,
21266    }
21267}
21268
21269pub fn styled_runs_for_code_label<'a>(
21270    label: &'a CodeLabel,
21271    syntax_theme: &'a theme::SyntaxTheme,
21272) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21273    let fade_out = HighlightStyle {
21274        fade_out: Some(0.35),
21275        ..Default::default()
21276    };
21277
21278    let mut prev_end = label.filter_range.end;
21279    label
21280        .runs
21281        .iter()
21282        .enumerate()
21283        .flat_map(move |(ix, (range, highlight_id))| {
21284            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21285                style
21286            } else {
21287                return Default::default();
21288            };
21289            let mut muted_style = style;
21290            muted_style.highlight(fade_out);
21291
21292            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21293            if range.start >= label.filter_range.end {
21294                if range.start > prev_end {
21295                    runs.push((prev_end..range.start, fade_out));
21296                }
21297                runs.push((range.clone(), muted_style));
21298            } else if range.end <= label.filter_range.end {
21299                runs.push((range.clone(), style));
21300            } else {
21301                runs.push((range.start..label.filter_range.end, style));
21302                runs.push((label.filter_range.end..range.end, muted_style));
21303            }
21304            prev_end = cmp::max(prev_end, range.end);
21305
21306            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21307                runs.push((prev_end..label.text.len(), fade_out));
21308            }
21309
21310            runs
21311        })
21312}
21313
21314pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21315    let mut prev_index = 0;
21316    let mut prev_codepoint: Option<char> = None;
21317    text.char_indices()
21318        .chain([(text.len(), '\0')])
21319        .filter_map(move |(index, codepoint)| {
21320            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21321            let is_boundary = index == text.len()
21322                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21323                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21324            if is_boundary {
21325                let chunk = &text[prev_index..index];
21326                prev_index = index;
21327                Some(chunk)
21328            } else {
21329                None
21330            }
21331        })
21332}
21333
21334pub trait RangeToAnchorExt: Sized {
21335    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21336
21337    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21338        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21339        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21340    }
21341}
21342
21343impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21344    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21345        let start_offset = self.start.to_offset(snapshot);
21346        let end_offset = self.end.to_offset(snapshot);
21347        if start_offset == end_offset {
21348            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21349        } else {
21350            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21351        }
21352    }
21353}
21354
21355pub trait RowExt {
21356    fn as_f32(&self) -> f32;
21357
21358    fn next_row(&self) -> Self;
21359
21360    fn previous_row(&self) -> Self;
21361
21362    fn minus(&self, other: Self) -> u32;
21363}
21364
21365impl RowExt for DisplayRow {
21366    fn as_f32(&self) -> f32 {
21367        self.0 as f32
21368    }
21369
21370    fn next_row(&self) -> Self {
21371        Self(self.0 + 1)
21372    }
21373
21374    fn previous_row(&self) -> Self {
21375        Self(self.0.saturating_sub(1))
21376    }
21377
21378    fn minus(&self, other: Self) -> u32 {
21379        self.0 - other.0
21380    }
21381}
21382
21383impl RowExt for MultiBufferRow {
21384    fn as_f32(&self) -> f32 {
21385        self.0 as f32
21386    }
21387
21388    fn next_row(&self) -> Self {
21389        Self(self.0 + 1)
21390    }
21391
21392    fn previous_row(&self) -> Self {
21393        Self(self.0.saturating_sub(1))
21394    }
21395
21396    fn minus(&self, other: Self) -> u32 {
21397        self.0 - other.0
21398    }
21399}
21400
21401trait RowRangeExt {
21402    type Row;
21403
21404    fn len(&self) -> usize;
21405
21406    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21407}
21408
21409impl RowRangeExt for Range<MultiBufferRow> {
21410    type Row = MultiBufferRow;
21411
21412    fn len(&self) -> usize {
21413        (self.end.0 - self.start.0) as usize
21414    }
21415
21416    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21417        (self.start.0..self.end.0).map(MultiBufferRow)
21418    }
21419}
21420
21421impl RowRangeExt for Range<DisplayRow> {
21422    type Row = DisplayRow;
21423
21424    fn len(&self) -> usize {
21425        (self.end.0 - self.start.0) as usize
21426    }
21427
21428    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21429        (self.start.0..self.end.0).map(DisplayRow)
21430    }
21431}
21432
21433/// If select range has more than one line, we
21434/// just point the cursor to range.start.
21435fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21436    if range.start.row == range.end.row {
21437        range
21438    } else {
21439        range.start..range.start
21440    }
21441}
21442pub struct KillRing(ClipboardItem);
21443impl Global for KillRing {}
21444
21445const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21446
21447enum BreakpointPromptEditAction {
21448    Log,
21449    Condition,
21450    HitCondition,
21451}
21452
21453struct BreakpointPromptEditor {
21454    pub(crate) prompt: Entity<Editor>,
21455    editor: WeakEntity<Editor>,
21456    breakpoint_anchor: Anchor,
21457    breakpoint: Breakpoint,
21458    edit_action: BreakpointPromptEditAction,
21459    block_ids: HashSet<CustomBlockId>,
21460    editor_margins: Arc<Mutex<EditorMargins>>,
21461    _subscriptions: Vec<Subscription>,
21462}
21463
21464impl BreakpointPromptEditor {
21465    const MAX_LINES: u8 = 4;
21466
21467    fn new(
21468        editor: WeakEntity<Editor>,
21469        breakpoint_anchor: Anchor,
21470        breakpoint: Breakpoint,
21471        edit_action: BreakpointPromptEditAction,
21472        window: &mut Window,
21473        cx: &mut Context<Self>,
21474    ) -> Self {
21475        let base_text = match edit_action {
21476            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21477            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21478            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21479        }
21480        .map(|msg| msg.to_string())
21481        .unwrap_or_default();
21482
21483        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21484        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21485
21486        let prompt = cx.new(|cx| {
21487            let mut prompt = Editor::new(
21488                EditorMode::AutoHeight {
21489                    max_lines: Self::MAX_LINES as usize,
21490                },
21491                buffer,
21492                None,
21493                window,
21494                cx,
21495            );
21496            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21497            prompt.set_show_cursor_when_unfocused(false, cx);
21498            prompt.set_placeholder_text(
21499                match edit_action {
21500                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21501                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21502                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21503                },
21504                cx,
21505            );
21506
21507            prompt
21508        });
21509
21510        Self {
21511            prompt,
21512            editor,
21513            breakpoint_anchor,
21514            breakpoint,
21515            edit_action,
21516            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21517            block_ids: Default::default(),
21518            _subscriptions: vec![],
21519        }
21520    }
21521
21522    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21523        self.block_ids.extend(block_ids)
21524    }
21525
21526    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21527        if let Some(editor) = self.editor.upgrade() {
21528            let message = self
21529                .prompt
21530                .read(cx)
21531                .buffer
21532                .read(cx)
21533                .as_singleton()
21534                .expect("A multi buffer in breakpoint prompt isn't possible")
21535                .read(cx)
21536                .as_rope()
21537                .to_string();
21538
21539            editor.update(cx, |editor, cx| {
21540                editor.edit_breakpoint_at_anchor(
21541                    self.breakpoint_anchor,
21542                    self.breakpoint.clone(),
21543                    match self.edit_action {
21544                        BreakpointPromptEditAction::Log => {
21545                            BreakpointEditAction::EditLogMessage(message.into())
21546                        }
21547                        BreakpointPromptEditAction::Condition => {
21548                            BreakpointEditAction::EditCondition(message.into())
21549                        }
21550                        BreakpointPromptEditAction::HitCondition => {
21551                            BreakpointEditAction::EditHitCondition(message.into())
21552                        }
21553                    },
21554                    cx,
21555                );
21556
21557                editor.remove_blocks(self.block_ids.clone(), None, cx);
21558                cx.focus_self(window);
21559            });
21560        }
21561    }
21562
21563    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21564        self.editor
21565            .update(cx, |editor, cx| {
21566                editor.remove_blocks(self.block_ids.clone(), None, cx);
21567                window.focus(&editor.focus_handle);
21568            })
21569            .log_err();
21570    }
21571
21572    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21573        let settings = ThemeSettings::get_global(cx);
21574        let text_style = TextStyle {
21575            color: if self.prompt.read(cx).read_only(cx) {
21576                cx.theme().colors().text_disabled
21577            } else {
21578                cx.theme().colors().text
21579            },
21580            font_family: settings.buffer_font.family.clone(),
21581            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21582            font_size: settings.buffer_font_size(cx).into(),
21583            font_weight: settings.buffer_font.weight,
21584            line_height: relative(settings.buffer_line_height.value()),
21585            ..Default::default()
21586        };
21587        EditorElement::new(
21588            &self.prompt,
21589            EditorStyle {
21590                background: cx.theme().colors().editor_background,
21591                local_player: cx.theme().players().local(),
21592                text: text_style,
21593                ..Default::default()
21594            },
21595        )
21596    }
21597}
21598
21599impl Render for BreakpointPromptEditor {
21600    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21601        let editor_margins = *self.editor_margins.lock();
21602        let gutter_dimensions = editor_margins.gutter;
21603        h_flex()
21604            .key_context("Editor")
21605            .bg(cx.theme().colors().editor_background)
21606            .border_y_1()
21607            .border_color(cx.theme().status().info_border)
21608            .size_full()
21609            .py(window.line_height() / 2.5)
21610            .on_action(cx.listener(Self::confirm))
21611            .on_action(cx.listener(Self::cancel))
21612            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21613            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21614    }
21615}
21616
21617impl Focusable for BreakpointPromptEditor {
21618    fn focus_handle(&self, cx: &App) -> FocusHandle {
21619        self.prompt.focus_handle(cx)
21620    }
21621}
21622
21623fn all_edits_insertions_or_deletions(
21624    edits: &Vec<(Range<Anchor>, String)>,
21625    snapshot: &MultiBufferSnapshot,
21626) -> bool {
21627    let mut all_insertions = true;
21628    let mut all_deletions = true;
21629
21630    for (range, new_text) in edits.iter() {
21631        let range_is_empty = range.to_offset(&snapshot).is_empty();
21632        let text_is_empty = new_text.is_empty();
21633
21634        if range_is_empty != text_is_empty {
21635            if range_is_empty {
21636                all_deletions = false;
21637            } else {
21638                all_insertions = false;
21639            }
21640        } else {
21641            return false;
21642        }
21643
21644        if !all_insertions && !all_deletions {
21645            return false;
21646        }
21647    }
21648    all_insertions || all_deletions
21649}
21650
21651struct MissingEditPredictionKeybindingTooltip;
21652
21653impl Render for MissingEditPredictionKeybindingTooltip {
21654    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21655        ui::tooltip_container(window, cx, |container, _, cx| {
21656            container
21657                .flex_shrink_0()
21658                .max_w_80()
21659                .min_h(rems_from_px(124.))
21660                .justify_between()
21661                .child(
21662                    v_flex()
21663                        .flex_1()
21664                        .text_ui_sm(cx)
21665                        .child(Label::new("Conflict with Accept Keybinding"))
21666                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21667                )
21668                .child(
21669                    h_flex()
21670                        .pb_1()
21671                        .gap_1()
21672                        .items_end()
21673                        .w_full()
21674                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21675                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21676                        }))
21677                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21678                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21679                        })),
21680                )
21681        })
21682    }
21683}
21684
21685#[derive(Debug, Clone, Copy, PartialEq)]
21686pub struct LineHighlight {
21687    pub background: Background,
21688    pub border: Option<gpui::Hsla>,
21689    pub include_gutter: bool,
21690    pub type_id: Option<TypeId>,
21691}
21692
21693fn render_diff_hunk_controls(
21694    row: u32,
21695    status: &DiffHunkStatus,
21696    hunk_range: Range<Anchor>,
21697    is_created_file: bool,
21698    line_height: Pixels,
21699    editor: &Entity<Editor>,
21700    _window: &mut Window,
21701    cx: &mut App,
21702) -> AnyElement {
21703    h_flex()
21704        .h(line_height)
21705        .mr_1()
21706        .gap_1()
21707        .px_0p5()
21708        .pb_1()
21709        .border_x_1()
21710        .border_b_1()
21711        .border_color(cx.theme().colors().border_variant)
21712        .rounded_b_lg()
21713        .bg(cx.theme().colors().editor_background)
21714        .gap_1()
21715        .occlude()
21716        .shadow_md()
21717        .child(if status.has_secondary_hunk() {
21718            Button::new(("stage", row as u64), "Stage")
21719                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21720                .tooltip({
21721                    let focus_handle = editor.focus_handle(cx);
21722                    move |window, cx| {
21723                        Tooltip::for_action_in(
21724                            "Stage Hunk",
21725                            &::git::ToggleStaged,
21726                            &focus_handle,
21727                            window,
21728                            cx,
21729                        )
21730                    }
21731                })
21732                .on_click({
21733                    let editor = editor.clone();
21734                    move |_event, _window, cx| {
21735                        editor.update(cx, |editor, cx| {
21736                            editor.stage_or_unstage_diff_hunks(
21737                                true,
21738                                vec![hunk_range.start..hunk_range.start],
21739                                cx,
21740                            );
21741                        });
21742                    }
21743                })
21744        } else {
21745            Button::new(("unstage", row as u64), "Unstage")
21746                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21747                .tooltip({
21748                    let focus_handle = editor.focus_handle(cx);
21749                    move |window, cx| {
21750                        Tooltip::for_action_in(
21751                            "Unstage Hunk",
21752                            &::git::ToggleStaged,
21753                            &focus_handle,
21754                            window,
21755                            cx,
21756                        )
21757                    }
21758                })
21759                .on_click({
21760                    let editor = editor.clone();
21761                    move |_event, _window, cx| {
21762                        editor.update(cx, |editor, cx| {
21763                            editor.stage_or_unstage_diff_hunks(
21764                                false,
21765                                vec![hunk_range.start..hunk_range.start],
21766                                cx,
21767                            );
21768                        });
21769                    }
21770                })
21771        })
21772        .child(
21773            Button::new(("restore", row as u64), "Restore")
21774                .tooltip({
21775                    let focus_handle = editor.focus_handle(cx);
21776                    move |window, cx| {
21777                        Tooltip::for_action_in(
21778                            "Restore Hunk",
21779                            &::git::Restore,
21780                            &focus_handle,
21781                            window,
21782                            cx,
21783                        )
21784                    }
21785                })
21786                .on_click({
21787                    let editor = editor.clone();
21788                    move |_event, window, cx| {
21789                        editor.update(cx, |editor, cx| {
21790                            let snapshot = editor.snapshot(window, cx);
21791                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21792                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21793                        });
21794                    }
21795                })
21796                .disabled(is_created_file),
21797        )
21798        .when(
21799            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21800            |el| {
21801                el.child(
21802                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21803                        .shape(IconButtonShape::Square)
21804                        .icon_size(IconSize::Small)
21805                        // .disabled(!has_multiple_hunks)
21806                        .tooltip({
21807                            let focus_handle = editor.focus_handle(cx);
21808                            move |window, cx| {
21809                                Tooltip::for_action_in(
21810                                    "Next Hunk",
21811                                    &GoToHunk,
21812                                    &focus_handle,
21813                                    window,
21814                                    cx,
21815                                )
21816                            }
21817                        })
21818                        .on_click({
21819                            let editor = editor.clone();
21820                            move |_event, window, cx| {
21821                                editor.update(cx, |editor, cx| {
21822                                    let snapshot = editor.snapshot(window, cx);
21823                                    let position =
21824                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21825                                    editor.go_to_hunk_before_or_after_position(
21826                                        &snapshot,
21827                                        position,
21828                                        Direction::Next,
21829                                        window,
21830                                        cx,
21831                                    );
21832                                    editor.expand_selected_diff_hunks(cx);
21833                                });
21834                            }
21835                        }),
21836                )
21837                .child(
21838                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21839                        .shape(IconButtonShape::Square)
21840                        .icon_size(IconSize::Small)
21841                        // .disabled(!has_multiple_hunks)
21842                        .tooltip({
21843                            let focus_handle = editor.focus_handle(cx);
21844                            move |window, cx| {
21845                                Tooltip::for_action_in(
21846                                    "Previous Hunk",
21847                                    &GoToPreviousHunk,
21848                                    &focus_handle,
21849                                    window,
21850                                    cx,
21851                                )
21852                            }
21853                        })
21854                        .on_click({
21855                            let editor = editor.clone();
21856                            move |_event, window, cx| {
21857                                editor.update(cx, |editor, cx| {
21858                                    let snapshot = editor.snapshot(window, cx);
21859                                    let point =
21860                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21861                                    editor.go_to_hunk_before_or_after_position(
21862                                        &snapshot,
21863                                        point,
21864                                        Direction::Prev,
21865                                        window,
21866                                        cx,
21867                                    );
21868                                    editor.expand_selected_diff_hunks(cx);
21869                                });
21870                            }
21871                        }),
21872                )
21873            },
21874        )
21875        .into_any_element()
21876}