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_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47#[cfg(test)]
   48mod inline_completion_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   55use aho_corasick::AhoCorasick;
   56use anyhow::{Context as _, Result, anyhow};
   57use blink_manager::BlinkManager;
   58use buffer_diff::DiffHunkStatus;
   59use client::{Collaborator, ParticipantIndex};
   60use clock::{AGENT_REPLICA_ID, ReplicaId};
   61use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   62use convert_case::{Case, Casing};
   63use dap::TelemetrySpawnLocation;
   64use display_map::*;
   65pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   66pub use editor_settings::{
   67    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   68    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowScrollbar,
   69};
   70use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   71pub use editor_settings_controls::*;
   72use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   73pub use element::{
   74    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   75};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82use lsp_colors::LspColorData;
   83
   84use ::git::blame::BlameEntry;
   85use ::git::{Restore, blame::ParsedCommitMessage};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use git::blame::{GitBlame, GlobalBlameRenderer};
   91use gpui::{
   92    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   93    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   94    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   95    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   96    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   97    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   98    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   99    div, point, prelude::*, pulsating_between, px, relative, size,
  100};
  101use highlight_matching_bracket::refresh_matching_bracket_highlights;
  102use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  103pub use hover_popover::hover_markdown_style;
  104use hover_popover::{HoverState, hide_hover};
  105use indent_guides::ActiveIndentGuidesState;
  106use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  107pub use inline_completion::Direction;
  108use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  109pub use items::MAX_TAB_TITLE_LEN;
  110use itertools::Itertools;
  111use language::{
  112    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  113    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  114    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  115    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, ProjectPath,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    git_store::{GitStoreEvent, RepositoryEvent},
  137    project_settings::DiagnosticSeverity,
  138};
  139
  140pub use git::blame::BlameRenderer;
  141pub use proposed_changes_editor::{
  142    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  143};
  144use std::{cell::OnceCell, iter::Peekable, ops::Not};
  145use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  146
  147pub use lsp::CompletionContext;
  148use lsp::{
  149    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  150    LanguageServerId, LanguageServerName,
  151};
  152
  153use language::BufferSnapshot;
  154pub use lsp_ext::lsp_tasks;
  155use movement::TextLayoutDetails;
  156pub use multi_buffer::{
  157    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  158    RowInfo, ToOffset, ToPoint,
  159};
  160use multi_buffer::{
  161    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  162    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  163};
  164use parking_lot::Mutex;
  165use project::{
  166    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  167    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  168    TaskSourceKind,
  169    debugger::breakpoint_store::Breakpoint,
  170    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  171    project_settings::{GitGutterSetting, ProjectSettings},
  172};
  173use rand::prelude::*;
  174use rpc::{ErrorExt, proto::*};
  175use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  176use selections_collection::{
  177    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  178};
  179use serde::{Deserialize, Serialize};
  180use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  181use smallvec::{SmallVec, smallvec};
  182use snippet::Snippet;
  183use std::sync::Arc;
  184use std::{
  185    any::TypeId,
  186    borrow::Cow,
  187    cell::RefCell,
  188    cmp::{self, Ordering, Reverse},
  189    mem,
  190    num::NonZeroU32,
  191    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  192    path::{Path, PathBuf},
  193    rc::Rc,
  194    time::{Duration, Instant},
  195};
  196pub use sum_tree::Bias;
  197use sum_tree::TreeMap;
  198use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  199use theme::{
  200    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  201    observe_buffer_font_size_adjustment,
  202};
  203use ui::{
  204    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  205    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  206};
  207use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  208use workspace::{
  209    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  210    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  211    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  212    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  213    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  214    searchable::SearchEvent,
  215};
  216
  217use crate::{
  218    code_context_menus::CompletionsMenuSource,
  219    hover_links::{find_url, find_url_from_range},
  220};
  221use crate::{
  222    editor_settings::MultiCursorModifier,
  223    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  224};
  225
  226pub const FILE_HEADER_HEIGHT: u32 = 2;
  227pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  228pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  229const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  230const MAX_LINE_LEN: usize = 1024;
  231const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  232const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  233pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  234#[doc(hidden)]
  235pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  236const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  237
  238pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  241
  242pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  243pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  244pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  245
  246pub type RenderDiffHunkControlsFn = Arc<
  247    dyn Fn(
  248        u32,
  249        &DiffHunkStatus,
  250        Range<Anchor>,
  251        bool,
  252        Pixels,
  253        &Entity<Editor>,
  254        &mut Window,
  255        &mut App,
  256    ) -> AnyElement,
  257>;
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    DebuggerValue(usize),
  279    // LSP
  280    Hint(usize),
  281    Color(usize),
  282}
  283
  284impl InlayId {
  285    fn id(&self) -> usize {
  286        match self {
  287            Self::InlineCompletion(id) => *id,
  288            Self::DebuggerValue(id) => *id,
  289            Self::Hint(id) => *id,
  290            Self::Color(id) => *id,
  291        }
  292    }
  293}
  294
  295pub enum ActiveDebugLine {}
  296pub enum DebugStackFrameLine {}
  297enum DocumentHighlightRead {}
  298enum DocumentHighlightWrite {}
  299enum InputComposition {}
  300pub enum PendingInput {}
  301enum SelectedTextHighlight {}
  302
  303pub enum ConflictsOuter {}
  304pub enum ConflictsOurs {}
  305pub enum ConflictsTheirs {}
  306pub enum ConflictsOursMarker {}
  307pub enum ConflictsTheirsMarker {}
  308
  309#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  310pub enum Navigated {
  311    Yes,
  312    No,
  313}
  314
  315impl Navigated {
  316    pub fn from_bool(yes: bool) -> Navigated {
  317        if yes { Navigated::Yes } else { Navigated::No }
  318    }
  319}
  320
  321#[derive(Debug, Clone, PartialEq, Eq)]
  322enum DisplayDiffHunk {
  323    Folded {
  324        display_row: DisplayRow,
  325    },
  326    Unfolded {
  327        is_created_file: bool,
  328        diff_base_byte_range: Range<usize>,
  329        display_row_range: Range<DisplayRow>,
  330        multi_buffer_range: Range<Anchor>,
  331        status: DiffHunkStatus,
  332    },
  333}
  334
  335pub enum HideMouseCursorOrigin {
  336    TypingAction,
  337    MovementAction,
  338}
  339
  340pub fn init_settings(cx: &mut App) {
  341    EditorSettings::register(cx);
  342}
  343
  344pub fn init(cx: &mut App) {
  345    init_settings(cx);
  346
  347    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  348
  349    workspace::register_project_item::<Editor>(cx);
  350    workspace::FollowableViewRegistry::register::<Editor>(cx);
  351    workspace::register_serializable_item::<Editor>(cx);
  352
  353    cx.observe_new(
  354        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  355            workspace.register_action(Editor::new_file);
  356            workspace.register_action(Editor::new_file_vertical);
  357            workspace.register_action(Editor::new_file_horizontal);
  358            workspace.register_action(Editor::cancel_language_server_work);
  359        },
  360    )
  361    .detach();
  362
  363    cx.on_action(move |_: &workspace::NewFile, cx| {
  364        let app_state = workspace::AppState::global(cx);
  365        if let Some(app_state) = app_state.upgrade() {
  366            workspace::open_new(
  367                Default::default(),
  368                app_state,
  369                cx,
  370                |workspace, window, cx| {
  371                    Editor::new_file(workspace, &Default::default(), window, cx)
  372                },
  373            )
  374            .detach();
  375        }
  376    });
  377    cx.on_action(move |_: &workspace::NewWindow, cx| {
  378        let app_state = workspace::AppState::global(cx);
  379        if let Some(app_state) = app_state.upgrade() {
  380            workspace::open_new(
  381                Default::default(),
  382                app_state,
  383                cx,
  384                |workspace, window, cx| {
  385                    cx.activate(true);
  386                    Editor::new_file(workspace, &Default::default(), window, cx)
  387                },
  388            )
  389            .detach();
  390        }
  391    });
  392}
  393
  394pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  395    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  396}
  397
  398pub trait DiagnosticRenderer {
  399    fn render_group(
  400        &self,
  401        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  402        buffer_id: BufferId,
  403        snapshot: EditorSnapshot,
  404        editor: WeakEntity<Editor>,
  405        cx: &mut App,
  406    ) -> Vec<BlockProperties<Anchor>>;
  407
  408    fn render_hover(
  409        &self,
  410        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  411        range: Range<Point>,
  412        buffer_id: BufferId,
  413        cx: &mut App,
  414    ) -> Option<Entity<markdown::Markdown>>;
  415
  416    fn open_link(
  417        &self,
  418        editor: &mut Editor,
  419        link: SharedString,
  420        window: &mut Window,
  421        cx: &mut Context<Editor>,
  422    );
  423}
  424
  425pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  426
  427impl GlobalDiagnosticRenderer {
  428    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  429        cx.try_global::<Self>().map(|g| g.0.clone())
  430    }
  431}
  432
  433impl gpui::Global for GlobalDiagnosticRenderer {}
  434pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  435    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  436}
  437
  438pub struct SearchWithinRange;
  439
  440trait InvalidationRegion {
  441    fn ranges(&self) -> &[Range<Anchor>];
  442}
  443
  444#[derive(Clone, Debug, PartialEq)]
  445pub enum SelectPhase {
  446    Begin {
  447        position: DisplayPoint,
  448        add: bool,
  449        click_count: usize,
  450    },
  451    BeginColumnar {
  452        position: DisplayPoint,
  453        reset: bool,
  454        mode: ColumnarMode,
  455        goal_column: u32,
  456    },
  457    Extend {
  458        position: DisplayPoint,
  459        click_count: usize,
  460    },
  461    Update {
  462        position: DisplayPoint,
  463        goal_column: u32,
  464        scroll_delta: gpui::Point<f32>,
  465    },
  466    End,
  467}
  468
  469#[derive(Clone, Debug, PartialEq)]
  470pub enum ColumnarMode {
  471    FromMouse,
  472    FromSelection,
  473}
  474
  475#[derive(Clone, Debug)]
  476pub enum SelectMode {
  477    Character,
  478    Word(Range<Anchor>),
  479    Line(Range<Anchor>),
  480    All,
  481}
  482
  483#[derive(Clone, PartialEq, Eq, Debug)]
  484pub enum EditorMode {
  485    SingleLine {
  486        auto_width: bool,
  487    },
  488    AutoHeight {
  489        min_lines: usize,
  490        max_lines: Option<usize>,
  491    },
  492    Full {
  493        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  494        scale_ui_elements_with_buffer_font_size: bool,
  495        /// When set to `true`, the editor will render a background for the active line.
  496        show_active_line_background: bool,
  497        /// When set to `true`, the editor's height will be determined by its content.
  498        sized_by_content: bool,
  499    },
  500    Minimap {
  501        parent: WeakEntity<Editor>,
  502    },
  503}
  504
  505impl EditorMode {
  506    pub fn full() -> Self {
  507        Self::Full {
  508            scale_ui_elements_with_buffer_font_size: true,
  509            show_active_line_background: true,
  510            sized_by_content: false,
  511        }
  512    }
  513
  514    #[inline]
  515    pub fn is_full(&self) -> bool {
  516        matches!(self, Self::Full { .. })
  517    }
  518
  519    #[inline]
  520    pub fn is_single_line(&self) -> bool {
  521        matches!(self, Self::SingleLine { .. })
  522    }
  523
  524    #[inline]
  525    fn is_minimap(&self) -> bool {
  526        matches!(self, Self::Minimap { .. })
  527    }
  528}
  529
  530#[derive(Copy, Clone, Debug)]
  531pub enum SoftWrap {
  532    /// Prefer not to wrap at all.
  533    ///
  534    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  535    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  536    GitDiff,
  537    /// Prefer a single line generally, unless an overly long line is encountered.
  538    None,
  539    /// Soft wrap lines that exceed the editor width.
  540    EditorWidth,
  541    /// Soft wrap lines at the preferred line length.
  542    Column(u32),
  543    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  544    Bounded(u32),
  545}
  546
  547#[derive(Clone)]
  548pub struct EditorStyle {
  549    pub background: Hsla,
  550    pub local_player: PlayerColor,
  551    pub text: TextStyle,
  552    pub scrollbar_width: Pixels,
  553    pub syntax: Arc<SyntaxTheme>,
  554    pub status: StatusColors,
  555    pub inlay_hints_style: HighlightStyle,
  556    pub inline_completion_styles: InlineCompletionStyles,
  557    pub unnecessary_code_fade: f32,
  558    pub show_underlines: bool,
  559}
  560
  561impl Default for EditorStyle {
  562    fn default() -> Self {
  563        Self {
  564            background: Hsla::default(),
  565            local_player: PlayerColor::default(),
  566            text: TextStyle::default(),
  567            scrollbar_width: Pixels::default(),
  568            syntax: Default::default(),
  569            // HACK: Status colors don't have a real default.
  570            // We should look into removing the status colors from the editor
  571            // style and retrieve them directly from the theme.
  572            status: StatusColors::dark(),
  573            inlay_hints_style: HighlightStyle::default(),
  574            inline_completion_styles: InlineCompletionStyles {
  575                insertion: HighlightStyle::default(),
  576                whitespace: HighlightStyle::default(),
  577            },
  578            unnecessary_code_fade: Default::default(),
  579            show_underlines: true,
  580        }
  581    }
  582}
  583
  584pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  585    let show_background = language_settings::language_settings(None, None, cx)
  586        .inlay_hints
  587        .show_background;
  588
  589    HighlightStyle {
  590        color: Some(cx.theme().status().hint),
  591        background_color: show_background.then(|| cx.theme().status().hint_background),
  592        ..HighlightStyle::default()
  593    }
  594}
  595
  596pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  597    InlineCompletionStyles {
  598        insertion: HighlightStyle {
  599            color: Some(cx.theme().status().predictive),
  600            ..HighlightStyle::default()
  601        },
  602        whitespace: HighlightStyle {
  603            background_color: Some(cx.theme().status().created_background),
  604            ..HighlightStyle::default()
  605        },
  606    }
  607}
  608
  609type CompletionId = usize;
  610
  611pub(crate) enum EditDisplayMode {
  612    TabAccept,
  613    DiffPopover,
  614    Inline,
  615}
  616
  617enum InlineCompletion {
  618    Edit {
  619        edits: Vec<(Range<Anchor>, String)>,
  620        edit_preview: Option<EditPreview>,
  621        display_mode: EditDisplayMode,
  622        snapshot: BufferSnapshot,
  623    },
  624    Move {
  625        target: Anchor,
  626        snapshot: BufferSnapshot,
  627    },
  628}
  629
  630struct InlineCompletionState {
  631    inlay_ids: Vec<InlayId>,
  632    completion: InlineCompletion,
  633    completion_id: Option<SharedString>,
  634    invalidation_range: Range<Anchor>,
  635}
  636
  637enum EditPredictionSettings {
  638    Disabled,
  639    Enabled {
  640        show_in_menu: bool,
  641        preview_requires_modifier: bool,
  642    },
  643}
  644
  645enum InlineCompletionHighlight {}
  646
  647#[derive(Debug, Clone)]
  648struct InlineDiagnostic {
  649    message: SharedString,
  650    group_id: usize,
  651    is_primary: bool,
  652    start: Point,
  653    severity: lsp::DiagnosticSeverity,
  654}
  655
  656pub enum MenuInlineCompletionsPolicy {
  657    Never,
  658    ByProvider,
  659}
  660
  661pub enum EditPredictionPreview {
  662    /// Modifier is not pressed
  663    Inactive { released_too_fast: bool },
  664    /// Modifier pressed
  665    Active {
  666        since: Instant,
  667        previous_scroll_position: Option<ScrollAnchor>,
  668    },
  669}
  670
  671impl EditPredictionPreview {
  672    pub fn released_too_fast(&self) -> bool {
  673        match self {
  674            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  675            EditPredictionPreview::Active { .. } => false,
  676        }
  677    }
  678
  679    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  680        if let EditPredictionPreview::Active {
  681            previous_scroll_position,
  682            ..
  683        } = self
  684        {
  685            *previous_scroll_position = scroll_position;
  686        }
  687    }
  688}
  689
  690pub struct ContextMenuOptions {
  691    pub min_entries_visible: usize,
  692    pub max_entries_visible: usize,
  693    pub placement: Option<ContextMenuPlacement>,
  694}
  695
  696#[derive(Debug, Clone, PartialEq, Eq)]
  697pub enum ContextMenuPlacement {
  698    Above,
  699    Below,
  700}
  701
  702#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  703struct EditorActionId(usize);
  704
  705impl EditorActionId {
  706    pub fn post_inc(&mut self) -> Self {
  707        let answer = self.0;
  708
  709        *self = Self(answer + 1);
  710
  711        Self(answer)
  712    }
  713}
  714
  715// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  716// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  717
  718type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  719type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  720
  721#[derive(Default)]
  722struct ScrollbarMarkerState {
  723    scrollbar_size: Size<Pixels>,
  724    dirty: bool,
  725    markers: Arc<[PaintQuad]>,
  726    pending_refresh: Option<Task<Result<()>>>,
  727}
  728
  729impl ScrollbarMarkerState {
  730    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  731        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  732    }
  733}
  734
  735#[derive(Clone, Copy, PartialEq, Eq)]
  736pub enum MinimapVisibility {
  737    Disabled,
  738    Enabled {
  739        /// The configuration currently present in the users settings.
  740        setting_configuration: bool,
  741        /// Whether to override the currently set visibility from the users setting.
  742        toggle_override: bool,
  743    },
  744}
  745
  746impl MinimapVisibility {
  747    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  748        if mode.is_full() {
  749            Self::Enabled {
  750                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  751                toggle_override: false,
  752            }
  753        } else {
  754            Self::Disabled
  755        }
  756    }
  757
  758    fn hidden(&self) -> Self {
  759        match *self {
  760            Self::Enabled {
  761                setting_configuration,
  762                ..
  763            } => Self::Enabled {
  764                setting_configuration,
  765                toggle_override: setting_configuration,
  766            },
  767            Self::Disabled => Self::Disabled,
  768        }
  769    }
  770
  771    fn disabled(&self) -> bool {
  772        match *self {
  773            Self::Disabled => true,
  774            _ => false,
  775        }
  776    }
  777
  778    fn settings_visibility(&self) -> bool {
  779        match *self {
  780            Self::Enabled {
  781                setting_configuration,
  782                ..
  783            } => setting_configuration,
  784            _ => false,
  785        }
  786    }
  787
  788    fn visible(&self) -> bool {
  789        match *self {
  790            Self::Enabled {
  791                setting_configuration,
  792                toggle_override,
  793            } => setting_configuration ^ toggle_override,
  794            _ => false,
  795        }
  796    }
  797
  798    fn toggle_visibility(&self) -> Self {
  799        match *self {
  800            Self::Enabled {
  801                toggle_override,
  802                setting_configuration,
  803            } => Self::Enabled {
  804                setting_configuration,
  805                toggle_override: !toggle_override,
  806            },
  807            Self::Disabled => Self::Disabled,
  808        }
  809    }
  810}
  811
  812#[derive(Clone, Debug)]
  813struct RunnableTasks {
  814    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  815    offset: multi_buffer::Anchor,
  816    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  817    column: u32,
  818    // Values of all named captures, including those starting with '_'
  819    extra_variables: HashMap<String, String>,
  820    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  821    context_range: Range<BufferOffset>,
  822}
  823
  824impl RunnableTasks {
  825    fn resolve<'a>(
  826        &'a self,
  827        cx: &'a task::TaskContext,
  828    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  829        self.templates.iter().filter_map(|(kind, template)| {
  830            template
  831                .resolve_task(&kind.to_id_base(), cx)
  832                .map(|task| (kind.clone(), task))
  833        })
  834    }
  835}
  836
  837#[derive(Clone)]
  838pub struct ResolvedTasks {
  839    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  840    position: Anchor,
  841}
  842
  843#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  844struct BufferOffset(usize);
  845
  846// Addons allow storing per-editor state in other crates (e.g. Vim)
  847pub trait Addon: 'static {
  848    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  849
  850    fn render_buffer_header_controls(
  851        &self,
  852        _: &ExcerptInfo,
  853        _: &Window,
  854        _: &App,
  855    ) -> Option<AnyElement> {
  856        None
  857    }
  858
  859    fn to_any(&self) -> &dyn std::any::Any;
  860
  861    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  862        None
  863    }
  864}
  865
  866/// A set of caret positions, registered when the editor was edited.
  867pub struct ChangeList {
  868    changes: Vec<Vec<Anchor>>,
  869    /// Currently "selected" change.
  870    position: Option<usize>,
  871}
  872
  873impl ChangeList {
  874    pub fn new() -> Self {
  875        Self {
  876            changes: Vec::new(),
  877            position: None,
  878        }
  879    }
  880
  881    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  882    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  883    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  884        if self.changes.is_empty() {
  885            return None;
  886        }
  887
  888        let prev = self.position.unwrap_or(self.changes.len());
  889        let next = if direction == Direction::Prev {
  890            prev.saturating_sub(count)
  891        } else {
  892            (prev + count).min(self.changes.len() - 1)
  893        };
  894        self.position = Some(next);
  895        self.changes.get(next).map(|anchors| anchors.as_slice())
  896    }
  897
  898    /// Adds a new change to the list, resetting the change list position.
  899    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  900        self.position.take();
  901        if pop_state {
  902            self.changes.pop();
  903        }
  904        self.changes.push(new_positions.clone());
  905    }
  906
  907    pub fn last(&self) -> Option<&[Anchor]> {
  908        self.changes.last().map(|anchors| anchors.as_slice())
  909    }
  910}
  911
  912#[derive(Clone)]
  913struct InlineBlamePopoverState {
  914    scroll_handle: ScrollHandle,
  915    commit_message: Option<ParsedCommitMessage>,
  916    markdown: Entity<Markdown>,
  917}
  918
  919struct InlineBlamePopover {
  920    position: gpui::Point<Pixels>,
  921    hide_task: Option<Task<()>>,
  922    popover_bounds: Option<Bounds<Pixels>>,
  923    popover_state: InlineBlamePopoverState,
  924}
  925
  926enum SelectionDragState {
  927    /// State when no drag related activity is detected.
  928    None,
  929    /// State when the mouse is down on a selection that is about to be dragged.
  930    ReadyToDrag {
  931        selection: Selection<Anchor>,
  932        click_position: gpui::Point<Pixels>,
  933        mouse_down_time: Instant,
  934    },
  935    /// State when the mouse is dragging the selection in the editor.
  936    Dragging {
  937        selection: Selection<Anchor>,
  938        drop_cursor: Selection<Anchor>,
  939        hide_drop_cursor: bool,
  940    },
  941}
  942
  943enum ColumnarSelectionState {
  944    FromMouse {
  945        selection_tail: Anchor,
  946        display_point: Option<DisplayPoint>,
  947    },
  948    FromSelection {
  949        selection_tail: Anchor,
  950    },
  951}
  952
  953/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  954/// a breakpoint on them.
  955#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  956struct PhantomBreakpointIndicator {
  957    display_row: DisplayRow,
  958    /// There's a small debounce between hovering over the line and showing the indicator.
  959    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  960    is_active: bool,
  961    collides_with_existing_breakpoint: bool,
  962}
  963
  964/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  965///
  966/// See the [module level documentation](self) for more information.
  967pub struct Editor {
  968    focus_handle: FocusHandle,
  969    last_focused_descendant: Option<WeakFocusHandle>,
  970    /// The text buffer being edited
  971    buffer: Entity<MultiBuffer>,
  972    /// Map of how text in the buffer should be displayed.
  973    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  974    pub display_map: Entity<DisplayMap>,
  975    pub selections: SelectionsCollection,
  976    pub scroll_manager: ScrollManager,
  977    /// When inline assist editors are linked, they all render cursors because
  978    /// typing enters text into each of them, even the ones that aren't focused.
  979    pub(crate) show_cursor_when_unfocused: bool,
  980    columnar_selection_state: Option<ColumnarSelectionState>,
  981    add_selections_state: Option<AddSelectionsState>,
  982    select_next_state: Option<SelectNextState>,
  983    select_prev_state: Option<SelectNextState>,
  984    selection_history: SelectionHistory,
  985    defer_selection_effects: bool,
  986    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  987    autoclose_regions: Vec<AutocloseRegion>,
  988    snippet_stack: InvalidationStack<SnippetState>,
  989    select_syntax_node_history: SelectSyntaxNodeHistory,
  990    ime_transaction: Option<TransactionId>,
  991    pub diagnostics_max_severity: DiagnosticSeverity,
  992    active_diagnostics: ActiveDiagnostic,
  993    show_inline_diagnostics: bool,
  994    inline_diagnostics_update: Task<()>,
  995    inline_diagnostics_enabled: bool,
  996    diagnostics_enabled: bool,
  997    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  998    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  999    hard_wrap: Option<usize>,
 1000
 1001    // TODO: make this a access method
 1002    pub project: Option<Entity<Project>>,
 1003    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1004    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1005    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1006    blink_manager: Entity<BlinkManager>,
 1007    show_cursor_names: bool,
 1008    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1009    pub show_local_selections: bool,
 1010    mode: EditorMode,
 1011    show_breadcrumbs: bool,
 1012    show_gutter: bool,
 1013    show_scrollbars: ScrollbarAxes,
 1014    minimap_visibility: MinimapVisibility,
 1015    offset_content: bool,
 1016    disable_expand_excerpt_buttons: bool,
 1017    show_line_numbers: Option<bool>,
 1018    use_relative_line_numbers: Option<bool>,
 1019    show_git_diff_gutter: Option<bool>,
 1020    show_code_actions: Option<bool>,
 1021    show_runnables: Option<bool>,
 1022    show_breakpoints: Option<bool>,
 1023    show_wrap_guides: Option<bool>,
 1024    show_indent_guides: Option<bool>,
 1025    placeholder_text: Option<Arc<str>>,
 1026    highlight_order: usize,
 1027    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1028    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1029    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1030    scrollbar_marker_state: ScrollbarMarkerState,
 1031    active_indent_guides_state: ActiveIndentGuidesState,
 1032    nav_history: Option<ItemNavHistory>,
 1033    context_menu: RefCell<Option<CodeContextMenu>>,
 1034    context_menu_options: Option<ContextMenuOptions>,
 1035    mouse_context_menu: Option<MouseContextMenu>,
 1036    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1037    inline_blame_popover: Option<InlineBlamePopover>,
 1038    inline_blame_popover_show_task: Option<Task<()>>,
 1039    signature_help_state: SignatureHelpState,
 1040    auto_signature_help: Option<bool>,
 1041    find_all_references_task_sources: Vec<Anchor>,
 1042    next_completion_id: CompletionId,
 1043    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1044    code_actions_task: Option<Task<Result<()>>>,
 1045    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1046    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1047    document_highlights_task: Option<Task<()>>,
 1048    linked_editing_range_task: Option<Task<Option<()>>>,
 1049    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1050    pending_rename: Option<RenameState>,
 1051    searchable: bool,
 1052    cursor_shape: CursorShape,
 1053    current_line_highlight: Option<CurrentLineHighlight>,
 1054    collapse_matches: bool,
 1055    autoindent_mode: Option<AutoindentMode>,
 1056    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1057    input_enabled: bool,
 1058    use_modal_editing: bool,
 1059    read_only: bool,
 1060    leader_id: Option<CollaboratorId>,
 1061    remote_id: Option<ViewId>,
 1062    pub hover_state: HoverState,
 1063    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1064    gutter_hovered: bool,
 1065    hovered_link_state: Option<HoveredLinkState>,
 1066    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1067    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1068    active_inline_completion: Option<InlineCompletionState>,
 1069    /// Used to prevent flickering as the user types while the menu is open
 1070    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1071    edit_prediction_settings: EditPredictionSettings,
 1072    inline_completions_hidden_for_vim_mode: bool,
 1073    show_inline_completions_override: Option<bool>,
 1074    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1075    edit_prediction_preview: EditPredictionPreview,
 1076    edit_prediction_indent_conflict: bool,
 1077    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1078    inlay_hint_cache: InlayHintCache,
 1079    next_inlay_id: usize,
 1080    _subscriptions: Vec<Subscription>,
 1081    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1082    gutter_dimensions: GutterDimensions,
 1083    style: Option<EditorStyle>,
 1084    text_style_refinement: Option<TextStyleRefinement>,
 1085    next_editor_action_id: EditorActionId,
 1086    editor_actions: Rc<
 1087        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1088    >,
 1089    use_autoclose: bool,
 1090    use_auto_surround: bool,
 1091    auto_replace_emoji_shortcode: bool,
 1092    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1093    show_git_blame_gutter: bool,
 1094    show_git_blame_inline: bool,
 1095    show_git_blame_inline_delay_task: Option<Task<()>>,
 1096    git_blame_inline_enabled: bool,
 1097    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1098    serialize_dirty_buffers: bool,
 1099    show_selection_menu: Option<bool>,
 1100    blame: Option<Entity<GitBlame>>,
 1101    blame_subscription: Option<Subscription>,
 1102    custom_context_menu: Option<
 1103        Box<
 1104            dyn 'static
 1105                + Fn(
 1106                    &mut Self,
 1107                    DisplayPoint,
 1108                    &mut Window,
 1109                    &mut Context<Self>,
 1110                ) -> Option<Entity<ui::ContextMenu>>,
 1111        >,
 1112    >,
 1113    last_bounds: Option<Bounds<Pixels>>,
 1114    last_position_map: Option<Rc<PositionMap>>,
 1115    expect_bounds_change: Option<Bounds<Pixels>>,
 1116    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1117    tasks_update_task: Option<Task<()>>,
 1118    breakpoint_store: Option<Entity<BreakpointStore>>,
 1119    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1120    hovered_diff_hunk_row: Option<DisplayRow>,
 1121    pull_diagnostics_task: Task<()>,
 1122    in_project_search: bool,
 1123    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1124    breadcrumb_header: Option<String>,
 1125    focused_block: Option<FocusedBlock>,
 1126    next_scroll_position: NextScrollCursorCenterTopBottom,
 1127    addons: HashMap<TypeId, Box<dyn Addon>>,
 1128    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1129    load_diff_task: Option<Shared<Task<()>>>,
 1130    /// Whether we are temporarily displaying a diff other than git's
 1131    temporary_diff_override: bool,
 1132    selection_mark_mode: bool,
 1133    toggle_fold_multiple_buffers: Task<()>,
 1134    _scroll_cursor_center_top_bottom_task: Task<()>,
 1135    serialize_selections: Task<()>,
 1136    serialize_folds: Task<()>,
 1137    mouse_cursor_hidden: bool,
 1138    minimap: Option<Entity<Self>>,
 1139    hide_mouse_mode: HideMouseMode,
 1140    pub change_list: ChangeList,
 1141    inline_value_cache: InlineValueCache,
 1142    selection_drag_state: SelectionDragState,
 1143    drag_and_drop_selection_enabled: bool,
 1144    next_color_inlay_id: usize,
 1145    colors: Option<LspColorData>,
 1146}
 1147
 1148#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1149enum NextScrollCursorCenterTopBottom {
 1150    #[default]
 1151    Center,
 1152    Top,
 1153    Bottom,
 1154}
 1155
 1156impl NextScrollCursorCenterTopBottom {
 1157    fn next(&self) -> Self {
 1158        match self {
 1159            Self::Center => Self::Top,
 1160            Self::Top => Self::Bottom,
 1161            Self::Bottom => Self::Center,
 1162        }
 1163    }
 1164}
 1165
 1166#[derive(Clone)]
 1167pub struct EditorSnapshot {
 1168    pub mode: EditorMode,
 1169    show_gutter: bool,
 1170    show_line_numbers: Option<bool>,
 1171    show_git_diff_gutter: Option<bool>,
 1172    show_code_actions: Option<bool>,
 1173    show_runnables: Option<bool>,
 1174    show_breakpoints: Option<bool>,
 1175    git_blame_gutter_max_author_length: Option<usize>,
 1176    pub display_snapshot: DisplaySnapshot,
 1177    pub placeholder_text: Option<Arc<str>>,
 1178    is_focused: bool,
 1179    scroll_anchor: ScrollAnchor,
 1180    ongoing_scroll: OngoingScroll,
 1181    current_line_highlight: CurrentLineHighlight,
 1182    gutter_hovered: bool,
 1183}
 1184
 1185#[derive(Default, Debug, Clone, Copy)]
 1186pub struct GutterDimensions {
 1187    pub left_padding: Pixels,
 1188    pub right_padding: Pixels,
 1189    pub width: Pixels,
 1190    pub margin: Pixels,
 1191    pub git_blame_entries_width: Option<Pixels>,
 1192}
 1193
 1194impl GutterDimensions {
 1195    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1196        Self {
 1197            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1198            ..Default::default()
 1199        }
 1200    }
 1201
 1202    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1203        -cx.text_system().descent(font_id, font_size)
 1204    }
 1205    /// The full width of the space taken up by the gutter.
 1206    pub fn full_width(&self) -> Pixels {
 1207        self.margin + self.width
 1208    }
 1209
 1210    /// The width of the space reserved for the fold indicators,
 1211    /// use alongside 'justify_end' and `gutter_width` to
 1212    /// right align content with the line numbers
 1213    pub fn fold_area_width(&self) -> Pixels {
 1214        self.margin + self.right_padding
 1215    }
 1216}
 1217
 1218#[derive(Debug)]
 1219pub struct RemoteSelection {
 1220    pub replica_id: ReplicaId,
 1221    pub selection: Selection<Anchor>,
 1222    pub cursor_shape: CursorShape,
 1223    pub collaborator_id: CollaboratorId,
 1224    pub line_mode: bool,
 1225    pub user_name: Option<SharedString>,
 1226    pub color: PlayerColor,
 1227}
 1228
 1229#[derive(Clone, Debug)]
 1230struct SelectionHistoryEntry {
 1231    selections: Arc<[Selection<Anchor>]>,
 1232    select_next_state: Option<SelectNextState>,
 1233    select_prev_state: Option<SelectNextState>,
 1234    add_selections_state: Option<AddSelectionsState>,
 1235}
 1236
 1237#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1238enum SelectionHistoryMode {
 1239    Normal,
 1240    Undoing,
 1241    Redoing,
 1242    Skipping,
 1243}
 1244
 1245#[derive(Clone, PartialEq, Eq, Hash)]
 1246struct HoveredCursor {
 1247    replica_id: u16,
 1248    selection_id: usize,
 1249}
 1250
 1251impl Default for SelectionHistoryMode {
 1252    fn default() -> Self {
 1253        Self::Normal
 1254    }
 1255}
 1256
 1257#[derive(Debug)]
 1258pub struct SelectionEffects {
 1259    nav_history: bool,
 1260    completions: bool,
 1261    scroll: Option<Autoscroll>,
 1262}
 1263
 1264impl Default for SelectionEffects {
 1265    fn default() -> Self {
 1266        Self {
 1267            nav_history: true,
 1268            completions: true,
 1269            scroll: Some(Autoscroll::fit()),
 1270        }
 1271    }
 1272}
 1273impl SelectionEffects {
 1274    pub fn scroll(scroll: Autoscroll) -> Self {
 1275        Self {
 1276            scroll: Some(scroll),
 1277            ..Default::default()
 1278        }
 1279    }
 1280
 1281    pub fn no_scroll() -> Self {
 1282        Self {
 1283            scroll: None,
 1284            ..Default::default()
 1285        }
 1286    }
 1287
 1288    pub fn completions(self, completions: bool) -> Self {
 1289        Self {
 1290            completions,
 1291            ..self
 1292        }
 1293    }
 1294
 1295    pub fn nav_history(self, nav_history: bool) -> Self {
 1296        Self {
 1297            nav_history,
 1298            ..self
 1299        }
 1300    }
 1301}
 1302
 1303struct DeferredSelectionEffectsState {
 1304    changed: bool,
 1305    effects: SelectionEffects,
 1306    old_cursor_position: Anchor,
 1307    history_entry: SelectionHistoryEntry,
 1308}
 1309
 1310#[derive(Default)]
 1311struct SelectionHistory {
 1312    #[allow(clippy::type_complexity)]
 1313    selections_by_transaction:
 1314        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1315    mode: SelectionHistoryMode,
 1316    undo_stack: VecDeque<SelectionHistoryEntry>,
 1317    redo_stack: VecDeque<SelectionHistoryEntry>,
 1318}
 1319
 1320impl SelectionHistory {
 1321    #[track_caller]
 1322    fn insert_transaction(
 1323        &mut self,
 1324        transaction_id: TransactionId,
 1325        selections: Arc<[Selection<Anchor>]>,
 1326    ) {
 1327        if selections.is_empty() {
 1328            log::error!(
 1329                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1330                std::panic::Location::caller()
 1331            );
 1332            return;
 1333        }
 1334        self.selections_by_transaction
 1335            .insert(transaction_id, (selections, None));
 1336    }
 1337
 1338    #[allow(clippy::type_complexity)]
 1339    fn transaction(
 1340        &self,
 1341        transaction_id: TransactionId,
 1342    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1343        self.selections_by_transaction.get(&transaction_id)
 1344    }
 1345
 1346    #[allow(clippy::type_complexity)]
 1347    fn transaction_mut(
 1348        &mut self,
 1349        transaction_id: TransactionId,
 1350    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1351        self.selections_by_transaction.get_mut(&transaction_id)
 1352    }
 1353
 1354    fn push(&mut self, entry: SelectionHistoryEntry) {
 1355        if !entry.selections.is_empty() {
 1356            match self.mode {
 1357                SelectionHistoryMode::Normal => {
 1358                    self.push_undo(entry);
 1359                    self.redo_stack.clear();
 1360                }
 1361                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1362                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1363                SelectionHistoryMode::Skipping => {}
 1364            }
 1365        }
 1366    }
 1367
 1368    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1369        if self
 1370            .undo_stack
 1371            .back()
 1372            .map_or(true, |e| e.selections != entry.selections)
 1373        {
 1374            self.undo_stack.push_back(entry);
 1375            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1376                self.undo_stack.pop_front();
 1377            }
 1378        }
 1379    }
 1380
 1381    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1382        if self
 1383            .redo_stack
 1384            .back()
 1385            .map_or(true, |e| e.selections != entry.selections)
 1386        {
 1387            self.redo_stack.push_back(entry);
 1388            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1389                self.redo_stack.pop_front();
 1390            }
 1391        }
 1392    }
 1393}
 1394
 1395#[derive(Clone, Copy)]
 1396pub struct RowHighlightOptions {
 1397    pub autoscroll: bool,
 1398    pub include_gutter: bool,
 1399}
 1400
 1401impl Default for RowHighlightOptions {
 1402    fn default() -> Self {
 1403        Self {
 1404            autoscroll: Default::default(),
 1405            include_gutter: true,
 1406        }
 1407    }
 1408}
 1409
 1410struct RowHighlight {
 1411    index: usize,
 1412    range: Range<Anchor>,
 1413    color: Hsla,
 1414    options: RowHighlightOptions,
 1415    type_id: TypeId,
 1416}
 1417
 1418#[derive(Clone, Debug)]
 1419struct AddSelectionsState {
 1420    groups: Vec<AddSelectionsGroup>,
 1421}
 1422
 1423#[derive(Clone, Debug)]
 1424struct AddSelectionsGroup {
 1425    above: bool,
 1426    stack: Vec<usize>,
 1427}
 1428
 1429#[derive(Clone)]
 1430struct SelectNextState {
 1431    query: AhoCorasick,
 1432    wordwise: bool,
 1433    done: bool,
 1434}
 1435
 1436impl std::fmt::Debug for SelectNextState {
 1437    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1438        f.debug_struct(std::any::type_name::<Self>())
 1439            .field("wordwise", &self.wordwise)
 1440            .field("done", &self.done)
 1441            .finish()
 1442    }
 1443}
 1444
 1445#[derive(Debug)]
 1446struct AutocloseRegion {
 1447    selection_id: usize,
 1448    range: Range<Anchor>,
 1449    pair: BracketPair,
 1450}
 1451
 1452#[derive(Debug)]
 1453struct SnippetState {
 1454    ranges: Vec<Vec<Range<Anchor>>>,
 1455    active_index: usize,
 1456    choices: Vec<Option<Vec<String>>>,
 1457}
 1458
 1459#[doc(hidden)]
 1460pub struct RenameState {
 1461    pub range: Range<Anchor>,
 1462    pub old_name: Arc<str>,
 1463    pub editor: Entity<Editor>,
 1464    block_id: CustomBlockId,
 1465}
 1466
 1467struct InvalidationStack<T>(Vec<T>);
 1468
 1469struct RegisteredInlineCompletionProvider {
 1470    provider: Arc<dyn InlineCompletionProviderHandle>,
 1471    _subscription: Subscription,
 1472}
 1473
 1474#[derive(Debug, PartialEq, Eq)]
 1475pub struct ActiveDiagnosticGroup {
 1476    pub active_range: Range<Anchor>,
 1477    pub active_message: String,
 1478    pub group_id: usize,
 1479    pub blocks: HashSet<CustomBlockId>,
 1480}
 1481
 1482#[derive(Debug, PartialEq, Eq)]
 1483
 1484pub(crate) enum ActiveDiagnostic {
 1485    None,
 1486    All,
 1487    Group(ActiveDiagnosticGroup),
 1488}
 1489
 1490#[derive(Serialize, Deserialize, Clone, Debug)]
 1491pub struct ClipboardSelection {
 1492    /// The number of bytes in this selection.
 1493    pub len: usize,
 1494    /// Whether this was a full-line selection.
 1495    pub is_entire_line: bool,
 1496    /// The indentation of the first line when this content was originally copied.
 1497    pub first_line_indent: u32,
 1498}
 1499
 1500// selections, scroll behavior, was newest selection reversed
 1501type SelectSyntaxNodeHistoryState = (
 1502    Box<[Selection<usize>]>,
 1503    SelectSyntaxNodeScrollBehavior,
 1504    bool,
 1505);
 1506
 1507#[derive(Default)]
 1508struct SelectSyntaxNodeHistory {
 1509    stack: Vec<SelectSyntaxNodeHistoryState>,
 1510    // disable temporarily to allow changing selections without losing the stack
 1511    pub disable_clearing: bool,
 1512}
 1513
 1514impl SelectSyntaxNodeHistory {
 1515    pub fn try_clear(&mut self) {
 1516        if !self.disable_clearing {
 1517            self.stack.clear();
 1518        }
 1519    }
 1520
 1521    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1522        self.stack.push(selection);
 1523    }
 1524
 1525    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1526        self.stack.pop()
 1527    }
 1528}
 1529
 1530enum SelectSyntaxNodeScrollBehavior {
 1531    CursorTop,
 1532    FitSelection,
 1533    CursorBottom,
 1534}
 1535
 1536#[derive(Debug)]
 1537pub(crate) struct NavigationData {
 1538    cursor_anchor: Anchor,
 1539    cursor_position: Point,
 1540    scroll_anchor: ScrollAnchor,
 1541    scroll_top_row: u32,
 1542}
 1543
 1544#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1545pub enum GotoDefinitionKind {
 1546    Symbol,
 1547    Declaration,
 1548    Type,
 1549    Implementation,
 1550}
 1551
 1552#[derive(Debug, Clone)]
 1553enum InlayHintRefreshReason {
 1554    ModifiersChanged(bool),
 1555    Toggle(bool),
 1556    SettingsChange(InlayHintSettings),
 1557    NewLinesShown,
 1558    BufferEdited(HashSet<Arc<Language>>),
 1559    RefreshRequested,
 1560    ExcerptsRemoved(Vec<ExcerptId>),
 1561}
 1562
 1563impl InlayHintRefreshReason {
 1564    fn description(&self) -> &'static str {
 1565        match self {
 1566            Self::ModifiersChanged(_) => "modifiers changed",
 1567            Self::Toggle(_) => "toggle",
 1568            Self::SettingsChange(_) => "settings change",
 1569            Self::NewLinesShown => "new lines shown",
 1570            Self::BufferEdited(_) => "buffer edited",
 1571            Self::RefreshRequested => "refresh requested",
 1572            Self::ExcerptsRemoved(_) => "excerpts removed",
 1573        }
 1574    }
 1575}
 1576
 1577pub enum FormatTarget {
 1578    Buffers(HashSet<Entity<Buffer>>),
 1579    Ranges(Vec<Range<MultiBufferPoint>>),
 1580}
 1581
 1582pub(crate) struct FocusedBlock {
 1583    id: BlockId,
 1584    focus_handle: WeakFocusHandle,
 1585}
 1586
 1587#[derive(Clone)]
 1588enum JumpData {
 1589    MultiBufferRow {
 1590        row: MultiBufferRow,
 1591        line_offset_from_top: u32,
 1592    },
 1593    MultiBufferPoint {
 1594        excerpt_id: ExcerptId,
 1595        position: Point,
 1596        anchor: text::Anchor,
 1597        line_offset_from_top: u32,
 1598    },
 1599}
 1600
 1601pub enum MultibufferSelectionMode {
 1602    First,
 1603    All,
 1604}
 1605
 1606#[derive(Clone, Copy, Debug, Default)]
 1607pub struct RewrapOptions {
 1608    pub override_language_settings: bool,
 1609    pub preserve_existing_whitespace: bool,
 1610}
 1611
 1612impl Editor {
 1613    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1614        let buffer = cx.new(|cx| Buffer::local("", cx));
 1615        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1616        Self::new(
 1617            EditorMode::SingleLine { auto_width: false },
 1618            buffer,
 1619            None,
 1620            window,
 1621            cx,
 1622        )
 1623    }
 1624
 1625    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1626        let buffer = cx.new(|cx| Buffer::local("", cx));
 1627        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1628        Self::new(EditorMode::full(), buffer, None, window, cx)
 1629    }
 1630
 1631    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1632        let buffer = cx.new(|cx| Buffer::local("", cx));
 1633        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1634        Self::new(
 1635            EditorMode::SingleLine { auto_width: true },
 1636            buffer,
 1637            None,
 1638            window,
 1639            cx,
 1640        )
 1641    }
 1642
 1643    pub fn auto_height(
 1644        min_lines: usize,
 1645        max_lines: usize,
 1646        window: &mut Window,
 1647        cx: &mut Context<Self>,
 1648    ) -> Self {
 1649        let buffer = cx.new(|cx| Buffer::local("", cx));
 1650        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1651        Self::new(
 1652            EditorMode::AutoHeight {
 1653                min_lines,
 1654                max_lines: Some(max_lines),
 1655            },
 1656            buffer,
 1657            None,
 1658            window,
 1659            cx,
 1660        )
 1661    }
 1662
 1663    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1664    /// The editor grows as tall as needed to fit its content.
 1665    pub fn auto_height_unbounded(
 1666        min_lines: usize,
 1667        window: &mut Window,
 1668        cx: &mut Context<Self>,
 1669    ) -> Self {
 1670        let buffer = cx.new(|cx| Buffer::local("", cx));
 1671        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1672        Self::new(
 1673            EditorMode::AutoHeight {
 1674                min_lines,
 1675                max_lines: None,
 1676            },
 1677            buffer,
 1678            None,
 1679            window,
 1680            cx,
 1681        )
 1682    }
 1683
 1684    pub fn for_buffer(
 1685        buffer: Entity<Buffer>,
 1686        project: Option<Entity<Project>>,
 1687        window: &mut Window,
 1688        cx: &mut Context<Self>,
 1689    ) -> Self {
 1690        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1691        Self::new(EditorMode::full(), buffer, project, window, cx)
 1692    }
 1693
 1694    pub fn for_multibuffer(
 1695        buffer: Entity<MultiBuffer>,
 1696        project: Option<Entity<Project>>,
 1697        window: &mut Window,
 1698        cx: &mut Context<Self>,
 1699    ) -> Self {
 1700        Self::new(EditorMode::full(), buffer, project, window, cx)
 1701    }
 1702
 1703    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1704        let mut clone = Self::new(
 1705            self.mode.clone(),
 1706            self.buffer.clone(),
 1707            self.project.clone(),
 1708            window,
 1709            cx,
 1710        );
 1711        self.display_map.update(cx, |display_map, cx| {
 1712            let snapshot = display_map.snapshot(cx);
 1713            clone.display_map.update(cx, |display_map, cx| {
 1714                display_map.set_state(&snapshot, cx);
 1715            });
 1716        });
 1717        clone.folds_did_change(cx);
 1718        clone.selections.clone_state(&self.selections);
 1719        clone.scroll_manager.clone_state(&self.scroll_manager);
 1720        clone.searchable = self.searchable;
 1721        clone.read_only = self.read_only;
 1722        clone
 1723    }
 1724
 1725    pub fn new(
 1726        mode: EditorMode,
 1727        buffer: Entity<MultiBuffer>,
 1728        project: Option<Entity<Project>>,
 1729        window: &mut Window,
 1730        cx: &mut Context<Self>,
 1731    ) -> Self {
 1732        Editor::new_internal(mode, buffer, project, None, window, cx)
 1733    }
 1734
 1735    fn new_internal(
 1736        mode: EditorMode,
 1737        buffer: Entity<MultiBuffer>,
 1738        project: Option<Entity<Project>>,
 1739        display_map: Option<Entity<DisplayMap>>,
 1740        window: &mut Window,
 1741        cx: &mut Context<Self>,
 1742    ) -> Self {
 1743        debug_assert!(
 1744            display_map.is_none() || mode.is_minimap(),
 1745            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1746        );
 1747
 1748        let full_mode = mode.is_full();
 1749        let diagnostics_max_severity = if full_mode {
 1750            EditorSettings::get_global(cx)
 1751                .diagnostics_max_severity
 1752                .unwrap_or(DiagnosticSeverity::Hint)
 1753        } else {
 1754            DiagnosticSeverity::Off
 1755        };
 1756        let style = window.text_style();
 1757        let font_size = style.font_size.to_pixels(window.rem_size());
 1758        let editor = cx.entity().downgrade();
 1759        let fold_placeholder = FoldPlaceholder {
 1760            constrain_width: true,
 1761            render: Arc::new(move |fold_id, fold_range, cx| {
 1762                let editor = editor.clone();
 1763                div()
 1764                    .id(fold_id)
 1765                    .bg(cx.theme().colors().ghost_element_background)
 1766                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1767                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1768                    .rounded_xs()
 1769                    .size_full()
 1770                    .cursor_pointer()
 1771                    .child("")
 1772                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1773                    .on_click(move |_, _window, cx| {
 1774                        editor
 1775                            .update(cx, |editor, cx| {
 1776                                editor.unfold_ranges(
 1777                                    &[fold_range.start..fold_range.end],
 1778                                    true,
 1779                                    false,
 1780                                    cx,
 1781                                );
 1782                                cx.stop_propagation();
 1783                            })
 1784                            .ok();
 1785                    })
 1786                    .into_any()
 1787            }),
 1788            merge_adjacent: true,
 1789            ..FoldPlaceholder::default()
 1790        };
 1791        let display_map = display_map.unwrap_or_else(|| {
 1792            cx.new(|cx| {
 1793                DisplayMap::new(
 1794                    buffer.clone(),
 1795                    style.font(),
 1796                    font_size,
 1797                    None,
 1798                    FILE_HEADER_HEIGHT,
 1799                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1800                    fold_placeholder,
 1801                    diagnostics_max_severity,
 1802                    cx,
 1803                )
 1804            })
 1805        });
 1806
 1807        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1808
 1809        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1810
 1811        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1812            .then(|| language_settings::SoftWrap::None);
 1813
 1814        let mut project_subscriptions = Vec::new();
 1815        if mode.is_full() {
 1816            if let Some(project) = project.as_ref() {
 1817                project_subscriptions.push(cx.subscribe_in(
 1818                    project,
 1819                    window,
 1820                    |editor, _, event, window, cx| match event {
 1821                        project::Event::RefreshCodeLens => {
 1822                            // we always query lens with actions, without storing them, always refreshing them
 1823                        }
 1824                        project::Event::RefreshInlayHints => {
 1825                            editor
 1826                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1827                        }
 1828                        project::Event::LanguageServerAdded(server_id, ..)
 1829                        | project::Event::LanguageServerRemoved(server_id) => {
 1830                            if editor.tasks_update_task.is_none() {
 1831                                editor.tasks_update_task =
 1832                                    Some(editor.refresh_runnables(window, cx));
 1833                            }
 1834                            editor.update_lsp_data(Some(*server_id), None, window, cx);
 1835                        }
 1836                        project::Event::SnippetEdit(id, snippet_edits) => {
 1837                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1838                                let focus_handle = editor.focus_handle(cx);
 1839                                if focus_handle.is_focused(window) {
 1840                                    let snapshot = buffer.read(cx).snapshot();
 1841                                    for (range, snippet) in snippet_edits {
 1842                                        let editor_range =
 1843                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1844                                        editor
 1845                                            .insert_snippet(
 1846                                                &[editor_range],
 1847                                                snippet.clone(),
 1848                                                window,
 1849                                                cx,
 1850                                            )
 1851                                            .ok();
 1852                                    }
 1853                                }
 1854                            }
 1855                        }
 1856                        _ => {}
 1857                    },
 1858                ));
 1859                if let Some(task_inventory) = project
 1860                    .read(cx)
 1861                    .task_store()
 1862                    .read(cx)
 1863                    .task_inventory()
 1864                    .cloned()
 1865                {
 1866                    project_subscriptions.push(cx.observe_in(
 1867                        &task_inventory,
 1868                        window,
 1869                        |editor, _, window, cx| {
 1870                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1871                        },
 1872                    ));
 1873                };
 1874
 1875                project_subscriptions.push(cx.subscribe_in(
 1876                    &project.read(cx).breakpoint_store(),
 1877                    window,
 1878                    |editor, _, event, window, cx| match event {
 1879                        BreakpointStoreEvent::ClearDebugLines => {
 1880                            editor.clear_row_highlights::<ActiveDebugLine>();
 1881                            editor.refresh_inline_values(cx);
 1882                        }
 1883                        BreakpointStoreEvent::SetDebugLine => {
 1884                            if editor.go_to_active_debug_line(window, cx) {
 1885                                cx.stop_propagation();
 1886                            }
 1887
 1888                            editor.refresh_inline_values(cx);
 1889                        }
 1890                        _ => {}
 1891                    },
 1892                ));
 1893                let git_store = project.read(cx).git_store().clone();
 1894                let project = project.clone();
 1895                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1896                    match event {
 1897                        GitStoreEvent::RepositoryUpdated(
 1898                            _,
 1899                            RepositoryEvent::Updated {
 1900                                new_instance: true, ..
 1901                            },
 1902                            _,
 1903                        ) => {
 1904                            this.load_diff_task = Some(
 1905                                update_uncommitted_diff_for_buffer(
 1906                                    cx.entity(),
 1907                                    &project,
 1908                                    this.buffer.read(cx).all_buffers(),
 1909                                    this.buffer.clone(),
 1910                                    cx,
 1911                                )
 1912                                .shared(),
 1913                            );
 1914                        }
 1915                        _ => {}
 1916                    }
 1917                }));
 1918            }
 1919        }
 1920
 1921        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1922
 1923        let inlay_hint_settings =
 1924            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1925        let focus_handle = cx.focus_handle();
 1926        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1927            .detach();
 1928        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1929            .detach();
 1930        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1931            .detach();
 1932        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1933            .detach();
 1934        cx.observe_pending_input(window, Self::observe_pending_input)
 1935            .detach();
 1936
 1937        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1938            Some(false)
 1939        } else {
 1940            None
 1941        };
 1942
 1943        let breakpoint_store = match (&mode, project.as_ref()) {
 1944            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1945            _ => None,
 1946        };
 1947
 1948        let mut code_action_providers = Vec::new();
 1949        let mut load_uncommitted_diff = None;
 1950        if let Some(project) = project.clone() {
 1951            load_uncommitted_diff = Some(
 1952                update_uncommitted_diff_for_buffer(
 1953                    cx.entity(),
 1954                    &project,
 1955                    buffer.read(cx).all_buffers(),
 1956                    buffer.clone(),
 1957                    cx,
 1958                )
 1959                .shared(),
 1960            );
 1961            code_action_providers.push(Rc::new(project) as Rc<_>);
 1962        }
 1963
 1964        let mut editor = Self {
 1965            focus_handle,
 1966            show_cursor_when_unfocused: false,
 1967            last_focused_descendant: None,
 1968            buffer: buffer.clone(),
 1969            display_map: display_map.clone(),
 1970            selections,
 1971            scroll_manager: ScrollManager::new(cx),
 1972            columnar_selection_state: None,
 1973            add_selections_state: None,
 1974            select_next_state: None,
 1975            select_prev_state: None,
 1976            selection_history: SelectionHistory::default(),
 1977            defer_selection_effects: false,
 1978            deferred_selection_effects_state: None,
 1979            autoclose_regions: Vec::new(),
 1980            snippet_stack: InvalidationStack::default(),
 1981            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1982            ime_transaction: None,
 1983            active_diagnostics: ActiveDiagnostic::None,
 1984            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1985            inline_diagnostics_update: Task::ready(()),
 1986            inline_diagnostics: Vec::new(),
 1987            soft_wrap_mode_override,
 1988            diagnostics_max_severity,
 1989            hard_wrap: None,
 1990            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1991            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1992            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1993            project,
 1994            blink_manager: blink_manager.clone(),
 1995            show_local_selections: true,
 1996            show_scrollbars: ScrollbarAxes {
 1997                horizontal: full_mode,
 1998                vertical: full_mode,
 1999            },
 2000            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2001            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2002            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2003            show_gutter: mode.is_full(),
 2004            show_line_numbers: None,
 2005            use_relative_line_numbers: None,
 2006            disable_expand_excerpt_buttons: false,
 2007            show_git_diff_gutter: None,
 2008            show_code_actions: None,
 2009            show_runnables: None,
 2010            show_breakpoints: None,
 2011            show_wrap_guides: None,
 2012            show_indent_guides,
 2013            placeholder_text: None,
 2014            highlight_order: 0,
 2015            highlighted_rows: HashMap::default(),
 2016            background_highlights: TreeMap::default(),
 2017            gutter_highlights: TreeMap::default(),
 2018            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2019            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2020            nav_history: None,
 2021            context_menu: RefCell::new(None),
 2022            context_menu_options: None,
 2023            mouse_context_menu: None,
 2024            completion_tasks: Vec::new(),
 2025            inline_blame_popover: None,
 2026            inline_blame_popover_show_task: None,
 2027            signature_help_state: SignatureHelpState::default(),
 2028            auto_signature_help: None,
 2029            find_all_references_task_sources: Vec::new(),
 2030            next_completion_id: 0,
 2031            next_inlay_id: 0,
 2032            code_action_providers,
 2033            available_code_actions: None,
 2034            code_actions_task: None,
 2035            quick_selection_highlight_task: None,
 2036            debounced_selection_highlight_task: None,
 2037            document_highlights_task: None,
 2038            linked_editing_range_task: None,
 2039            pending_rename: None,
 2040            searchable: true,
 2041            cursor_shape: EditorSettings::get_global(cx)
 2042                .cursor_shape
 2043                .unwrap_or_default(),
 2044            current_line_highlight: None,
 2045            autoindent_mode: Some(AutoindentMode::EachLine),
 2046            collapse_matches: false,
 2047            workspace: None,
 2048            input_enabled: true,
 2049            use_modal_editing: mode.is_full(),
 2050            read_only: mode.is_minimap(),
 2051            use_autoclose: true,
 2052            use_auto_surround: true,
 2053            auto_replace_emoji_shortcode: false,
 2054            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2055            leader_id: None,
 2056            remote_id: None,
 2057            hover_state: HoverState::default(),
 2058            pending_mouse_down: None,
 2059            hovered_link_state: None,
 2060            edit_prediction_provider: None,
 2061            active_inline_completion: None,
 2062            stale_inline_completion_in_menu: None,
 2063            edit_prediction_preview: EditPredictionPreview::Inactive {
 2064                released_too_fast: false,
 2065            },
 2066            inline_diagnostics_enabled: mode.is_full(),
 2067            diagnostics_enabled: mode.is_full(),
 2068            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2069            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2070
 2071            gutter_hovered: false,
 2072            pixel_position_of_newest_cursor: None,
 2073            last_bounds: None,
 2074            last_position_map: None,
 2075            expect_bounds_change: None,
 2076            gutter_dimensions: GutterDimensions::default(),
 2077            style: None,
 2078            show_cursor_names: false,
 2079            hovered_cursors: HashMap::default(),
 2080            next_editor_action_id: EditorActionId::default(),
 2081            editor_actions: Rc::default(),
 2082            inline_completions_hidden_for_vim_mode: false,
 2083            show_inline_completions_override: None,
 2084            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2085            edit_prediction_settings: EditPredictionSettings::Disabled,
 2086            edit_prediction_indent_conflict: false,
 2087            edit_prediction_requires_modifier_in_indent_conflict: true,
 2088            custom_context_menu: None,
 2089            show_git_blame_gutter: false,
 2090            show_git_blame_inline: false,
 2091            show_selection_menu: None,
 2092            show_git_blame_inline_delay_task: None,
 2093            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2094            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2095            serialize_dirty_buffers: !mode.is_minimap()
 2096                && ProjectSettings::get_global(cx)
 2097                    .session
 2098                    .restore_unsaved_buffers,
 2099            blame: None,
 2100            blame_subscription: None,
 2101            tasks: BTreeMap::default(),
 2102
 2103            breakpoint_store,
 2104            gutter_breakpoint_indicator: (None, None),
 2105            hovered_diff_hunk_row: None,
 2106            _subscriptions: vec![
 2107                cx.observe(&buffer, Self::on_buffer_changed),
 2108                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2109                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2110                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2111                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2112                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2113                cx.observe_window_activation(window, |editor, window, cx| {
 2114                    let active = window.is_window_active();
 2115                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2116                        if active {
 2117                            blink_manager.enable(cx);
 2118                        } else {
 2119                            blink_manager.disable(cx);
 2120                        }
 2121                    });
 2122                    if active {
 2123                        editor.show_mouse_cursor(cx);
 2124                    }
 2125                }),
 2126            ],
 2127            tasks_update_task: None,
 2128            pull_diagnostics_task: Task::ready(()),
 2129            colors: None,
 2130            next_color_inlay_id: 0,
 2131            linked_edit_ranges: Default::default(),
 2132            in_project_search: false,
 2133            previous_search_ranges: None,
 2134            breadcrumb_header: None,
 2135            focused_block: None,
 2136            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2137            addons: HashMap::default(),
 2138            registered_buffers: HashMap::default(),
 2139            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2140            selection_mark_mode: false,
 2141            toggle_fold_multiple_buffers: Task::ready(()),
 2142            serialize_selections: Task::ready(()),
 2143            serialize_folds: Task::ready(()),
 2144            text_style_refinement: None,
 2145            load_diff_task: load_uncommitted_diff,
 2146            temporary_diff_override: false,
 2147            mouse_cursor_hidden: false,
 2148            minimap: None,
 2149            hide_mouse_mode: EditorSettings::get_global(cx)
 2150                .hide_mouse
 2151                .unwrap_or_default(),
 2152            change_list: ChangeList::new(),
 2153            mode,
 2154            selection_drag_state: SelectionDragState::None,
 2155            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2156        };
 2157        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2158            editor
 2159                ._subscriptions
 2160                .push(cx.observe(breakpoints, |_, _, cx| {
 2161                    cx.notify();
 2162                }));
 2163        }
 2164        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2165        editor._subscriptions.extend(project_subscriptions);
 2166
 2167        editor._subscriptions.push(cx.subscribe_in(
 2168            &cx.entity(),
 2169            window,
 2170            |editor, _, e: &EditorEvent, window, cx| match e {
 2171                EditorEvent::ScrollPositionChanged { local, .. } => {
 2172                    if *local {
 2173                        let new_anchor = editor.scroll_manager.anchor();
 2174                        let snapshot = editor.snapshot(window, cx);
 2175                        editor.update_restoration_data(cx, move |data| {
 2176                            data.scroll_position = (
 2177                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2178                                new_anchor.offset,
 2179                            );
 2180                        });
 2181                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2182                        editor.inline_blame_popover.take();
 2183                    }
 2184                }
 2185                EditorEvent::Edited { .. } => {
 2186                    if !vim_enabled(cx) {
 2187                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2188                        let pop_state = editor
 2189                            .change_list
 2190                            .last()
 2191                            .map(|previous| {
 2192                                previous.len() == selections.len()
 2193                                    && previous.iter().enumerate().all(|(ix, p)| {
 2194                                        p.to_display_point(&map).row()
 2195                                            == selections[ix].head().row()
 2196                                    })
 2197                            })
 2198                            .unwrap_or(false);
 2199                        let new_positions = selections
 2200                            .into_iter()
 2201                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2202                            .collect();
 2203                        editor
 2204                            .change_list
 2205                            .push_to_change_list(pop_state, new_positions);
 2206                    }
 2207                }
 2208                _ => (),
 2209            },
 2210        ));
 2211
 2212        if let Some(dap_store) = editor
 2213            .project
 2214            .as_ref()
 2215            .map(|project| project.read(cx).dap_store())
 2216        {
 2217            let weak_editor = cx.weak_entity();
 2218
 2219            editor
 2220                ._subscriptions
 2221                .push(
 2222                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2223                        let session_entity = cx.entity();
 2224                        weak_editor
 2225                            .update(cx, |editor, cx| {
 2226                                editor._subscriptions.push(
 2227                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2228                                );
 2229                            })
 2230                            .ok();
 2231                    }),
 2232                );
 2233
 2234            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2235                editor
 2236                    ._subscriptions
 2237                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2238            }
 2239        }
 2240
 2241        // skip adding the initial selection to selection history
 2242        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2243        editor.end_selection(window, cx);
 2244        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2245
 2246        editor.scroll_manager.show_scrollbars(window, cx);
 2247        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2248
 2249        if full_mode {
 2250            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2251            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2252
 2253            if editor.git_blame_inline_enabled {
 2254                editor.start_git_blame_inline(false, window, cx);
 2255            }
 2256
 2257            editor.go_to_active_debug_line(window, cx);
 2258
 2259            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2260                if let Some(project) = editor.project.as_ref() {
 2261                    let handle = project.update(cx, |project, cx| {
 2262                        project.register_buffer_with_language_servers(&buffer, cx)
 2263                    });
 2264                    editor
 2265                        .registered_buffers
 2266                        .insert(buffer.read(cx).remote_id(), handle);
 2267                }
 2268            }
 2269
 2270            editor.minimap =
 2271                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2272            editor.colors = Some(LspColorData::new(cx));
 2273            editor.update_lsp_data(None, None, window, cx);
 2274        }
 2275
 2276        editor.report_editor_event("Editor Opened", None, cx);
 2277        editor
 2278    }
 2279
 2280    pub fn deploy_mouse_context_menu(
 2281        &mut self,
 2282        position: gpui::Point<Pixels>,
 2283        context_menu: Entity<ContextMenu>,
 2284        window: &mut Window,
 2285        cx: &mut Context<Self>,
 2286    ) {
 2287        self.mouse_context_menu = Some(MouseContextMenu::new(
 2288            self,
 2289            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2290            context_menu,
 2291            window,
 2292            cx,
 2293        ));
 2294    }
 2295
 2296    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2297        self.mouse_context_menu
 2298            .as_ref()
 2299            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2300    }
 2301
 2302    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2303        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2304    }
 2305
 2306    fn key_context_internal(
 2307        &self,
 2308        has_active_edit_prediction: bool,
 2309        window: &Window,
 2310        cx: &App,
 2311    ) -> KeyContext {
 2312        let mut key_context = KeyContext::new_with_defaults();
 2313        key_context.add("Editor");
 2314        let mode = match self.mode {
 2315            EditorMode::SingleLine { .. } => "single_line",
 2316            EditorMode::AutoHeight { .. } => "auto_height",
 2317            EditorMode::Minimap { .. } => "minimap",
 2318            EditorMode::Full { .. } => "full",
 2319        };
 2320
 2321        if EditorSettings::jupyter_enabled(cx) {
 2322            key_context.add("jupyter");
 2323        }
 2324
 2325        key_context.set("mode", mode);
 2326        if self.pending_rename.is_some() {
 2327            key_context.add("renaming");
 2328        }
 2329
 2330        match self.context_menu.borrow().as_ref() {
 2331            Some(CodeContextMenu::Completions(_)) => {
 2332                key_context.add("menu");
 2333                key_context.add("showing_completions");
 2334            }
 2335            Some(CodeContextMenu::CodeActions(_)) => {
 2336                key_context.add("menu");
 2337                key_context.add("showing_code_actions")
 2338            }
 2339            None => {}
 2340        }
 2341
 2342        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2343        if !self.focus_handle(cx).contains_focused(window, cx)
 2344            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2345        {
 2346            for addon in self.addons.values() {
 2347                addon.extend_key_context(&mut key_context, cx)
 2348            }
 2349        }
 2350
 2351        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2352            if let Some(extension) = singleton_buffer
 2353                .read(cx)
 2354                .file()
 2355                .and_then(|file| file.path().extension()?.to_str())
 2356            {
 2357                key_context.set("extension", extension.to_string());
 2358            }
 2359        } else {
 2360            key_context.add("multibuffer");
 2361        }
 2362
 2363        if has_active_edit_prediction {
 2364            if self.edit_prediction_in_conflict() {
 2365                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2366            } else {
 2367                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2368                key_context.add("copilot_suggestion");
 2369            }
 2370        }
 2371
 2372        if self.selection_mark_mode {
 2373            key_context.add("selection_mode");
 2374        }
 2375
 2376        key_context
 2377    }
 2378
 2379    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2380        if self.mouse_cursor_hidden {
 2381            self.mouse_cursor_hidden = false;
 2382            cx.notify();
 2383        }
 2384    }
 2385
 2386    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2387        let hide_mouse_cursor = match origin {
 2388            HideMouseCursorOrigin::TypingAction => {
 2389                matches!(
 2390                    self.hide_mouse_mode,
 2391                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2392                )
 2393            }
 2394            HideMouseCursorOrigin::MovementAction => {
 2395                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2396            }
 2397        };
 2398        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2399            self.mouse_cursor_hidden = hide_mouse_cursor;
 2400            cx.notify();
 2401        }
 2402    }
 2403
 2404    pub fn edit_prediction_in_conflict(&self) -> bool {
 2405        if !self.show_edit_predictions_in_menu() {
 2406            return false;
 2407        }
 2408
 2409        let showing_completions = self
 2410            .context_menu
 2411            .borrow()
 2412            .as_ref()
 2413            .map_or(false, |context| {
 2414                matches!(context, CodeContextMenu::Completions(_))
 2415            });
 2416
 2417        showing_completions
 2418            || self.edit_prediction_requires_modifier()
 2419            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2420            // bindings to insert tab characters.
 2421            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2422    }
 2423
 2424    pub fn accept_edit_prediction_keybind(
 2425        &self,
 2426        accept_partial: bool,
 2427        window: &Window,
 2428        cx: &App,
 2429    ) -> AcceptEditPredictionBinding {
 2430        let key_context = self.key_context_internal(true, window, cx);
 2431        let in_conflict = self.edit_prediction_in_conflict();
 2432
 2433        let bindings = if accept_partial {
 2434            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2435        } else {
 2436            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2437        };
 2438
 2439        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2440        // just the first one.
 2441        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2442            !in_conflict
 2443                || binding
 2444                    .keystrokes()
 2445                    .first()
 2446                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2447        }))
 2448    }
 2449
 2450    pub fn new_file(
 2451        workspace: &mut Workspace,
 2452        _: &workspace::NewFile,
 2453        window: &mut Window,
 2454        cx: &mut Context<Workspace>,
 2455    ) {
 2456        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2457            "Failed to create buffer",
 2458            window,
 2459            cx,
 2460            |e, _, _| match e.error_code() {
 2461                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2462                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2463                e.error_tag("required").unwrap_or("the latest version")
 2464            )),
 2465                _ => None,
 2466            },
 2467        );
 2468    }
 2469
 2470    pub fn new_in_workspace(
 2471        workspace: &mut Workspace,
 2472        window: &mut Window,
 2473        cx: &mut Context<Workspace>,
 2474    ) -> Task<Result<Entity<Editor>>> {
 2475        let project = workspace.project().clone();
 2476        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2477
 2478        cx.spawn_in(window, async move |workspace, cx| {
 2479            let buffer = create.await?;
 2480            workspace.update_in(cx, |workspace, window, cx| {
 2481                let editor =
 2482                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2483                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2484                editor
 2485            })
 2486        })
 2487    }
 2488
 2489    fn new_file_vertical(
 2490        workspace: &mut Workspace,
 2491        _: &workspace::NewFileSplitVertical,
 2492        window: &mut Window,
 2493        cx: &mut Context<Workspace>,
 2494    ) {
 2495        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2496    }
 2497
 2498    fn new_file_horizontal(
 2499        workspace: &mut Workspace,
 2500        _: &workspace::NewFileSplitHorizontal,
 2501        window: &mut Window,
 2502        cx: &mut Context<Workspace>,
 2503    ) {
 2504        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2505    }
 2506
 2507    fn new_file_in_direction(
 2508        workspace: &mut Workspace,
 2509        direction: SplitDirection,
 2510        window: &mut Window,
 2511        cx: &mut Context<Workspace>,
 2512    ) {
 2513        let project = workspace.project().clone();
 2514        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2515
 2516        cx.spawn_in(window, async move |workspace, cx| {
 2517            let buffer = create.await?;
 2518            workspace.update_in(cx, move |workspace, window, cx| {
 2519                workspace.split_item(
 2520                    direction,
 2521                    Box::new(
 2522                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2523                    ),
 2524                    window,
 2525                    cx,
 2526                )
 2527            })?;
 2528            anyhow::Ok(())
 2529        })
 2530        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2531            match e.error_code() {
 2532                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2533                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2534                e.error_tag("required").unwrap_or("the latest version")
 2535            )),
 2536                _ => None,
 2537            }
 2538        });
 2539    }
 2540
 2541    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2542        self.leader_id
 2543    }
 2544
 2545    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2546        &self.buffer
 2547    }
 2548
 2549    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2550        self.workspace.as_ref()?.0.upgrade()
 2551    }
 2552
 2553    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2554        self.buffer().read(cx).title(cx)
 2555    }
 2556
 2557    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2558        let git_blame_gutter_max_author_length = self
 2559            .render_git_blame_gutter(cx)
 2560            .then(|| {
 2561                if let Some(blame) = self.blame.as_ref() {
 2562                    let max_author_length =
 2563                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2564                    Some(max_author_length)
 2565                } else {
 2566                    None
 2567                }
 2568            })
 2569            .flatten();
 2570
 2571        EditorSnapshot {
 2572            mode: self.mode.clone(),
 2573            show_gutter: self.show_gutter,
 2574            show_line_numbers: self.show_line_numbers,
 2575            show_git_diff_gutter: self.show_git_diff_gutter,
 2576            show_code_actions: self.show_code_actions,
 2577            show_runnables: self.show_runnables,
 2578            show_breakpoints: self.show_breakpoints,
 2579            git_blame_gutter_max_author_length,
 2580            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2581            scroll_anchor: self.scroll_manager.anchor(),
 2582            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2583            placeholder_text: self.placeholder_text.clone(),
 2584            is_focused: self.focus_handle.is_focused(window),
 2585            current_line_highlight: self
 2586                .current_line_highlight
 2587                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2588            gutter_hovered: self.gutter_hovered,
 2589        }
 2590    }
 2591
 2592    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2593        self.buffer.read(cx).language_at(point, cx)
 2594    }
 2595
 2596    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2597        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2598    }
 2599
 2600    pub fn active_excerpt(
 2601        &self,
 2602        cx: &App,
 2603    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2604        self.buffer
 2605            .read(cx)
 2606            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2607    }
 2608
 2609    pub fn mode(&self) -> &EditorMode {
 2610        &self.mode
 2611    }
 2612
 2613    pub fn set_mode(&mut self, mode: EditorMode) {
 2614        self.mode = mode;
 2615    }
 2616
 2617    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2618        self.collaboration_hub.as_deref()
 2619    }
 2620
 2621    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2622        self.collaboration_hub = Some(hub);
 2623    }
 2624
 2625    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2626        self.in_project_search = in_project_search;
 2627    }
 2628
 2629    pub fn set_custom_context_menu(
 2630        &mut self,
 2631        f: impl 'static
 2632        + Fn(
 2633            &mut Self,
 2634            DisplayPoint,
 2635            &mut Window,
 2636            &mut Context<Self>,
 2637        ) -> Option<Entity<ui::ContextMenu>>,
 2638    ) {
 2639        self.custom_context_menu = Some(Box::new(f))
 2640    }
 2641
 2642    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2643        self.completion_provider = provider;
 2644    }
 2645
 2646    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2647        self.semantics_provider.clone()
 2648    }
 2649
 2650    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2651        self.semantics_provider = provider;
 2652    }
 2653
 2654    pub fn set_edit_prediction_provider<T>(
 2655        &mut self,
 2656        provider: Option<Entity<T>>,
 2657        window: &mut Window,
 2658        cx: &mut Context<Self>,
 2659    ) where
 2660        T: EditPredictionProvider,
 2661    {
 2662        self.edit_prediction_provider =
 2663            provider.map(|provider| RegisteredInlineCompletionProvider {
 2664                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2665                    if this.focus_handle.is_focused(window) {
 2666                        this.update_visible_inline_completion(window, cx);
 2667                    }
 2668                }),
 2669                provider: Arc::new(provider),
 2670            });
 2671        self.update_edit_prediction_settings(cx);
 2672        self.refresh_inline_completion(false, false, window, cx);
 2673    }
 2674
 2675    pub fn placeholder_text(&self) -> Option<&str> {
 2676        self.placeholder_text.as_deref()
 2677    }
 2678
 2679    pub fn set_placeholder_text(
 2680        &mut self,
 2681        placeholder_text: impl Into<Arc<str>>,
 2682        cx: &mut Context<Self>,
 2683    ) {
 2684        let placeholder_text = Some(placeholder_text.into());
 2685        if self.placeholder_text != placeholder_text {
 2686            self.placeholder_text = placeholder_text;
 2687            cx.notify();
 2688        }
 2689    }
 2690
 2691    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2692        self.cursor_shape = cursor_shape;
 2693
 2694        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2695        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2696
 2697        cx.notify();
 2698    }
 2699
 2700    pub fn set_current_line_highlight(
 2701        &mut self,
 2702        current_line_highlight: Option<CurrentLineHighlight>,
 2703    ) {
 2704        self.current_line_highlight = current_line_highlight;
 2705    }
 2706
 2707    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2708        self.collapse_matches = collapse_matches;
 2709    }
 2710
 2711    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2712        let buffers = self.buffer.read(cx).all_buffers();
 2713        let Some(project) = self.project.as_ref() else {
 2714            return;
 2715        };
 2716        project.update(cx, |project, cx| {
 2717            for buffer in buffers {
 2718                self.registered_buffers
 2719                    .entry(buffer.read(cx).remote_id())
 2720                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2721            }
 2722        })
 2723    }
 2724
 2725    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2726        if self.collapse_matches {
 2727            return range.start..range.start;
 2728        }
 2729        range.clone()
 2730    }
 2731
 2732    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2733        if self.display_map.read(cx).clip_at_line_ends != clip {
 2734            self.display_map
 2735                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2736        }
 2737    }
 2738
 2739    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2740        self.input_enabled = input_enabled;
 2741    }
 2742
 2743    pub fn set_inline_completions_hidden_for_vim_mode(
 2744        &mut self,
 2745        hidden: bool,
 2746        window: &mut Window,
 2747        cx: &mut Context<Self>,
 2748    ) {
 2749        if hidden != self.inline_completions_hidden_for_vim_mode {
 2750            self.inline_completions_hidden_for_vim_mode = hidden;
 2751            if hidden {
 2752                self.update_visible_inline_completion(window, cx);
 2753            } else {
 2754                self.refresh_inline_completion(true, false, window, cx);
 2755            }
 2756        }
 2757    }
 2758
 2759    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2760        self.menu_inline_completions_policy = value;
 2761    }
 2762
 2763    pub fn set_autoindent(&mut self, autoindent: bool) {
 2764        if autoindent {
 2765            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2766        } else {
 2767            self.autoindent_mode = None;
 2768        }
 2769    }
 2770
 2771    pub fn read_only(&self, cx: &App) -> bool {
 2772        self.read_only || self.buffer.read(cx).read_only()
 2773    }
 2774
 2775    pub fn set_read_only(&mut self, read_only: bool) {
 2776        self.read_only = read_only;
 2777    }
 2778
 2779    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2780        self.use_autoclose = autoclose;
 2781    }
 2782
 2783    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2784        self.use_auto_surround = auto_surround;
 2785    }
 2786
 2787    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2788        self.auto_replace_emoji_shortcode = auto_replace;
 2789    }
 2790
 2791    pub fn toggle_edit_predictions(
 2792        &mut self,
 2793        _: &ToggleEditPrediction,
 2794        window: &mut Window,
 2795        cx: &mut Context<Self>,
 2796    ) {
 2797        if self.show_inline_completions_override.is_some() {
 2798            self.set_show_edit_predictions(None, window, cx);
 2799        } else {
 2800            let show_edit_predictions = !self.edit_predictions_enabled();
 2801            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2802        }
 2803    }
 2804
 2805    pub fn set_show_edit_predictions(
 2806        &mut self,
 2807        show_edit_predictions: Option<bool>,
 2808        window: &mut Window,
 2809        cx: &mut Context<Self>,
 2810    ) {
 2811        self.show_inline_completions_override = show_edit_predictions;
 2812        self.update_edit_prediction_settings(cx);
 2813
 2814        if let Some(false) = show_edit_predictions {
 2815            self.discard_inline_completion(false, cx);
 2816        } else {
 2817            self.refresh_inline_completion(false, true, window, cx);
 2818        }
 2819    }
 2820
 2821    fn inline_completions_disabled_in_scope(
 2822        &self,
 2823        buffer: &Entity<Buffer>,
 2824        buffer_position: language::Anchor,
 2825        cx: &App,
 2826    ) -> bool {
 2827        let snapshot = buffer.read(cx).snapshot();
 2828        let settings = snapshot.settings_at(buffer_position, cx);
 2829
 2830        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2831            return false;
 2832        };
 2833
 2834        scope.override_name().map_or(false, |scope_name| {
 2835            settings
 2836                .edit_predictions_disabled_in
 2837                .iter()
 2838                .any(|s| s == scope_name)
 2839        })
 2840    }
 2841
 2842    pub fn set_use_modal_editing(&mut self, to: bool) {
 2843        self.use_modal_editing = to;
 2844    }
 2845
 2846    pub fn use_modal_editing(&self) -> bool {
 2847        self.use_modal_editing
 2848    }
 2849
 2850    fn selections_did_change(
 2851        &mut self,
 2852        local: bool,
 2853        old_cursor_position: &Anchor,
 2854        effects: SelectionEffects,
 2855        window: &mut Window,
 2856        cx: &mut Context<Self>,
 2857    ) {
 2858        window.invalidate_character_coordinates();
 2859
 2860        // Copy selections to primary selection buffer
 2861        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2862        if local {
 2863            let selections = self.selections.all::<usize>(cx);
 2864            let buffer_handle = self.buffer.read(cx).read(cx);
 2865
 2866            let mut text = String::new();
 2867            for (index, selection) in selections.iter().enumerate() {
 2868                let text_for_selection = buffer_handle
 2869                    .text_for_range(selection.start..selection.end)
 2870                    .collect::<String>();
 2871
 2872                text.push_str(&text_for_selection);
 2873                if index != selections.len() - 1 {
 2874                    text.push('\n');
 2875                }
 2876            }
 2877
 2878            if !text.is_empty() {
 2879                cx.write_to_primary(ClipboardItem::new_string(text));
 2880            }
 2881        }
 2882
 2883        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2884            self.buffer.update(cx, |buffer, cx| {
 2885                buffer.set_active_selections(
 2886                    &self.selections.disjoint_anchors(),
 2887                    self.selections.line_mode,
 2888                    self.cursor_shape,
 2889                    cx,
 2890                )
 2891            });
 2892        }
 2893        let display_map = self
 2894            .display_map
 2895            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2896        let buffer = &display_map.buffer_snapshot;
 2897        if self.selections.count() == 1 {
 2898            self.add_selections_state = None;
 2899        }
 2900        self.select_next_state = None;
 2901        self.select_prev_state = None;
 2902        self.select_syntax_node_history.try_clear();
 2903        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2904        self.snippet_stack
 2905            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2906        self.take_rename(false, window, cx);
 2907
 2908        let newest_selection = self.selections.newest_anchor();
 2909        let new_cursor_position = newest_selection.head();
 2910        let selection_start = newest_selection.start;
 2911
 2912        if effects.nav_history {
 2913            self.push_to_nav_history(
 2914                *old_cursor_position,
 2915                Some(new_cursor_position.to_point(buffer)),
 2916                false,
 2917                cx,
 2918            );
 2919        }
 2920
 2921        if local {
 2922            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2923                if !self.registered_buffers.contains_key(&buffer_id) {
 2924                    if let Some(project) = self.project.as_ref() {
 2925                        project.update(cx, |project, cx| {
 2926                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2927                                return;
 2928                            };
 2929                            self.registered_buffers.insert(
 2930                                buffer_id,
 2931                                project.register_buffer_with_language_servers(&buffer, cx),
 2932                            );
 2933                        })
 2934                    }
 2935                }
 2936            }
 2937
 2938            let mut context_menu = self.context_menu.borrow_mut();
 2939            let completion_menu = match context_menu.as_ref() {
 2940                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2941                Some(CodeContextMenu::CodeActions(_)) => {
 2942                    *context_menu = None;
 2943                    None
 2944                }
 2945                None => None,
 2946            };
 2947            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2948            drop(context_menu);
 2949
 2950            if effects.completions {
 2951                if let Some(completion_position) = completion_position {
 2952                    let start_offset = selection_start.to_offset(buffer);
 2953                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2954                    let continue_showing = if position_matches {
 2955                        if self.snippet_stack.is_empty() {
 2956                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2957                        } else {
 2958                            // Snippet choices can be shown even when the cursor is in whitespace.
 2959                            // Dismissing the menu with actions like backspace is handled by
 2960                            // invalidation regions.
 2961                            true
 2962                        }
 2963                    } else {
 2964                        false
 2965                    };
 2966
 2967                    if continue_showing {
 2968                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2969                    } else {
 2970                        self.hide_context_menu(window, cx);
 2971                    }
 2972                }
 2973            }
 2974
 2975            hide_hover(self, cx);
 2976
 2977            if old_cursor_position.to_display_point(&display_map).row()
 2978                != new_cursor_position.to_display_point(&display_map).row()
 2979            {
 2980                self.available_code_actions.take();
 2981            }
 2982            self.refresh_code_actions(window, cx);
 2983            self.refresh_document_highlights(cx);
 2984            self.refresh_selected_text_highlights(false, window, cx);
 2985            refresh_matching_bracket_highlights(self, window, cx);
 2986            self.update_visible_inline_completion(window, cx);
 2987            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2988            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2989            self.inline_blame_popover.take();
 2990            if self.git_blame_inline_enabled {
 2991                self.start_inline_blame_timer(window, cx);
 2992            }
 2993        }
 2994
 2995        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2996        cx.emit(EditorEvent::SelectionsChanged { local });
 2997
 2998        let selections = &self.selections.disjoint;
 2999        if selections.len() == 1 {
 3000            cx.emit(SearchEvent::ActiveMatchChanged)
 3001        }
 3002        if local {
 3003            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3004                let inmemory_selections = selections
 3005                    .iter()
 3006                    .map(|s| {
 3007                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3008                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3009                    })
 3010                    .collect();
 3011                self.update_restoration_data(cx, |data| {
 3012                    data.selections = inmemory_selections;
 3013                });
 3014
 3015                if WorkspaceSettings::get(None, cx).restore_on_startup
 3016                    != RestoreOnStartupBehavior::None
 3017                {
 3018                    if let Some(workspace_id) =
 3019                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3020                    {
 3021                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3022                        let selections = selections.clone();
 3023                        let background_executor = cx.background_executor().clone();
 3024                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3025                        self.serialize_selections = cx.background_spawn(async move {
 3026                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3027                            let db_selections = selections
 3028                                .iter()
 3029                                .map(|selection| {
 3030                                    (
 3031                                        selection.start.to_offset(&snapshot),
 3032                                        selection.end.to_offset(&snapshot),
 3033                                    )
 3034                                })
 3035                                .collect();
 3036
 3037                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3038                                .await
 3039                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3040                                .log_err();
 3041                        });
 3042                    }
 3043                }
 3044            }
 3045        }
 3046
 3047        cx.notify();
 3048    }
 3049
 3050    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3051        use text::ToOffset as _;
 3052        use text::ToPoint as _;
 3053
 3054        if self.mode.is_minimap()
 3055            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3056        {
 3057            return;
 3058        }
 3059
 3060        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3061            return;
 3062        };
 3063
 3064        let snapshot = singleton.read(cx).snapshot();
 3065        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3066            let display_snapshot = display_map.snapshot(cx);
 3067
 3068            display_snapshot
 3069                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3070                .map(|fold| {
 3071                    fold.range.start.text_anchor.to_point(&snapshot)
 3072                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3073                })
 3074                .collect()
 3075        });
 3076        self.update_restoration_data(cx, |data| {
 3077            data.folds = inmemory_folds;
 3078        });
 3079
 3080        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3081            return;
 3082        };
 3083        let background_executor = cx.background_executor().clone();
 3084        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3085        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3086            display_map
 3087                .snapshot(cx)
 3088                .folds_in_range(0..snapshot.len())
 3089                .map(|fold| {
 3090                    (
 3091                        fold.range.start.text_anchor.to_offset(&snapshot),
 3092                        fold.range.end.text_anchor.to_offset(&snapshot),
 3093                    )
 3094                })
 3095                .collect()
 3096        });
 3097        self.serialize_folds = cx.background_spawn(async move {
 3098            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3099            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3100                .await
 3101                .with_context(|| {
 3102                    format!(
 3103                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3104                    )
 3105                })
 3106                .log_err();
 3107        });
 3108    }
 3109
 3110    pub fn sync_selections(
 3111        &mut self,
 3112        other: Entity<Editor>,
 3113        cx: &mut Context<Self>,
 3114    ) -> gpui::Subscription {
 3115        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3116        self.selections.change_with(cx, |selections| {
 3117            selections.select_anchors(other_selections);
 3118        });
 3119
 3120        let other_subscription =
 3121            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3122                EditorEvent::SelectionsChanged { local: true } => {
 3123                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3124                    if other_selections.is_empty() {
 3125                        return;
 3126                    }
 3127                    this.selections.change_with(cx, |selections| {
 3128                        selections.select_anchors(other_selections);
 3129                    });
 3130                }
 3131                _ => {}
 3132            });
 3133
 3134        let this_subscription =
 3135            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3136                EditorEvent::SelectionsChanged { local: true } => {
 3137                    let these_selections = this.selections.disjoint.to_vec();
 3138                    if these_selections.is_empty() {
 3139                        return;
 3140                    }
 3141                    other.update(cx, |other_editor, cx| {
 3142                        other_editor.selections.change_with(cx, |selections| {
 3143                            selections.select_anchors(these_selections);
 3144                        })
 3145                    });
 3146                }
 3147                _ => {}
 3148            });
 3149
 3150        Subscription::join(other_subscription, this_subscription)
 3151    }
 3152
 3153    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3154    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3155    /// effects of selection change occur at the end of the transaction.
 3156    pub fn change_selections<R>(
 3157        &mut self,
 3158        effects: impl Into<SelectionEffects>,
 3159        window: &mut Window,
 3160        cx: &mut Context<Self>,
 3161        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3162    ) -> R {
 3163        let effects = effects.into();
 3164        if let Some(state) = &mut self.deferred_selection_effects_state {
 3165            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3166            state.effects.completions = effects.completions;
 3167            state.effects.nav_history |= effects.nav_history;
 3168            let (changed, result) = self.selections.change_with(cx, change);
 3169            state.changed |= changed;
 3170            return result;
 3171        }
 3172        let mut state = DeferredSelectionEffectsState {
 3173            changed: false,
 3174            effects,
 3175            old_cursor_position: self.selections.newest_anchor().head(),
 3176            history_entry: SelectionHistoryEntry {
 3177                selections: self.selections.disjoint_anchors(),
 3178                select_next_state: self.select_next_state.clone(),
 3179                select_prev_state: self.select_prev_state.clone(),
 3180                add_selections_state: self.add_selections_state.clone(),
 3181            },
 3182        };
 3183        let (changed, result) = self.selections.change_with(cx, change);
 3184        state.changed = state.changed || changed;
 3185        if self.defer_selection_effects {
 3186            self.deferred_selection_effects_state = Some(state);
 3187        } else {
 3188            self.apply_selection_effects(state, window, cx);
 3189        }
 3190        result
 3191    }
 3192
 3193    /// Defers the effects of selection change, so that the effects of multiple calls to
 3194    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3195    /// to selection history and the state of popovers based on selection position aren't
 3196    /// erroneously updated.
 3197    pub fn with_selection_effects_deferred<R>(
 3198        &mut self,
 3199        window: &mut Window,
 3200        cx: &mut Context<Self>,
 3201        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3202    ) -> R {
 3203        let already_deferred = self.defer_selection_effects;
 3204        self.defer_selection_effects = true;
 3205        let result = update(self, window, cx);
 3206        if !already_deferred {
 3207            self.defer_selection_effects = false;
 3208            if let Some(state) = self.deferred_selection_effects_state.take() {
 3209                self.apply_selection_effects(state, window, cx);
 3210            }
 3211        }
 3212        result
 3213    }
 3214
 3215    fn apply_selection_effects(
 3216        &mut self,
 3217        state: DeferredSelectionEffectsState,
 3218        window: &mut Window,
 3219        cx: &mut Context<Self>,
 3220    ) {
 3221        if state.changed {
 3222            self.selection_history.push(state.history_entry);
 3223
 3224            if let Some(autoscroll) = state.effects.scroll {
 3225                self.request_autoscroll(autoscroll, cx);
 3226            }
 3227
 3228            let old_cursor_position = &state.old_cursor_position;
 3229
 3230            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3231
 3232            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3233                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3234            }
 3235        }
 3236    }
 3237
 3238    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3239    where
 3240        I: IntoIterator<Item = (Range<S>, T)>,
 3241        S: ToOffset,
 3242        T: Into<Arc<str>>,
 3243    {
 3244        if self.read_only(cx) {
 3245            return;
 3246        }
 3247
 3248        self.buffer
 3249            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3250    }
 3251
 3252    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3253    where
 3254        I: IntoIterator<Item = (Range<S>, T)>,
 3255        S: ToOffset,
 3256        T: Into<Arc<str>>,
 3257    {
 3258        if self.read_only(cx) {
 3259            return;
 3260        }
 3261
 3262        self.buffer.update(cx, |buffer, cx| {
 3263            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3264        });
 3265    }
 3266
 3267    pub fn edit_with_block_indent<I, S, T>(
 3268        &mut self,
 3269        edits: I,
 3270        original_indent_columns: Vec<Option<u32>>,
 3271        cx: &mut Context<Self>,
 3272    ) where
 3273        I: IntoIterator<Item = (Range<S>, T)>,
 3274        S: ToOffset,
 3275        T: Into<Arc<str>>,
 3276    {
 3277        if self.read_only(cx) {
 3278            return;
 3279        }
 3280
 3281        self.buffer.update(cx, |buffer, cx| {
 3282            buffer.edit(
 3283                edits,
 3284                Some(AutoindentMode::Block {
 3285                    original_indent_columns,
 3286                }),
 3287                cx,
 3288            )
 3289        });
 3290    }
 3291
 3292    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3293        self.hide_context_menu(window, cx);
 3294
 3295        match phase {
 3296            SelectPhase::Begin {
 3297                position,
 3298                add,
 3299                click_count,
 3300            } => self.begin_selection(position, add, click_count, window, cx),
 3301            SelectPhase::BeginColumnar {
 3302                position,
 3303                goal_column,
 3304                reset,
 3305                mode,
 3306            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3307            SelectPhase::Extend {
 3308                position,
 3309                click_count,
 3310            } => self.extend_selection(position, click_count, window, cx),
 3311            SelectPhase::Update {
 3312                position,
 3313                goal_column,
 3314                scroll_delta,
 3315            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3316            SelectPhase::End => self.end_selection(window, cx),
 3317        }
 3318    }
 3319
 3320    fn extend_selection(
 3321        &mut self,
 3322        position: DisplayPoint,
 3323        click_count: usize,
 3324        window: &mut Window,
 3325        cx: &mut Context<Self>,
 3326    ) {
 3327        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3328        let tail = self.selections.newest::<usize>(cx).tail();
 3329        self.begin_selection(position, false, click_count, window, cx);
 3330
 3331        let position = position.to_offset(&display_map, Bias::Left);
 3332        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3333
 3334        let mut pending_selection = self
 3335            .selections
 3336            .pending_anchor()
 3337            .expect("extend_selection not called with pending selection");
 3338        if position >= tail {
 3339            pending_selection.start = tail_anchor;
 3340        } else {
 3341            pending_selection.end = tail_anchor;
 3342            pending_selection.reversed = true;
 3343        }
 3344
 3345        let mut pending_mode = self.selections.pending_mode().unwrap();
 3346        match &mut pending_mode {
 3347            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3348            _ => {}
 3349        }
 3350
 3351        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3352            SelectionEffects::scroll(Autoscroll::fit())
 3353        } else {
 3354            SelectionEffects::no_scroll()
 3355        };
 3356
 3357        self.change_selections(effects, window, cx, |s| {
 3358            s.set_pending(pending_selection, pending_mode)
 3359        });
 3360    }
 3361
 3362    fn begin_selection(
 3363        &mut self,
 3364        position: DisplayPoint,
 3365        add: bool,
 3366        click_count: usize,
 3367        window: &mut Window,
 3368        cx: &mut Context<Self>,
 3369    ) {
 3370        if !self.focus_handle.is_focused(window) {
 3371            self.last_focused_descendant = None;
 3372            window.focus(&self.focus_handle);
 3373        }
 3374
 3375        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3376        let buffer = &display_map.buffer_snapshot;
 3377        let position = display_map.clip_point(position, Bias::Left);
 3378
 3379        let start;
 3380        let end;
 3381        let mode;
 3382        let mut auto_scroll;
 3383        match click_count {
 3384            1 => {
 3385                start = buffer.anchor_before(position.to_point(&display_map));
 3386                end = start;
 3387                mode = SelectMode::Character;
 3388                auto_scroll = true;
 3389            }
 3390            2 => {
 3391                let range = movement::surrounding_word(&display_map, position);
 3392                start = buffer.anchor_before(range.start.to_point(&display_map));
 3393                end = buffer.anchor_before(range.end.to_point(&display_map));
 3394                mode = SelectMode::Word(start..end);
 3395                auto_scroll = true;
 3396            }
 3397            3 => {
 3398                let position = display_map
 3399                    .clip_point(position, Bias::Left)
 3400                    .to_point(&display_map);
 3401                let line_start = display_map.prev_line_boundary(position).0;
 3402                let next_line_start = buffer.clip_point(
 3403                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3404                    Bias::Left,
 3405                );
 3406                start = buffer.anchor_before(line_start);
 3407                end = buffer.anchor_before(next_line_start);
 3408                mode = SelectMode::Line(start..end);
 3409                auto_scroll = true;
 3410            }
 3411            _ => {
 3412                start = buffer.anchor_before(0);
 3413                end = buffer.anchor_before(buffer.len());
 3414                mode = SelectMode::All;
 3415                auto_scroll = false;
 3416            }
 3417        }
 3418        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3419
 3420        let point_to_delete: Option<usize> = {
 3421            let selected_points: Vec<Selection<Point>> =
 3422                self.selections.disjoint_in_range(start..end, cx);
 3423
 3424            if !add || click_count > 1 {
 3425                None
 3426            } else if !selected_points.is_empty() {
 3427                Some(selected_points[0].id)
 3428            } else {
 3429                let clicked_point_already_selected =
 3430                    self.selections.disjoint.iter().find(|selection| {
 3431                        selection.start.to_point(buffer) == start.to_point(buffer)
 3432                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3433                    });
 3434
 3435                clicked_point_already_selected.map(|selection| selection.id)
 3436            }
 3437        };
 3438
 3439        let selections_count = self.selections.count();
 3440
 3441        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3442            if let Some(point_to_delete) = point_to_delete {
 3443                s.delete(point_to_delete);
 3444
 3445                if selections_count == 1 {
 3446                    s.set_pending_anchor_range(start..end, mode);
 3447                }
 3448            } else {
 3449                if !add {
 3450                    s.clear_disjoint();
 3451                }
 3452
 3453                s.set_pending_anchor_range(start..end, mode);
 3454            }
 3455        });
 3456    }
 3457
 3458    fn begin_columnar_selection(
 3459        &mut self,
 3460        position: DisplayPoint,
 3461        goal_column: u32,
 3462        reset: bool,
 3463        mode: ColumnarMode,
 3464        window: &mut Window,
 3465        cx: &mut Context<Self>,
 3466    ) {
 3467        if !self.focus_handle.is_focused(window) {
 3468            self.last_focused_descendant = None;
 3469            window.focus(&self.focus_handle);
 3470        }
 3471
 3472        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3473
 3474        if reset {
 3475            let pointer_position = display_map
 3476                .buffer_snapshot
 3477                .anchor_before(position.to_point(&display_map));
 3478
 3479            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3480                s.clear_disjoint();
 3481                s.set_pending_anchor_range(
 3482                    pointer_position..pointer_position,
 3483                    SelectMode::Character,
 3484                );
 3485            });
 3486        };
 3487
 3488        let tail = self.selections.newest::<Point>(cx).tail();
 3489        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3490        self.columnar_selection_state = match mode {
 3491            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3492                selection_tail: selection_anchor,
 3493                display_point: if reset {
 3494                    if position.column() != goal_column {
 3495                        Some(DisplayPoint::new(position.row(), goal_column))
 3496                    } else {
 3497                        None
 3498                    }
 3499                } else {
 3500                    None
 3501                },
 3502            }),
 3503            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3504                selection_tail: selection_anchor,
 3505            }),
 3506        };
 3507
 3508        if !reset {
 3509            self.select_columns(position, goal_column, &display_map, window, cx);
 3510        }
 3511    }
 3512
 3513    fn update_selection(
 3514        &mut self,
 3515        position: DisplayPoint,
 3516        goal_column: u32,
 3517        scroll_delta: gpui::Point<f32>,
 3518        window: &mut Window,
 3519        cx: &mut Context<Self>,
 3520    ) {
 3521        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3522
 3523        if self.columnar_selection_state.is_some() {
 3524            self.select_columns(position, goal_column, &display_map, window, cx);
 3525        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3526            let buffer = self.buffer.read(cx).snapshot(cx);
 3527            let head;
 3528            let tail;
 3529            let mode = self.selections.pending_mode().unwrap();
 3530            match &mode {
 3531                SelectMode::Character => {
 3532                    head = position.to_point(&display_map);
 3533                    tail = pending.tail().to_point(&buffer);
 3534                }
 3535                SelectMode::Word(original_range) => {
 3536                    let original_display_range = original_range.start.to_display_point(&display_map)
 3537                        ..original_range.end.to_display_point(&display_map);
 3538                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3539                        ..original_display_range.end.to_point(&display_map);
 3540                    if movement::is_inside_word(&display_map, position)
 3541                        || original_display_range.contains(&position)
 3542                    {
 3543                        let word_range = movement::surrounding_word(&display_map, position);
 3544                        if word_range.start < original_display_range.start {
 3545                            head = word_range.start.to_point(&display_map);
 3546                        } else {
 3547                            head = word_range.end.to_point(&display_map);
 3548                        }
 3549                    } else {
 3550                        head = position.to_point(&display_map);
 3551                    }
 3552
 3553                    if head <= original_buffer_range.start {
 3554                        tail = original_buffer_range.end;
 3555                    } else {
 3556                        tail = original_buffer_range.start;
 3557                    }
 3558                }
 3559                SelectMode::Line(original_range) => {
 3560                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3561
 3562                    let position = display_map
 3563                        .clip_point(position, Bias::Left)
 3564                        .to_point(&display_map);
 3565                    let line_start = display_map.prev_line_boundary(position).0;
 3566                    let next_line_start = buffer.clip_point(
 3567                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3568                        Bias::Left,
 3569                    );
 3570
 3571                    if line_start < original_range.start {
 3572                        head = line_start
 3573                    } else {
 3574                        head = next_line_start
 3575                    }
 3576
 3577                    if head <= original_range.start {
 3578                        tail = original_range.end;
 3579                    } else {
 3580                        tail = original_range.start;
 3581                    }
 3582                }
 3583                SelectMode::All => {
 3584                    return;
 3585                }
 3586            };
 3587
 3588            if head < tail {
 3589                pending.start = buffer.anchor_before(head);
 3590                pending.end = buffer.anchor_before(tail);
 3591                pending.reversed = true;
 3592            } else {
 3593                pending.start = buffer.anchor_before(tail);
 3594                pending.end = buffer.anchor_before(head);
 3595                pending.reversed = false;
 3596            }
 3597
 3598            self.change_selections(None, window, cx, |s| {
 3599                s.set_pending(pending, mode);
 3600            });
 3601        } else {
 3602            log::error!("update_selection dispatched with no pending selection");
 3603            return;
 3604        }
 3605
 3606        self.apply_scroll_delta(scroll_delta, window, cx);
 3607        cx.notify();
 3608    }
 3609
 3610    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3611        self.columnar_selection_state.take();
 3612        if self.selections.pending_anchor().is_some() {
 3613            let selections = self.selections.all::<usize>(cx);
 3614            self.change_selections(None, window, cx, |s| {
 3615                s.select(selections);
 3616                s.clear_pending();
 3617            });
 3618        }
 3619    }
 3620
 3621    fn select_columns(
 3622        &mut self,
 3623        head: DisplayPoint,
 3624        goal_column: u32,
 3625        display_map: &DisplaySnapshot,
 3626        window: &mut Window,
 3627        cx: &mut Context<Self>,
 3628    ) {
 3629        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3630            return;
 3631        };
 3632
 3633        let tail = match columnar_state {
 3634            ColumnarSelectionState::FromMouse {
 3635                selection_tail,
 3636                display_point,
 3637            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3638            ColumnarSelectionState::FromSelection { selection_tail } => {
 3639                selection_tail.to_display_point(&display_map)
 3640            }
 3641        };
 3642
 3643        let start_row = cmp::min(tail.row(), head.row());
 3644        let end_row = cmp::max(tail.row(), head.row());
 3645        let start_column = cmp::min(tail.column(), goal_column);
 3646        let end_column = cmp::max(tail.column(), goal_column);
 3647        let reversed = start_column < tail.column();
 3648
 3649        let selection_ranges = (start_row.0..=end_row.0)
 3650            .map(DisplayRow)
 3651            .filter_map(|row| {
 3652                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3653                    || start_column <= display_map.line_len(row))
 3654                    && !display_map.is_block_line(row)
 3655                {
 3656                    let start = display_map
 3657                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3658                        .to_point(display_map);
 3659                    let end = display_map
 3660                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3661                        .to_point(display_map);
 3662                    if reversed {
 3663                        Some(end..start)
 3664                    } else {
 3665                        Some(start..end)
 3666                    }
 3667                } else {
 3668                    None
 3669                }
 3670            })
 3671            .collect::<Vec<_>>();
 3672
 3673        let ranges = match columnar_state {
 3674            ColumnarSelectionState::FromMouse { .. } => {
 3675                let mut non_empty_ranges = selection_ranges
 3676                    .iter()
 3677                    .filter(|selection_range| selection_range.start != selection_range.end)
 3678                    .peekable();
 3679                if non_empty_ranges.peek().is_some() {
 3680                    non_empty_ranges.cloned().collect()
 3681                } else {
 3682                    selection_ranges
 3683                }
 3684            }
 3685            _ => selection_ranges,
 3686        };
 3687
 3688        self.change_selections(None, window, cx, |s| {
 3689            s.select_ranges(ranges);
 3690        });
 3691        cx.notify();
 3692    }
 3693
 3694    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3695        self.selections
 3696            .all_adjusted(cx)
 3697            .iter()
 3698            .any(|selection| !selection.is_empty())
 3699    }
 3700
 3701    pub fn has_pending_nonempty_selection(&self) -> bool {
 3702        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3703            Some(Selection { start, end, .. }) => start != end,
 3704            None => false,
 3705        };
 3706
 3707        pending_nonempty_selection
 3708            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3709    }
 3710
 3711    pub fn has_pending_selection(&self) -> bool {
 3712        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3713    }
 3714
 3715    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3716        self.selection_mark_mode = false;
 3717        self.selection_drag_state = SelectionDragState::None;
 3718
 3719        if self.clear_expanded_diff_hunks(cx) {
 3720            cx.notify();
 3721            return;
 3722        }
 3723        if self.dismiss_menus_and_popups(true, window, cx) {
 3724            return;
 3725        }
 3726
 3727        if self.mode.is_full()
 3728            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3729        {
 3730            return;
 3731        }
 3732
 3733        cx.propagate();
 3734    }
 3735
 3736    pub fn dismiss_menus_and_popups(
 3737        &mut self,
 3738        is_user_requested: bool,
 3739        window: &mut Window,
 3740        cx: &mut Context<Self>,
 3741    ) -> bool {
 3742        if self.take_rename(false, window, cx).is_some() {
 3743            return true;
 3744        }
 3745
 3746        if hide_hover(self, cx) {
 3747            return true;
 3748        }
 3749
 3750        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3751            return true;
 3752        }
 3753
 3754        if self.hide_context_menu(window, cx).is_some() {
 3755            return true;
 3756        }
 3757
 3758        if self.mouse_context_menu.take().is_some() {
 3759            return true;
 3760        }
 3761
 3762        if is_user_requested && self.discard_inline_completion(true, cx) {
 3763            return true;
 3764        }
 3765
 3766        if self.snippet_stack.pop().is_some() {
 3767            return true;
 3768        }
 3769
 3770        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3771            self.dismiss_diagnostics(cx);
 3772            return true;
 3773        }
 3774
 3775        false
 3776    }
 3777
 3778    fn linked_editing_ranges_for(
 3779        &self,
 3780        selection: Range<text::Anchor>,
 3781        cx: &App,
 3782    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3783        if self.linked_edit_ranges.is_empty() {
 3784            return None;
 3785        }
 3786        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3787            selection.end.buffer_id.and_then(|end_buffer_id| {
 3788                if selection.start.buffer_id != Some(end_buffer_id) {
 3789                    return None;
 3790                }
 3791                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3792                let snapshot = buffer.read(cx).snapshot();
 3793                self.linked_edit_ranges
 3794                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3795                    .map(|ranges| (ranges, snapshot, buffer))
 3796            })?;
 3797        use text::ToOffset as TO;
 3798        // find offset from the start of current range to current cursor position
 3799        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3800
 3801        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3802        let start_difference = start_offset - start_byte_offset;
 3803        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3804        let end_difference = end_offset - start_byte_offset;
 3805        // Current range has associated linked ranges.
 3806        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3807        for range in linked_ranges.iter() {
 3808            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3809            let end_offset = start_offset + end_difference;
 3810            let start_offset = start_offset + start_difference;
 3811            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3812                continue;
 3813            }
 3814            if self.selections.disjoint_anchor_ranges().any(|s| {
 3815                if s.start.buffer_id != selection.start.buffer_id
 3816                    || s.end.buffer_id != selection.end.buffer_id
 3817                {
 3818                    return false;
 3819                }
 3820                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3821                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3822            }) {
 3823                continue;
 3824            }
 3825            let start = buffer_snapshot.anchor_after(start_offset);
 3826            let end = buffer_snapshot.anchor_after(end_offset);
 3827            linked_edits
 3828                .entry(buffer.clone())
 3829                .or_default()
 3830                .push(start..end);
 3831        }
 3832        Some(linked_edits)
 3833    }
 3834
 3835    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3836        let text: Arc<str> = text.into();
 3837
 3838        if self.read_only(cx) {
 3839            return;
 3840        }
 3841
 3842        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3843
 3844        let selections = self.selections.all_adjusted(cx);
 3845        let mut bracket_inserted = false;
 3846        let mut edits = Vec::new();
 3847        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3848        let mut new_selections = Vec::with_capacity(selections.len());
 3849        let mut new_autoclose_regions = Vec::new();
 3850        let snapshot = self.buffer.read(cx).read(cx);
 3851        let mut clear_linked_edit_ranges = false;
 3852
 3853        for (selection, autoclose_region) in
 3854            self.selections_with_autoclose_regions(selections, &snapshot)
 3855        {
 3856            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3857                // Determine if the inserted text matches the opening or closing
 3858                // bracket of any of this language's bracket pairs.
 3859                let mut bracket_pair = None;
 3860                let mut is_bracket_pair_start = false;
 3861                let mut is_bracket_pair_end = false;
 3862                if !text.is_empty() {
 3863                    let mut bracket_pair_matching_end = None;
 3864                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3865                    //  and they are removing the character that triggered IME popup.
 3866                    for (pair, enabled) in scope.brackets() {
 3867                        if !pair.close && !pair.surround {
 3868                            continue;
 3869                        }
 3870
 3871                        if enabled && pair.start.ends_with(text.as_ref()) {
 3872                            let prefix_len = pair.start.len() - text.len();
 3873                            let preceding_text_matches_prefix = prefix_len == 0
 3874                                || (selection.start.column >= (prefix_len as u32)
 3875                                    && snapshot.contains_str_at(
 3876                                        Point::new(
 3877                                            selection.start.row,
 3878                                            selection.start.column - (prefix_len as u32),
 3879                                        ),
 3880                                        &pair.start[..prefix_len],
 3881                                    ));
 3882                            if preceding_text_matches_prefix {
 3883                                bracket_pair = Some(pair.clone());
 3884                                is_bracket_pair_start = true;
 3885                                break;
 3886                            }
 3887                        }
 3888                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3889                        {
 3890                            // take first bracket pair matching end, but don't break in case a later bracket
 3891                            // pair matches start
 3892                            bracket_pair_matching_end = Some(pair.clone());
 3893                        }
 3894                    }
 3895                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3896                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3897                        is_bracket_pair_end = true;
 3898                    }
 3899                }
 3900
 3901                if let Some(bracket_pair) = bracket_pair {
 3902                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3903                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3904                    let auto_surround =
 3905                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3906                    if selection.is_empty() {
 3907                        if is_bracket_pair_start {
 3908                            // If the inserted text is a suffix of an opening bracket and the
 3909                            // selection is preceded by the rest of the opening bracket, then
 3910                            // insert the closing bracket.
 3911                            let following_text_allows_autoclose = snapshot
 3912                                .chars_at(selection.start)
 3913                                .next()
 3914                                .map_or(true, |c| scope.should_autoclose_before(c));
 3915
 3916                            let preceding_text_allows_autoclose = selection.start.column == 0
 3917                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3918                                    true,
 3919                                    |c| {
 3920                                        bracket_pair.start != bracket_pair.end
 3921                                            || !snapshot
 3922                                                .char_classifier_at(selection.start)
 3923                                                .is_word(c)
 3924                                    },
 3925                                );
 3926
 3927                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3928                                && bracket_pair.start.len() == 1
 3929                            {
 3930                                let target = bracket_pair.start.chars().next().unwrap();
 3931                                let current_line_count = snapshot
 3932                                    .reversed_chars_at(selection.start)
 3933                                    .take_while(|&c| c != '\n')
 3934                                    .filter(|&c| c == target)
 3935                                    .count();
 3936                                current_line_count % 2 == 1
 3937                            } else {
 3938                                false
 3939                            };
 3940
 3941                            if autoclose
 3942                                && bracket_pair.close
 3943                                && following_text_allows_autoclose
 3944                                && preceding_text_allows_autoclose
 3945                                && !is_closing_quote
 3946                            {
 3947                                let anchor = snapshot.anchor_before(selection.end);
 3948                                new_selections.push((selection.map(|_| anchor), text.len()));
 3949                                new_autoclose_regions.push((
 3950                                    anchor,
 3951                                    text.len(),
 3952                                    selection.id,
 3953                                    bracket_pair.clone(),
 3954                                ));
 3955                                edits.push((
 3956                                    selection.range(),
 3957                                    format!("{}{}", text, bracket_pair.end).into(),
 3958                                ));
 3959                                bracket_inserted = true;
 3960                                continue;
 3961                            }
 3962                        }
 3963
 3964                        if let Some(region) = autoclose_region {
 3965                            // If the selection is followed by an auto-inserted closing bracket,
 3966                            // then don't insert that closing bracket again; just move the selection
 3967                            // past the closing bracket.
 3968                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3969                                && text.as_ref() == region.pair.end.as_str();
 3970                            if should_skip {
 3971                                let anchor = snapshot.anchor_after(selection.end);
 3972                                new_selections
 3973                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3974                                continue;
 3975                            }
 3976                        }
 3977
 3978                        let always_treat_brackets_as_autoclosed = snapshot
 3979                            .language_settings_at(selection.start, cx)
 3980                            .always_treat_brackets_as_autoclosed;
 3981                        if always_treat_brackets_as_autoclosed
 3982                            && is_bracket_pair_end
 3983                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3984                        {
 3985                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3986                            // and the inserted text is a closing bracket and the selection is followed
 3987                            // by the closing bracket then move the selection past the closing bracket.
 3988                            let anchor = snapshot.anchor_after(selection.end);
 3989                            new_selections.push((selection.map(|_| anchor), text.len()));
 3990                            continue;
 3991                        }
 3992                    }
 3993                    // If an opening bracket is 1 character long and is typed while
 3994                    // text is selected, then surround that text with the bracket pair.
 3995                    else if auto_surround
 3996                        && bracket_pair.surround
 3997                        && is_bracket_pair_start
 3998                        && bracket_pair.start.chars().count() == 1
 3999                    {
 4000                        edits.push((selection.start..selection.start, text.clone()));
 4001                        edits.push((
 4002                            selection.end..selection.end,
 4003                            bracket_pair.end.as_str().into(),
 4004                        ));
 4005                        bracket_inserted = true;
 4006                        new_selections.push((
 4007                            Selection {
 4008                                id: selection.id,
 4009                                start: snapshot.anchor_after(selection.start),
 4010                                end: snapshot.anchor_before(selection.end),
 4011                                reversed: selection.reversed,
 4012                                goal: selection.goal,
 4013                            },
 4014                            0,
 4015                        ));
 4016                        continue;
 4017                    }
 4018                }
 4019            }
 4020
 4021            if self.auto_replace_emoji_shortcode
 4022                && selection.is_empty()
 4023                && text.as_ref().ends_with(':')
 4024            {
 4025                if let Some(possible_emoji_short_code) =
 4026                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4027                {
 4028                    if !possible_emoji_short_code.is_empty() {
 4029                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4030                            let emoji_shortcode_start = Point::new(
 4031                                selection.start.row,
 4032                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4033                            );
 4034
 4035                            // Remove shortcode from buffer
 4036                            edits.push((
 4037                                emoji_shortcode_start..selection.start,
 4038                                "".to_string().into(),
 4039                            ));
 4040                            new_selections.push((
 4041                                Selection {
 4042                                    id: selection.id,
 4043                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4044                                    end: snapshot.anchor_before(selection.start),
 4045                                    reversed: selection.reversed,
 4046                                    goal: selection.goal,
 4047                                },
 4048                                0,
 4049                            ));
 4050
 4051                            // Insert emoji
 4052                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4053                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4054                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4055
 4056                            continue;
 4057                        }
 4058                    }
 4059                }
 4060            }
 4061
 4062            // If not handling any auto-close operation, then just replace the selected
 4063            // text with the given input and move the selection to the end of the
 4064            // newly inserted text.
 4065            let anchor = snapshot.anchor_after(selection.end);
 4066            if !self.linked_edit_ranges.is_empty() {
 4067                let start_anchor = snapshot.anchor_before(selection.start);
 4068
 4069                let is_word_char = text.chars().next().map_or(true, |char| {
 4070                    let classifier = snapshot
 4071                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4072                        .ignore_punctuation(true);
 4073                    classifier.is_word(char)
 4074                });
 4075
 4076                if is_word_char {
 4077                    if let Some(ranges) = self
 4078                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4079                    {
 4080                        for (buffer, edits) in ranges {
 4081                            linked_edits
 4082                                .entry(buffer.clone())
 4083                                .or_default()
 4084                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4085                        }
 4086                    }
 4087                } else {
 4088                    clear_linked_edit_ranges = true;
 4089                }
 4090            }
 4091
 4092            new_selections.push((selection.map(|_| anchor), 0));
 4093            edits.push((selection.start..selection.end, text.clone()));
 4094        }
 4095
 4096        drop(snapshot);
 4097
 4098        self.transact(window, cx, |this, window, cx| {
 4099            if clear_linked_edit_ranges {
 4100                this.linked_edit_ranges.clear();
 4101            }
 4102            let initial_buffer_versions =
 4103                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4104
 4105            this.buffer.update(cx, |buffer, cx| {
 4106                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4107            });
 4108            for (buffer, edits) in linked_edits {
 4109                buffer.update(cx, |buffer, cx| {
 4110                    let snapshot = buffer.snapshot();
 4111                    let edits = edits
 4112                        .into_iter()
 4113                        .map(|(range, text)| {
 4114                            use text::ToPoint as TP;
 4115                            let end_point = TP::to_point(&range.end, &snapshot);
 4116                            let start_point = TP::to_point(&range.start, &snapshot);
 4117                            (start_point..end_point, text)
 4118                        })
 4119                        .sorted_by_key(|(range, _)| range.start);
 4120                    buffer.edit(edits, None, cx);
 4121                })
 4122            }
 4123            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4124            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4125            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4126            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4127                .zip(new_selection_deltas)
 4128                .map(|(selection, delta)| Selection {
 4129                    id: selection.id,
 4130                    start: selection.start + delta,
 4131                    end: selection.end + delta,
 4132                    reversed: selection.reversed,
 4133                    goal: SelectionGoal::None,
 4134                })
 4135                .collect::<Vec<_>>();
 4136
 4137            let mut i = 0;
 4138            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4139                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4140                let start = map.buffer_snapshot.anchor_before(position);
 4141                let end = map.buffer_snapshot.anchor_after(position);
 4142                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4143                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4144                        Ordering::Less => i += 1,
 4145                        Ordering::Greater => break,
 4146                        Ordering::Equal => {
 4147                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4148                                Ordering::Less => i += 1,
 4149                                Ordering::Equal => break,
 4150                                Ordering::Greater => break,
 4151                            }
 4152                        }
 4153                    }
 4154                }
 4155                this.autoclose_regions.insert(
 4156                    i,
 4157                    AutocloseRegion {
 4158                        selection_id,
 4159                        range: start..end,
 4160                        pair,
 4161                    },
 4162                );
 4163            }
 4164
 4165            let had_active_inline_completion = this.has_active_inline_completion();
 4166            this.change_selections(
 4167                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4168                window,
 4169                cx,
 4170                |s| s.select(new_selections),
 4171            );
 4172
 4173            if !bracket_inserted {
 4174                if let Some(on_type_format_task) =
 4175                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4176                {
 4177                    on_type_format_task.detach_and_log_err(cx);
 4178                }
 4179            }
 4180
 4181            let editor_settings = EditorSettings::get_global(cx);
 4182            if bracket_inserted
 4183                && (editor_settings.auto_signature_help
 4184                    || editor_settings.show_signature_help_after_edits)
 4185            {
 4186                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4187            }
 4188
 4189            let trigger_in_words =
 4190                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4191            if this.hard_wrap.is_some() {
 4192                let latest: Range<Point> = this.selections.newest(cx).range();
 4193                if latest.is_empty()
 4194                    && this
 4195                        .buffer()
 4196                        .read(cx)
 4197                        .snapshot(cx)
 4198                        .line_len(MultiBufferRow(latest.start.row))
 4199                        == latest.start.column
 4200                {
 4201                    this.rewrap_impl(
 4202                        RewrapOptions {
 4203                            override_language_settings: true,
 4204                            preserve_existing_whitespace: true,
 4205                        },
 4206                        cx,
 4207                    )
 4208                }
 4209            }
 4210            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4211            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4212            this.refresh_inline_completion(true, false, window, cx);
 4213            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4214        });
 4215    }
 4216
 4217    fn find_possible_emoji_shortcode_at_position(
 4218        snapshot: &MultiBufferSnapshot,
 4219        position: Point,
 4220    ) -> Option<String> {
 4221        let mut chars = Vec::new();
 4222        let mut found_colon = false;
 4223        for char in snapshot.reversed_chars_at(position).take(100) {
 4224            // Found a possible emoji shortcode in the middle of the buffer
 4225            if found_colon {
 4226                if char.is_whitespace() {
 4227                    chars.reverse();
 4228                    return Some(chars.iter().collect());
 4229                }
 4230                // If the previous character is not a whitespace, we are in the middle of a word
 4231                // and we only want to complete the shortcode if the word is made up of other emojis
 4232                let mut containing_word = String::new();
 4233                for ch in snapshot
 4234                    .reversed_chars_at(position)
 4235                    .skip(chars.len() + 1)
 4236                    .take(100)
 4237                {
 4238                    if ch.is_whitespace() {
 4239                        break;
 4240                    }
 4241                    containing_word.push(ch);
 4242                }
 4243                let containing_word = containing_word.chars().rev().collect::<String>();
 4244                if util::word_consists_of_emojis(containing_word.as_str()) {
 4245                    chars.reverse();
 4246                    return Some(chars.iter().collect());
 4247                }
 4248            }
 4249
 4250            if char.is_whitespace() || !char.is_ascii() {
 4251                return None;
 4252            }
 4253            if char == ':' {
 4254                found_colon = true;
 4255            } else {
 4256                chars.push(char);
 4257            }
 4258        }
 4259        // Found a possible emoji shortcode at the beginning of the buffer
 4260        chars.reverse();
 4261        Some(chars.iter().collect())
 4262    }
 4263
 4264    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4265        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4266        self.transact(window, cx, |this, window, cx| {
 4267            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4268                let selections = this.selections.all::<usize>(cx);
 4269                let multi_buffer = this.buffer.read(cx);
 4270                let buffer = multi_buffer.snapshot(cx);
 4271                selections
 4272                    .iter()
 4273                    .map(|selection| {
 4274                        let start_point = selection.start.to_point(&buffer);
 4275                        let mut existing_indent =
 4276                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4277                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4278                        let start = selection.start;
 4279                        let end = selection.end;
 4280                        let selection_is_empty = start == end;
 4281                        let language_scope = buffer.language_scope_at(start);
 4282                        let (
 4283                            comment_delimiter,
 4284                            doc_delimiter,
 4285                            insert_extra_newline,
 4286                            indent_on_newline,
 4287                            indent_on_extra_newline,
 4288                        ) = if let Some(language) = &language_scope {
 4289                            let mut insert_extra_newline =
 4290                                insert_extra_newline_brackets(&buffer, start..end, language)
 4291                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4292
 4293                            // Comment extension on newline is allowed only for cursor selections
 4294                            let comment_delimiter = maybe!({
 4295                                if !selection_is_empty {
 4296                                    return None;
 4297                                }
 4298
 4299                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4300                                    return None;
 4301                                }
 4302
 4303                                let delimiters = language.line_comment_prefixes();
 4304                                let max_len_of_delimiter =
 4305                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4306                                let (snapshot, range) =
 4307                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4308
 4309                                let num_of_whitespaces = snapshot
 4310                                    .chars_for_range(range.clone())
 4311                                    .take_while(|c| c.is_whitespace())
 4312                                    .count();
 4313                                let comment_candidate = snapshot
 4314                                    .chars_for_range(range)
 4315                                    .skip(num_of_whitespaces)
 4316                                    .take(max_len_of_delimiter)
 4317                                    .collect::<String>();
 4318                                let (delimiter, trimmed_len) = delimiters
 4319                                    .iter()
 4320                                    .filter_map(|delimiter| {
 4321                                        let prefix = delimiter.trim_end();
 4322                                        if comment_candidate.starts_with(prefix) {
 4323                                            Some((delimiter, prefix.len()))
 4324                                        } else {
 4325                                            None
 4326                                        }
 4327                                    })
 4328                                    .max_by_key(|(_, len)| *len)?;
 4329
 4330                                let cursor_is_placed_after_comment_marker =
 4331                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4332                                if cursor_is_placed_after_comment_marker {
 4333                                    Some(delimiter.clone())
 4334                                } else {
 4335                                    None
 4336                                }
 4337                            });
 4338
 4339                            let mut indent_on_newline = IndentSize::spaces(0);
 4340                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4341
 4342                            let doc_delimiter = maybe!({
 4343                                if !selection_is_empty {
 4344                                    return None;
 4345                                }
 4346
 4347                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4348                                    return None;
 4349                                }
 4350
 4351                                let DocumentationConfig {
 4352                                    start: start_tag,
 4353                                    end: end_tag,
 4354                                    prefix: delimiter,
 4355                                    tab_size: len,
 4356                                } = language.documentation()?;
 4357
 4358                                let is_within_block_comment = buffer
 4359                                    .language_scope_at(start_point)
 4360                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4361                                if !is_within_block_comment {
 4362                                    return None;
 4363                                }
 4364
 4365                                let (snapshot, range) =
 4366                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4367
 4368                                let num_of_whitespaces = snapshot
 4369                                    .chars_for_range(range.clone())
 4370                                    .take_while(|c| c.is_whitespace())
 4371                                    .count();
 4372
 4373                                // 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.
 4374                                let column = start_point.column;
 4375                                let cursor_is_after_start_tag = {
 4376                                    let start_tag_len = start_tag.len();
 4377                                    let start_tag_line = snapshot
 4378                                        .chars_for_range(range.clone())
 4379                                        .skip(num_of_whitespaces)
 4380                                        .take(start_tag_len)
 4381                                        .collect::<String>();
 4382                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4383                                        num_of_whitespaces + start_tag_len <= column as usize
 4384                                    } else {
 4385                                        false
 4386                                    }
 4387                                };
 4388
 4389                                let cursor_is_after_delimiter = {
 4390                                    let delimiter_trim = delimiter.trim_end();
 4391                                    let delimiter_line = snapshot
 4392                                        .chars_for_range(range.clone())
 4393                                        .skip(num_of_whitespaces)
 4394                                        .take(delimiter_trim.len())
 4395                                        .collect::<String>();
 4396                                    if delimiter_line.starts_with(delimiter_trim) {
 4397                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4398                                    } else {
 4399                                        false
 4400                                    }
 4401                                };
 4402
 4403                                let cursor_is_before_end_tag_if_exists = {
 4404                                    let mut char_position = 0u32;
 4405                                    let mut end_tag_offset = None;
 4406
 4407                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4408                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4409                                            let chars_before_match =
 4410                                                chunk[..byte_pos].chars().count() as u32;
 4411                                            end_tag_offset =
 4412                                                Some(char_position + chars_before_match);
 4413                                            break 'outer;
 4414                                        }
 4415                                        char_position += chunk.chars().count() as u32;
 4416                                    }
 4417
 4418                                    if let Some(end_tag_offset) = end_tag_offset {
 4419                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4420                                        if cursor_is_after_start_tag {
 4421                                            if cursor_is_before_end_tag {
 4422                                                insert_extra_newline = true;
 4423                                            }
 4424                                            let cursor_is_at_start_of_end_tag =
 4425                                                column == end_tag_offset;
 4426                                            if cursor_is_at_start_of_end_tag {
 4427                                                indent_on_extra_newline.len = (*len).into();
 4428                                            }
 4429                                        }
 4430                                        cursor_is_before_end_tag
 4431                                    } else {
 4432                                        true
 4433                                    }
 4434                                };
 4435
 4436                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4437                                    && cursor_is_before_end_tag_if_exists
 4438                                {
 4439                                    if cursor_is_after_start_tag {
 4440                                        indent_on_newline.len = (*len).into();
 4441                                    }
 4442                                    Some(delimiter.clone())
 4443                                } else {
 4444                                    None
 4445                                }
 4446                            });
 4447
 4448                            (
 4449                                comment_delimiter,
 4450                                doc_delimiter,
 4451                                insert_extra_newline,
 4452                                indent_on_newline,
 4453                                indent_on_extra_newline,
 4454                            )
 4455                        } else {
 4456                            (
 4457                                None,
 4458                                None,
 4459                                false,
 4460                                IndentSize::default(),
 4461                                IndentSize::default(),
 4462                            )
 4463                        };
 4464
 4465                        let prevent_auto_indent = doc_delimiter.is_some();
 4466                        let delimiter = comment_delimiter.or(doc_delimiter);
 4467
 4468                        let capacity_for_delimiter =
 4469                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4470                        let mut new_text = String::with_capacity(
 4471                            1 + capacity_for_delimiter
 4472                                + existing_indent.len as usize
 4473                                + indent_on_newline.len as usize
 4474                                + indent_on_extra_newline.len as usize,
 4475                        );
 4476                        new_text.push('\n');
 4477                        new_text.extend(existing_indent.chars());
 4478                        new_text.extend(indent_on_newline.chars());
 4479
 4480                        if let Some(delimiter) = &delimiter {
 4481                            new_text.push_str(delimiter);
 4482                        }
 4483
 4484                        if insert_extra_newline {
 4485                            new_text.push('\n');
 4486                            new_text.extend(existing_indent.chars());
 4487                            new_text.extend(indent_on_extra_newline.chars());
 4488                        }
 4489
 4490                        let anchor = buffer.anchor_after(end);
 4491                        let new_selection = selection.map(|_| anchor);
 4492                        (
 4493                            ((start..end, new_text), prevent_auto_indent),
 4494                            (insert_extra_newline, new_selection),
 4495                        )
 4496                    })
 4497                    .unzip()
 4498            };
 4499
 4500            let mut auto_indent_edits = Vec::new();
 4501            let mut edits = Vec::new();
 4502            for (edit, prevent_auto_indent) in edits_with_flags {
 4503                if prevent_auto_indent {
 4504                    edits.push(edit);
 4505                } else {
 4506                    auto_indent_edits.push(edit);
 4507                }
 4508            }
 4509            if !edits.is_empty() {
 4510                this.edit(edits, cx);
 4511            }
 4512            if !auto_indent_edits.is_empty() {
 4513                this.edit_with_autoindent(auto_indent_edits, cx);
 4514            }
 4515
 4516            let buffer = this.buffer.read(cx).snapshot(cx);
 4517            let new_selections = selection_info
 4518                .into_iter()
 4519                .map(|(extra_newline_inserted, new_selection)| {
 4520                    let mut cursor = new_selection.end.to_point(&buffer);
 4521                    if extra_newline_inserted {
 4522                        cursor.row -= 1;
 4523                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4524                    }
 4525                    new_selection.map(|_| cursor)
 4526                })
 4527                .collect();
 4528
 4529            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4530                s.select(new_selections)
 4531            });
 4532            this.refresh_inline_completion(true, false, window, cx);
 4533        });
 4534    }
 4535
 4536    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4537        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4538
 4539        let buffer = self.buffer.read(cx);
 4540        let snapshot = buffer.snapshot(cx);
 4541
 4542        let mut edits = Vec::new();
 4543        let mut rows = Vec::new();
 4544
 4545        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4546            let cursor = selection.head();
 4547            let row = cursor.row;
 4548
 4549            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4550
 4551            let newline = "\n".to_string();
 4552            edits.push((start_of_line..start_of_line, newline));
 4553
 4554            rows.push(row + rows_inserted as u32);
 4555        }
 4556
 4557        self.transact(window, cx, |editor, window, cx| {
 4558            editor.edit(edits, cx);
 4559
 4560            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4561                let mut index = 0;
 4562                s.move_cursors_with(|map, _, _| {
 4563                    let row = rows[index];
 4564                    index += 1;
 4565
 4566                    let point = Point::new(row, 0);
 4567                    let boundary = map.next_line_boundary(point).1;
 4568                    let clipped = map.clip_point(boundary, Bias::Left);
 4569
 4570                    (clipped, SelectionGoal::None)
 4571                });
 4572            });
 4573
 4574            let mut indent_edits = Vec::new();
 4575            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4576            for row in rows {
 4577                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4578                for (row, indent) in indents {
 4579                    if indent.len == 0 {
 4580                        continue;
 4581                    }
 4582
 4583                    let text = match indent.kind {
 4584                        IndentKind::Space => " ".repeat(indent.len as usize),
 4585                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4586                    };
 4587                    let point = Point::new(row.0, 0);
 4588                    indent_edits.push((point..point, text));
 4589                }
 4590            }
 4591            editor.edit(indent_edits, cx);
 4592        });
 4593    }
 4594
 4595    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4596        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4597
 4598        let buffer = self.buffer.read(cx);
 4599        let snapshot = buffer.snapshot(cx);
 4600
 4601        let mut edits = Vec::new();
 4602        let mut rows = Vec::new();
 4603        let mut rows_inserted = 0;
 4604
 4605        for selection in self.selections.all_adjusted(cx) {
 4606            let cursor = selection.head();
 4607            let row = cursor.row;
 4608
 4609            let point = Point::new(row + 1, 0);
 4610            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4611
 4612            let newline = "\n".to_string();
 4613            edits.push((start_of_line..start_of_line, newline));
 4614
 4615            rows_inserted += 1;
 4616            rows.push(row + rows_inserted);
 4617        }
 4618
 4619        self.transact(window, cx, |editor, window, cx| {
 4620            editor.edit(edits, cx);
 4621
 4622            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4623                let mut index = 0;
 4624                s.move_cursors_with(|map, _, _| {
 4625                    let row = rows[index];
 4626                    index += 1;
 4627
 4628                    let point = Point::new(row, 0);
 4629                    let boundary = map.next_line_boundary(point).1;
 4630                    let clipped = map.clip_point(boundary, Bias::Left);
 4631
 4632                    (clipped, SelectionGoal::None)
 4633                });
 4634            });
 4635
 4636            let mut indent_edits = Vec::new();
 4637            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4638            for row in rows {
 4639                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4640                for (row, indent) in indents {
 4641                    if indent.len == 0 {
 4642                        continue;
 4643                    }
 4644
 4645                    let text = match indent.kind {
 4646                        IndentKind::Space => " ".repeat(indent.len as usize),
 4647                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4648                    };
 4649                    let point = Point::new(row.0, 0);
 4650                    indent_edits.push((point..point, text));
 4651                }
 4652            }
 4653            editor.edit(indent_edits, cx);
 4654        });
 4655    }
 4656
 4657    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4658        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4659            original_indent_columns: Vec::new(),
 4660        });
 4661        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4662    }
 4663
 4664    fn insert_with_autoindent_mode(
 4665        &mut self,
 4666        text: &str,
 4667        autoindent_mode: Option<AutoindentMode>,
 4668        window: &mut Window,
 4669        cx: &mut Context<Self>,
 4670    ) {
 4671        if self.read_only(cx) {
 4672            return;
 4673        }
 4674
 4675        let text: Arc<str> = text.into();
 4676        self.transact(window, cx, |this, window, cx| {
 4677            let old_selections = this.selections.all_adjusted(cx);
 4678            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4679                let anchors = {
 4680                    let snapshot = buffer.read(cx);
 4681                    old_selections
 4682                        .iter()
 4683                        .map(|s| {
 4684                            let anchor = snapshot.anchor_after(s.head());
 4685                            s.map(|_| anchor)
 4686                        })
 4687                        .collect::<Vec<_>>()
 4688                };
 4689                buffer.edit(
 4690                    old_selections
 4691                        .iter()
 4692                        .map(|s| (s.start..s.end, text.clone())),
 4693                    autoindent_mode,
 4694                    cx,
 4695                );
 4696                anchors
 4697            });
 4698
 4699            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4700                s.select_anchors(selection_anchors);
 4701            });
 4702
 4703            cx.notify();
 4704        });
 4705    }
 4706
 4707    fn trigger_completion_on_input(
 4708        &mut self,
 4709        text: &str,
 4710        trigger_in_words: bool,
 4711        window: &mut Window,
 4712        cx: &mut Context<Self>,
 4713    ) {
 4714        let completions_source = self
 4715            .context_menu
 4716            .borrow()
 4717            .as_ref()
 4718            .and_then(|menu| match menu {
 4719                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4720                CodeContextMenu::CodeActions(_) => None,
 4721            });
 4722
 4723        match completions_source {
 4724            Some(CompletionsMenuSource::Words) => {
 4725                self.show_word_completions(&ShowWordCompletions, window, cx)
 4726            }
 4727            Some(CompletionsMenuSource::Normal)
 4728            | Some(CompletionsMenuSource::SnippetChoices)
 4729            | None
 4730                if self.is_completion_trigger(
 4731                    text,
 4732                    trigger_in_words,
 4733                    completions_source.is_some(),
 4734                    cx,
 4735                ) =>
 4736            {
 4737                self.show_completions(
 4738                    &ShowCompletions {
 4739                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4740                    },
 4741                    window,
 4742                    cx,
 4743                )
 4744            }
 4745            _ => {
 4746                self.hide_context_menu(window, cx);
 4747            }
 4748        }
 4749    }
 4750
 4751    fn is_completion_trigger(
 4752        &self,
 4753        text: &str,
 4754        trigger_in_words: bool,
 4755        menu_is_open: bool,
 4756        cx: &mut Context<Self>,
 4757    ) -> bool {
 4758        let position = self.selections.newest_anchor().head();
 4759        let multibuffer = self.buffer.read(cx);
 4760        let Some(buffer) = position
 4761            .buffer_id
 4762            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4763        else {
 4764            return false;
 4765        };
 4766
 4767        if let Some(completion_provider) = &self.completion_provider {
 4768            completion_provider.is_completion_trigger(
 4769                &buffer,
 4770                position.text_anchor,
 4771                text,
 4772                trigger_in_words,
 4773                menu_is_open,
 4774                cx,
 4775            )
 4776        } else {
 4777            false
 4778        }
 4779    }
 4780
 4781    /// If any empty selections is touching the start of its innermost containing autoclose
 4782    /// region, expand it to select the brackets.
 4783    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4784        let selections = self.selections.all::<usize>(cx);
 4785        let buffer = self.buffer.read(cx).read(cx);
 4786        let new_selections = self
 4787            .selections_with_autoclose_regions(selections, &buffer)
 4788            .map(|(mut selection, region)| {
 4789                if !selection.is_empty() {
 4790                    return selection;
 4791                }
 4792
 4793                if let Some(region) = region {
 4794                    let mut range = region.range.to_offset(&buffer);
 4795                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4796                        range.start -= region.pair.start.len();
 4797                        if buffer.contains_str_at(range.start, &region.pair.start)
 4798                            && buffer.contains_str_at(range.end, &region.pair.end)
 4799                        {
 4800                            range.end += region.pair.end.len();
 4801                            selection.start = range.start;
 4802                            selection.end = range.end;
 4803
 4804                            return selection;
 4805                        }
 4806                    }
 4807                }
 4808
 4809                let always_treat_brackets_as_autoclosed = buffer
 4810                    .language_settings_at(selection.start, cx)
 4811                    .always_treat_brackets_as_autoclosed;
 4812
 4813                if !always_treat_brackets_as_autoclosed {
 4814                    return selection;
 4815                }
 4816
 4817                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4818                    for (pair, enabled) in scope.brackets() {
 4819                        if !enabled || !pair.close {
 4820                            continue;
 4821                        }
 4822
 4823                        if buffer.contains_str_at(selection.start, &pair.end) {
 4824                            let pair_start_len = pair.start.len();
 4825                            if buffer.contains_str_at(
 4826                                selection.start.saturating_sub(pair_start_len),
 4827                                &pair.start,
 4828                            ) {
 4829                                selection.start -= pair_start_len;
 4830                                selection.end += pair.end.len();
 4831
 4832                                return selection;
 4833                            }
 4834                        }
 4835                    }
 4836                }
 4837
 4838                selection
 4839            })
 4840            .collect();
 4841
 4842        drop(buffer);
 4843        self.change_selections(None, window, cx, |selections| {
 4844            selections.select(new_selections)
 4845        });
 4846    }
 4847
 4848    /// Iterate the given selections, and for each one, find the smallest surrounding
 4849    /// autoclose region. This uses the ordering of the selections and the autoclose
 4850    /// regions to avoid repeated comparisons.
 4851    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4852        &'a self,
 4853        selections: impl IntoIterator<Item = Selection<D>>,
 4854        buffer: &'a MultiBufferSnapshot,
 4855    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4856        let mut i = 0;
 4857        let mut regions = self.autoclose_regions.as_slice();
 4858        selections.into_iter().map(move |selection| {
 4859            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4860
 4861            let mut enclosing = None;
 4862            while let Some(pair_state) = regions.get(i) {
 4863                if pair_state.range.end.to_offset(buffer) < range.start {
 4864                    regions = &regions[i + 1..];
 4865                    i = 0;
 4866                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4867                    break;
 4868                } else {
 4869                    if pair_state.selection_id == selection.id {
 4870                        enclosing = Some(pair_state);
 4871                    }
 4872                    i += 1;
 4873                }
 4874            }
 4875
 4876            (selection, enclosing)
 4877        })
 4878    }
 4879
 4880    /// Remove any autoclose regions that no longer contain their selection.
 4881    fn invalidate_autoclose_regions(
 4882        &mut self,
 4883        mut selections: &[Selection<Anchor>],
 4884        buffer: &MultiBufferSnapshot,
 4885    ) {
 4886        self.autoclose_regions.retain(|state| {
 4887            let mut i = 0;
 4888            while let Some(selection) = selections.get(i) {
 4889                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4890                    selections = &selections[1..];
 4891                    continue;
 4892                }
 4893                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4894                    break;
 4895                }
 4896                if selection.id == state.selection_id {
 4897                    return true;
 4898                } else {
 4899                    i += 1;
 4900                }
 4901            }
 4902            false
 4903        });
 4904    }
 4905
 4906    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4907        let offset = position.to_offset(buffer);
 4908        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4909        if offset > word_range.start && kind == Some(CharKind::Word) {
 4910            Some(
 4911                buffer
 4912                    .text_for_range(word_range.start..offset)
 4913                    .collect::<String>(),
 4914            )
 4915        } else {
 4916            None
 4917        }
 4918    }
 4919
 4920    pub fn toggle_inline_values(
 4921        &mut self,
 4922        _: &ToggleInlineValues,
 4923        _: &mut Window,
 4924        cx: &mut Context<Self>,
 4925    ) {
 4926        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4927
 4928        self.refresh_inline_values(cx);
 4929    }
 4930
 4931    pub fn toggle_inlay_hints(
 4932        &mut self,
 4933        _: &ToggleInlayHints,
 4934        _: &mut Window,
 4935        cx: &mut Context<Self>,
 4936    ) {
 4937        self.refresh_inlay_hints(
 4938            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4939            cx,
 4940        );
 4941    }
 4942
 4943    pub fn inlay_hints_enabled(&self) -> bool {
 4944        self.inlay_hint_cache.enabled
 4945    }
 4946
 4947    pub fn inline_values_enabled(&self) -> bool {
 4948        self.inline_value_cache.enabled
 4949    }
 4950
 4951    #[cfg(any(test, feature = "test-support"))]
 4952    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4953        self.display_map
 4954            .read(cx)
 4955            .current_inlays()
 4956            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4957            .cloned()
 4958            .collect()
 4959    }
 4960
 4961    #[cfg(any(test, feature = "test-support"))]
 4962    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 4963        self.display_map
 4964            .read(cx)
 4965            .current_inlays()
 4966            .cloned()
 4967            .collect()
 4968    }
 4969
 4970    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4971        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4972            return;
 4973        }
 4974
 4975        let reason_description = reason.description();
 4976        let ignore_debounce = matches!(
 4977            reason,
 4978            InlayHintRefreshReason::SettingsChange(_)
 4979                | InlayHintRefreshReason::Toggle(_)
 4980                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4981                | InlayHintRefreshReason::ModifiersChanged(_)
 4982        );
 4983        let (invalidate_cache, required_languages) = match reason {
 4984            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4985                match self.inlay_hint_cache.modifiers_override(enabled) {
 4986                    Some(enabled) => {
 4987                        if enabled {
 4988                            (InvalidationStrategy::RefreshRequested, None)
 4989                        } else {
 4990                            self.splice_inlays(
 4991                                &self
 4992                                    .visible_inlay_hints(cx)
 4993                                    .iter()
 4994                                    .map(|inlay| inlay.id)
 4995                                    .collect::<Vec<InlayId>>(),
 4996                                Vec::new(),
 4997                                cx,
 4998                            );
 4999                            return;
 5000                        }
 5001                    }
 5002                    None => return,
 5003                }
 5004            }
 5005            InlayHintRefreshReason::Toggle(enabled) => {
 5006                if self.inlay_hint_cache.toggle(enabled) {
 5007                    if enabled {
 5008                        (InvalidationStrategy::RefreshRequested, None)
 5009                    } else {
 5010                        self.splice_inlays(
 5011                            &self
 5012                                .visible_inlay_hints(cx)
 5013                                .iter()
 5014                                .map(|inlay| inlay.id)
 5015                                .collect::<Vec<InlayId>>(),
 5016                            Vec::new(),
 5017                            cx,
 5018                        );
 5019                        return;
 5020                    }
 5021                } else {
 5022                    return;
 5023                }
 5024            }
 5025            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5026                match self.inlay_hint_cache.update_settings(
 5027                    &self.buffer,
 5028                    new_settings,
 5029                    self.visible_inlay_hints(cx),
 5030                    cx,
 5031                ) {
 5032                    ControlFlow::Break(Some(InlaySplice {
 5033                        to_remove,
 5034                        to_insert,
 5035                    })) => {
 5036                        self.splice_inlays(&to_remove, to_insert, cx);
 5037                        return;
 5038                    }
 5039                    ControlFlow::Break(None) => return,
 5040                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5041                }
 5042            }
 5043            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5044                if let Some(InlaySplice {
 5045                    to_remove,
 5046                    to_insert,
 5047                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5048                {
 5049                    self.splice_inlays(&to_remove, to_insert, cx);
 5050                }
 5051                self.display_map.update(cx, |display_map, _| {
 5052                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5053                });
 5054                return;
 5055            }
 5056            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5057            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5058                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5059            }
 5060            InlayHintRefreshReason::RefreshRequested => {
 5061                (InvalidationStrategy::RefreshRequested, None)
 5062            }
 5063        };
 5064
 5065        if let Some(InlaySplice {
 5066            to_remove,
 5067            to_insert,
 5068        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5069            reason_description,
 5070            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 5071            invalidate_cache,
 5072            ignore_debounce,
 5073            cx,
 5074        ) {
 5075            self.splice_inlays(&to_remove, to_insert, cx);
 5076        }
 5077    }
 5078
 5079    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5080        self.display_map
 5081            .read(cx)
 5082            .current_inlays()
 5083            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5084            .cloned()
 5085            .collect()
 5086    }
 5087
 5088    pub fn excerpts_for_inlay_hints_query(
 5089        &self,
 5090        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5091        cx: &mut Context<Editor>,
 5092    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5093        let Some(project) = self.project.as_ref() else {
 5094            return HashMap::default();
 5095        };
 5096        let project = project.read(cx);
 5097        let multi_buffer = self.buffer().read(cx);
 5098        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5099        let multi_buffer_visible_start = self
 5100            .scroll_manager
 5101            .anchor()
 5102            .anchor
 5103            .to_point(&multi_buffer_snapshot);
 5104        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5105            multi_buffer_visible_start
 5106                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5107            Bias::Left,
 5108        );
 5109        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5110        multi_buffer_snapshot
 5111            .range_to_buffer_ranges(multi_buffer_visible_range)
 5112            .into_iter()
 5113            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5114            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5115                let buffer_file = project::File::from_dyn(buffer.file())?;
 5116                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5117                let worktree_entry = buffer_worktree
 5118                    .read(cx)
 5119                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5120                if worktree_entry.is_ignored {
 5121                    return None;
 5122                }
 5123
 5124                let language = buffer.language()?;
 5125                if let Some(restrict_to_languages) = restrict_to_languages {
 5126                    if !restrict_to_languages.contains(language) {
 5127                        return None;
 5128                    }
 5129                }
 5130                Some((
 5131                    excerpt_id,
 5132                    (
 5133                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5134                        buffer.version().clone(),
 5135                        excerpt_visible_range,
 5136                    ),
 5137                ))
 5138            })
 5139            .collect()
 5140    }
 5141
 5142    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5143        TextLayoutDetails {
 5144            text_system: window.text_system().clone(),
 5145            editor_style: self.style.clone().unwrap(),
 5146            rem_size: window.rem_size(),
 5147            scroll_anchor: self.scroll_manager.anchor(),
 5148            visible_rows: self.visible_line_count(),
 5149            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5150        }
 5151    }
 5152
 5153    pub fn splice_inlays(
 5154        &self,
 5155        to_remove: &[InlayId],
 5156        to_insert: Vec<Inlay>,
 5157        cx: &mut Context<Self>,
 5158    ) {
 5159        self.display_map.update(cx, |display_map, cx| {
 5160            display_map.splice_inlays(to_remove, to_insert, cx)
 5161        });
 5162        cx.notify();
 5163    }
 5164
 5165    fn trigger_on_type_formatting(
 5166        &self,
 5167        input: String,
 5168        window: &mut Window,
 5169        cx: &mut Context<Self>,
 5170    ) -> Option<Task<Result<()>>> {
 5171        if input.len() != 1 {
 5172            return None;
 5173        }
 5174
 5175        let project = self.project.as_ref()?;
 5176        let position = self.selections.newest_anchor().head();
 5177        let (buffer, buffer_position) = self
 5178            .buffer
 5179            .read(cx)
 5180            .text_anchor_for_position(position, cx)?;
 5181
 5182        let settings = language_settings::language_settings(
 5183            buffer
 5184                .read(cx)
 5185                .language_at(buffer_position)
 5186                .map(|l| l.name()),
 5187            buffer.read(cx).file(),
 5188            cx,
 5189        );
 5190        if !settings.use_on_type_format {
 5191            return None;
 5192        }
 5193
 5194        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5195        // hence we do LSP request & edit on host side only — add formats to host's history.
 5196        let push_to_lsp_host_history = true;
 5197        // If this is not the host, append its history with new edits.
 5198        let push_to_client_history = project.read(cx).is_via_collab();
 5199
 5200        let on_type_formatting = project.update(cx, |project, cx| {
 5201            project.on_type_format(
 5202                buffer.clone(),
 5203                buffer_position,
 5204                input,
 5205                push_to_lsp_host_history,
 5206                cx,
 5207            )
 5208        });
 5209        Some(cx.spawn_in(window, async move |editor, cx| {
 5210            if let Some(transaction) = on_type_formatting.await? {
 5211                if push_to_client_history {
 5212                    buffer
 5213                        .update(cx, |buffer, _| {
 5214                            buffer.push_transaction(transaction, Instant::now());
 5215                            buffer.finalize_last_transaction();
 5216                        })
 5217                        .ok();
 5218                }
 5219                editor.update(cx, |editor, cx| {
 5220                    editor.refresh_document_highlights(cx);
 5221                })?;
 5222            }
 5223            Ok(())
 5224        }))
 5225    }
 5226
 5227    pub fn show_word_completions(
 5228        &mut self,
 5229        _: &ShowWordCompletions,
 5230        window: &mut Window,
 5231        cx: &mut Context<Self>,
 5232    ) {
 5233        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5234    }
 5235
 5236    pub fn show_completions(
 5237        &mut self,
 5238        options: &ShowCompletions,
 5239        window: &mut Window,
 5240        cx: &mut Context<Self>,
 5241    ) {
 5242        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5243    }
 5244
 5245    fn open_or_update_completions_menu(
 5246        &mut self,
 5247        requested_source: Option<CompletionsMenuSource>,
 5248        trigger: Option<&str>,
 5249        window: &mut Window,
 5250        cx: &mut Context<Self>,
 5251    ) {
 5252        if self.pending_rename.is_some() {
 5253            return;
 5254        }
 5255
 5256        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5257
 5258        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5259        // inserted and selected. To handle that case, the start of the selection is used so that
 5260        // the menu starts with all choices.
 5261        let position = self
 5262            .selections
 5263            .newest_anchor()
 5264            .start
 5265            .bias_right(&multibuffer_snapshot);
 5266        if position.diff_base_anchor.is_some() {
 5267            return;
 5268        }
 5269        let (buffer, buffer_position) =
 5270            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5271                output
 5272            } else {
 5273                return;
 5274            };
 5275        let buffer_snapshot = buffer.read(cx).snapshot();
 5276
 5277        let query: Option<Arc<String>> =
 5278            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5279
 5280        drop(multibuffer_snapshot);
 5281
 5282        let provider = match requested_source {
 5283            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5284            Some(CompletionsMenuSource::Words) => None,
 5285            Some(CompletionsMenuSource::SnippetChoices) => {
 5286                log::error!("bug: SnippetChoices requested_source is not handled");
 5287                None
 5288            }
 5289        };
 5290
 5291        let sort_completions = provider
 5292            .as_ref()
 5293            .map_or(false, |provider| provider.sort_completions());
 5294
 5295        let filter_completions = provider
 5296            .as_ref()
 5297            .map_or(true, |provider| provider.filter_completions());
 5298
 5299        let trigger_kind = match trigger {
 5300            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5301                CompletionTriggerKind::TRIGGER_CHARACTER
 5302            }
 5303            _ => CompletionTriggerKind::INVOKED,
 5304        };
 5305        let completion_context = CompletionContext {
 5306            trigger_character: trigger.and_then(|trigger| {
 5307                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5308                    Some(String::from(trigger))
 5309                } else {
 5310                    None
 5311                }
 5312            }),
 5313            trigger_kind,
 5314        };
 5315
 5316        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5317        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5318        // involve trigger chars, so this is skipped in that case.
 5319        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5320        {
 5321            let menu_is_open = matches!(
 5322                self.context_menu.borrow().as_ref(),
 5323                Some(CodeContextMenu::Completions(_))
 5324            );
 5325            if menu_is_open {
 5326                self.hide_context_menu(window, cx);
 5327            }
 5328        }
 5329
 5330        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5331            if filter_completions {
 5332                menu.filter(query.clone(), provider.clone(), window, cx);
 5333            }
 5334            // When `is_incomplete` is false, no need to re-query completions when the current query
 5335            // is a suffix of the initial query.
 5336            if !menu.is_incomplete {
 5337                // If the new query is a suffix of the old query (typing more characters) and
 5338                // the previous result was complete, the existing completions can be filtered.
 5339                //
 5340                // Note that this is always true for snippet completions.
 5341                let query_matches = match (&menu.initial_query, &query) {
 5342                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5343                    (None, _) => true,
 5344                    _ => false,
 5345                };
 5346                if query_matches {
 5347                    let position_matches = if menu.initial_position == position {
 5348                        true
 5349                    } else {
 5350                        let snapshot = self.buffer.read(cx).read(cx);
 5351                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5352                    };
 5353                    if position_matches {
 5354                        return;
 5355                    }
 5356                }
 5357            }
 5358        };
 5359
 5360        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5361            buffer_snapshot.surrounding_word(buffer_position)
 5362        {
 5363            let word_to_exclude = buffer_snapshot
 5364                .text_for_range(word_range.clone())
 5365                .collect::<String>();
 5366            (
 5367                buffer_snapshot.anchor_before(word_range.start)
 5368                    ..buffer_snapshot.anchor_after(buffer_position),
 5369                Some(word_to_exclude),
 5370            )
 5371        } else {
 5372            (buffer_position..buffer_position, None)
 5373        };
 5374
 5375        let language = buffer_snapshot
 5376            .language_at(buffer_position)
 5377            .map(|language| language.name());
 5378
 5379        let completion_settings =
 5380            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5381
 5382        let show_completion_documentation = buffer_snapshot
 5383            .settings_at(buffer_position, cx)
 5384            .show_completion_documentation;
 5385
 5386        // The document can be large, so stay in reasonable bounds when searching for words,
 5387        // otherwise completion pop-up might be slow to appear.
 5388        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5389        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5390        let min_word_search = buffer_snapshot.clip_point(
 5391            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5392            Bias::Left,
 5393        );
 5394        let max_word_search = buffer_snapshot.clip_point(
 5395            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5396            Bias::Right,
 5397        );
 5398        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5399            ..buffer_snapshot.point_to_offset(max_word_search);
 5400
 5401        let skip_digits = query
 5402            .as_ref()
 5403            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5404
 5405        let (mut words, provider_responses) = match &provider {
 5406            Some(provider) => {
 5407                let provider_responses = provider.completions(
 5408                    position.excerpt_id,
 5409                    &buffer,
 5410                    buffer_position,
 5411                    completion_context,
 5412                    window,
 5413                    cx,
 5414                );
 5415
 5416                let words = match completion_settings.words {
 5417                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5418                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5419                        .background_spawn(async move {
 5420                            buffer_snapshot.words_in_range(WordsQuery {
 5421                                fuzzy_contents: None,
 5422                                range: word_search_range,
 5423                                skip_digits,
 5424                            })
 5425                        }),
 5426                };
 5427
 5428                (words, provider_responses)
 5429            }
 5430            None => (
 5431                cx.background_spawn(async move {
 5432                    buffer_snapshot.words_in_range(WordsQuery {
 5433                        fuzzy_contents: None,
 5434                        range: word_search_range,
 5435                        skip_digits,
 5436                    })
 5437                }),
 5438                Task::ready(Ok(Vec::new())),
 5439            ),
 5440        };
 5441
 5442        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5443
 5444        let id = post_inc(&mut self.next_completion_id);
 5445        let task = cx.spawn_in(window, async move |editor, cx| {
 5446            let Ok(()) = editor.update(cx, |this, _| {
 5447                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5448            }) else {
 5449                return;
 5450            };
 5451
 5452            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5453            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5454            let mut completions = Vec::new();
 5455            let mut is_incomplete = false;
 5456            if let Some(provider_responses) = provider_responses.await.log_err() {
 5457                if !provider_responses.is_empty() {
 5458                    for response in provider_responses {
 5459                        completions.extend(response.completions);
 5460                        is_incomplete = is_incomplete || response.is_incomplete;
 5461                    }
 5462                    if completion_settings.words == WordsCompletionMode::Fallback {
 5463                        words = Task::ready(BTreeMap::default());
 5464                    }
 5465                }
 5466            }
 5467
 5468            let mut words = words.await;
 5469            if let Some(word_to_exclude) = &word_to_exclude {
 5470                words.remove(word_to_exclude);
 5471            }
 5472            for lsp_completion in &completions {
 5473                words.remove(&lsp_completion.new_text);
 5474            }
 5475            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5476                replace_range: word_replace_range.clone(),
 5477                new_text: word.clone(),
 5478                label: CodeLabel::plain(word, None),
 5479                icon_path: None,
 5480                documentation: None,
 5481                source: CompletionSource::BufferWord {
 5482                    word_range,
 5483                    resolved: false,
 5484                },
 5485                insert_text_mode: Some(InsertTextMode::AS_IS),
 5486                confirm: None,
 5487            }));
 5488
 5489            let menu = if completions.is_empty() {
 5490                None
 5491            } else {
 5492                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5493                    let languages = editor
 5494                        .workspace
 5495                        .as_ref()
 5496                        .and_then(|(workspace, _)| workspace.upgrade())
 5497                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5498                    let menu = CompletionsMenu::new(
 5499                        id,
 5500                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5501                        sort_completions,
 5502                        show_completion_documentation,
 5503                        position,
 5504                        query.clone(),
 5505                        is_incomplete,
 5506                        buffer.clone(),
 5507                        completions.into(),
 5508                        snippet_sort_order,
 5509                        languages,
 5510                        language,
 5511                        cx,
 5512                    );
 5513
 5514                    let query = if filter_completions { query } else { None };
 5515                    let matches_task = if let Some(query) = query {
 5516                        menu.do_async_filtering(query, cx)
 5517                    } else {
 5518                        Task::ready(menu.unfiltered_matches())
 5519                    };
 5520                    (menu, matches_task)
 5521                }) else {
 5522                    return;
 5523                };
 5524
 5525                let matches = matches_task.await;
 5526
 5527                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5528                    // Newer menu already set, so exit.
 5529                    match editor.context_menu.borrow().as_ref() {
 5530                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5531                            if prev_menu.id > id {
 5532                                return;
 5533                            }
 5534                        }
 5535                        _ => {}
 5536                    };
 5537
 5538                    // Only valid to take prev_menu because it the new menu is immediately set
 5539                    // below, or the menu is hidden.
 5540                    match editor.context_menu.borrow_mut().take() {
 5541                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5542                            let position_matches =
 5543                                if prev_menu.initial_position == menu.initial_position {
 5544                                    true
 5545                                } else {
 5546                                    let snapshot = editor.buffer.read(cx).read(cx);
 5547                                    prev_menu.initial_position.to_offset(&snapshot)
 5548                                        == menu.initial_position.to_offset(&snapshot)
 5549                                };
 5550                            if position_matches {
 5551                                // Preserve markdown cache before `set_filter_results` because it will
 5552                                // try to populate the documentation cache.
 5553                                menu.preserve_markdown_cache(prev_menu);
 5554                            }
 5555                        }
 5556                        _ => {}
 5557                    };
 5558
 5559                    menu.set_filter_results(matches, provider, window, cx);
 5560                }) else {
 5561                    return;
 5562                };
 5563
 5564                menu.visible().then_some(menu)
 5565            };
 5566
 5567            editor
 5568                .update_in(cx, |editor, window, cx| {
 5569                    if editor.focus_handle.is_focused(window) {
 5570                        if let Some(menu) = menu {
 5571                            *editor.context_menu.borrow_mut() =
 5572                                Some(CodeContextMenu::Completions(menu));
 5573
 5574                            crate::hover_popover::hide_hover(editor, cx);
 5575                            if editor.show_edit_predictions_in_menu() {
 5576                                editor.update_visible_inline_completion(window, cx);
 5577                            } else {
 5578                                editor.discard_inline_completion(false, cx);
 5579                            }
 5580
 5581                            cx.notify();
 5582                            return;
 5583                        }
 5584                    }
 5585
 5586                    if editor.completion_tasks.len() <= 1 {
 5587                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5588                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5589                        // If it was already hidden and we don't show inline completions in the menu, we should
 5590                        // also show the inline-completion when available.
 5591                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5592                            editor.update_visible_inline_completion(window, cx);
 5593                        }
 5594                    }
 5595                })
 5596                .ok();
 5597        });
 5598
 5599        self.completion_tasks.push((id, task));
 5600    }
 5601
 5602    #[cfg(feature = "test-support")]
 5603    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5604        let menu = self.context_menu.borrow();
 5605        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5606            let completions = menu.completions.borrow();
 5607            Some(completions.to_vec())
 5608        } else {
 5609            None
 5610        }
 5611    }
 5612
 5613    pub fn with_completions_menu_matching_id<R>(
 5614        &self,
 5615        id: CompletionId,
 5616        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5617    ) -> R {
 5618        let mut context_menu = self.context_menu.borrow_mut();
 5619        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5620            return f(None);
 5621        };
 5622        if completions_menu.id != id {
 5623            return f(None);
 5624        }
 5625        f(Some(completions_menu))
 5626    }
 5627
 5628    pub fn confirm_completion(
 5629        &mut self,
 5630        action: &ConfirmCompletion,
 5631        window: &mut Window,
 5632        cx: &mut Context<Self>,
 5633    ) -> Option<Task<Result<()>>> {
 5634        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5635        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5636    }
 5637
 5638    pub fn confirm_completion_insert(
 5639        &mut self,
 5640        _: &ConfirmCompletionInsert,
 5641        window: &mut Window,
 5642        cx: &mut Context<Self>,
 5643    ) -> Option<Task<Result<()>>> {
 5644        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5645        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5646    }
 5647
 5648    pub fn confirm_completion_replace(
 5649        &mut self,
 5650        _: &ConfirmCompletionReplace,
 5651        window: &mut Window,
 5652        cx: &mut Context<Self>,
 5653    ) -> Option<Task<Result<()>>> {
 5654        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5655        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5656    }
 5657
 5658    pub fn compose_completion(
 5659        &mut self,
 5660        action: &ComposeCompletion,
 5661        window: &mut Window,
 5662        cx: &mut Context<Self>,
 5663    ) -> Option<Task<Result<()>>> {
 5664        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5665        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5666    }
 5667
 5668    fn do_completion(
 5669        &mut self,
 5670        item_ix: Option<usize>,
 5671        intent: CompletionIntent,
 5672        window: &mut Window,
 5673        cx: &mut Context<Editor>,
 5674    ) -> Option<Task<Result<()>>> {
 5675        use language::ToOffset as _;
 5676
 5677        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5678        else {
 5679            return None;
 5680        };
 5681
 5682        let candidate_id = {
 5683            let entries = completions_menu.entries.borrow();
 5684            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5685            if self.show_edit_predictions_in_menu() {
 5686                self.discard_inline_completion(true, cx);
 5687            }
 5688            mat.candidate_id
 5689        };
 5690
 5691        let completion = completions_menu
 5692            .completions
 5693            .borrow()
 5694            .get(candidate_id)?
 5695            .clone();
 5696        cx.stop_propagation();
 5697
 5698        let buffer_handle = completions_menu.buffer.clone();
 5699
 5700        let CompletionEdit {
 5701            new_text,
 5702            snippet,
 5703            replace_range,
 5704        } = process_completion_for_edit(
 5705            &completion,
 5706            intent,
 5707            &buffer_handle,
 5708            &completions_menu.initial_position.text_anchor,
 5709            cx,
 5710        );
 5711
 5712        let buffer = buffer_handle.read(cx);
 5713        let snapshot = self.buffer.read(cx).snapshot(cx);
 5714        let newest_anchor = self.selections.newest_anchor();
 5715        let replace_range_multibuffer = {
 5716            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5717            let multibuffer_anchor = snapshot
 5718                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5719                .unwrap()
 5720                ..snapshot
 5721                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5722                    .unwrap();
 5723            multibuffer_anchor.start.to_offset(&snapshot)
 5724                ..multibuffer_anchor.end.to_offset(&snapshot)
 5725        };
 5726        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5727            return None;
 5728        }
 5729
 5730        let old_text = buffer
 5731            .text_for_range(replace_range.clone())
 5732            .collect::<String>();
 5733        let lookbehind = newest_anchor
 5734            .start
 5735            .text_anchor
 5736            .to_offset(buffer)
 5737            .saturating_sub(replace_range.start);
 5738        let lookahead = replace_range
 5739            .end
 5740            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5741        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5742        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5743
 5744        let selections = self.selections.all::<usize>(cx);
 5745        let mut ranges = Vec::new();
 5746        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5747
 5748        for selection in &selections {
 5749            let range = if selection.id == newest_anchor.id {
 5750                replace_range_multibuffer.clone()
 5751            } else {
 5752                let mut range = selection.range();
 5753
 5754                // if prefix is present, don't duplicate it
 5755                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5756                    range.start = range.start.saturating_sub(lookbehind);
 5757
 5758                    // if suffix is also present, mimic the newest cursor and replace it
 5759                    if selection.id != newest_anchor.id
 5760                        && snapshot.contains_str_at(range.end, suffix)
 5761                    {
 5762                        range.end += lookahead;
 5763                    }
 5764                }
 5765                range
 5766            };
 5767
 5768            ranges.push(range.clone());
 5769
 5770            if !self.linked_edit_ranges.is_empty() {
 5771                let start_anchor = snapshot.anchor_before(range.start);
 5772                let end_anchor = snapshot.anchor_after(range.end);
 5773                if let Some(ranges) = self
 5774                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5775                {
 5776                    for (buffer, edits) in ranges {
 5777                        linked_edits
 5778                            .entry(buffer.clone())
 5779                            .or_default()
 5780                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5781                    }
 5782                }
 5783            }
 5784        }
 5785
 5786        let common_prefix_len = old_text
 5787            .chars()
 5788            .zip(new_text.chars())
 5789            .take_while(|(a, b)| a == b)
 5790            .map(|(a, _)| a.len_utf8())
 5791            .sum::<usize>();
 5792
 5793        cx.emit(EditorEvent::InputHandled {
 5794            utf16_range_to_replace: None,
 5795            text: new_text[common_prefix_len..].into(),
 5796        });
 5797
 5798        self.transact(window, cx, |this, window, cx| {
 5799            if let Some(mut snippet) = snippet {
 5800                snippet.text = new_text.to_string();
 5801                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5802            } else {
 5803                this.buffer.update(cx, |buffer, cx| {
 5804                    let auto_indent = match completion.insert_text_mode {
 5805                        Some(InsertTextMode::AS_IS) => None,
 5806                        _ => this.autoindent_mode.clone(),
 5807                    };
 5808                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5809                    buffer.edit(edits, auto_indent, cx);
 5810                });
 5811            }
 5812            for (buffer, edits) in linked_edits {
 5813                buffer.update(cx, |buffer, cx| {
 5814                    let snapshot = buffer.snapshot();
 5815                    let edits = edits
 5816                        .into_iter()
 5817                        .map(|(range, text)| {
 5818                            use text::ToPoint as TP;
 5819                            let end_point = TP::to_point(&range.end, &snapshot);
 5820                            let start_point = TP::to_point(&range.start, &snapshot);
 5821                            (start_point..end_point, text)
 5822                        })
 5823                        .sorted_by_key(|(range, _)| range.start);
 5824                    buffer.edit(edits, None, cx);
 5825                })
 5826            }
 5827
 5828            this.refresh_inline_completion(true, false, window, cx);
 5829        });
 5830
 5831        let show_new_completions_on_confirm = completion
 5832            .confirm
 5833            .as_ref()
 5834            .map_or(false, |confirm| confirm(intent, window, cx));
 5835        if show_new_completions_on_confirm {
 5836            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5837        }
 5838
 5839        let provider = self.completion_provider.as_ref()?;
 5840        drop(completion);
 5841        let apply_edits = provider.apply_additional_edits_for_completion(
 5842            buffer_handle,
 5843            completions_menu.completions.clone(),
 5844            candidate_id,
 5845            true,
 5846            cx,
 5847        );
 5848
 5849        let editor_settings = EditorSettings::get_global(cx);
 5850        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5851            // After the code completion is finished, users often want to know what signatures are needed.
 5852            // so we should automatically call signature_help
 5853            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5854        }
 5855
 5856        Some(cx.foreground_executor().spawn(async move {
 5857            apply_edits.await?;
 5858            Ok(())
 5859        }))
 5860    }
 5861
 5862    pub fn toggle_code_actions(
 5863        &mut self,
 5864        action: &ToggleCodeActions,
 5865        window: &mut Window,
 5866        cx: &mut Context<Self>,
 5867    ) {
 5868        let quick_launch = action.quick_launch;
 5869        let mut context_menu = self.context_menu.borrow_mut();
 5870        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5871            if code_actions.deployed_from == action.deployed_from {
 5872                // Toggle if we're selecting the same one
 5873                *context_menu = None;
 5874                cx.notify();
 5875                return;
 5876            } else {
 5877                // Otherwise, clear it and start a new one
 5878                *context_menu = None;
 5879                cx.notify();
 5880            }
 5881        }
 5882        drop(context_menu);
 5883        let snapshot = self.snapshot(window, cx);
 5884        let deployed_from = action.deployed_from.clone();
 5885        let action = action.clone();
 5886        self.completion_tasks.clear();
 5887        self.discard_inline_completion(false, cx);
 5888
 5889        let multibuffer_point = match &action.deployed_from {
 5890            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5891                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5892            }
 5893            _ => self.selections.newest::<Point>(cx).head(),
 5894        };
 5895        let Some((buffer, buffer_row)) = snapshot
 5896            .buffer_snapshot
 5897            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5898            .and_then(|(buffer_snapshot, range)| {
 5899                self.buffer()
 5900                    .read(cx)
 5901                    .buffer(buffer_snapshot.remote_id())
 5902                    .map(|buffer| (buffer, range.start.row))
 5903            })
 5904        else {
 5905            return;
 5906        };
 5907        let buffer_id = buffer.read(cx).remote_id();
 5908        let tasks = self
 5909            .tasks
 5910            .get(&(buffer_id, buffer_row))
 5911            .map(|t| Arc::new(t.to_owned()));
 5912
 5913        if !self.focus_handle.is_focused(window) {
 5914            return;
 5915        }
 5916        let project = self.project.clone();
 5917
 5918        let code_actions_task = match deployed_from {
 5919            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5920            _ => self.code_actions(buffer_row, window, cx),
 5921        };
 5922
 5923        let runnable_task = match deployed_from {
 5924            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5925            _ => {
 5926                let mut task_context_task = Task::ready(None);
 5927                if let Some(tasks) = &tasks {
 5928                    if let Some(project) = project {
 5929                        task_context_task =
 5930                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5931                    }
 5932                }
 5933
 5934                cx.spawn_in(window, {
 5935                    let buffer = buffer.clone();
 5936                    async move |editor, cx| {
 5937                        let task_context = task_context_task.await;
 5938
 5939                        let resolved_tasks =
 5940                            tasks
 5941                                .zip(task_context.clone())
 5942                                .map(|(tasks, task_context)| ResolvedTasks {
 5943                                    templates: tasks.resolve(&task_context).collect(),
 5944                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5945                                        multibuffer_point.row,
 5946                                        tasks.column,
 5947                                    )),
 5948                                });
 5949                        let debug_scenarios = editor
 5950                            .update(cx, |editor, cx| {
 5951                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5952                            })?
 5953                            .await;
 5954                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5955                    }
 5956                })
 5957            }
 5958        };
 5959
 5960        cx.spawn_in(window, async move |editor, cx| {
 5961            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5962            let code_actions = code_actions_task.await;
 5963            let spawn_straight_away = quick_launch
 5964                && resolved_tasks
 5965                    .as_ref()
 5966                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5967                && code_actions
 5968                    .as_ref()
 5969                    .map_or(true, |actions| actions.is_empty())
 5970                && debug_scenarios.is_empty();
 5971
 5972            editor.update_in(cx, |editor, window, cx| {
 5973                crate::hover_popover::hide_hover(editor, cx);
 5974                *editor.context_menu.borrow_mut() =
 5975                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5976                        buffer,
 5977                        actions: CodeActionContents::new(
 5978                            resolved_tasks,
 5979                            code_actions,
 5980                            debug_scenarios,
 5981                            task_context.unwrap_or_default(),
 5982                        ),
 5983                        selected_item: Default::default(),
 5984                        scroll_handle: UniformListScrollHandle::default(),
 5985                        deployed_from,
 5986                    }));
 5987                cx.notify();
 5988                if spawn_straight_away {
 5989                    if let Some(task) = editor.confirm_code_action(
 5990                        &ConfirmCodeAction { item_ix: Some(0) },
 5991                        window,
 5992                        cx,
 5993                    ) {
 5994                        return task;
 5995                    }
 5996                }
 5997
 5998                Task::ready(Ok(()))
 5999            })
 6000        })
 6001        .detach_and_log_err(cx);
 6002    }
 6003
 6004    fn debug_scenarios(
 6005        &mut self,
 6006        resolved_tasks: &Option<ResolvedTasks>,
 6007        buffer: &Entity<Buffer>,
 6008        cx: &mut App,
 6009    ) -> Task<Vec<task::DebugScenario>> {
 6010        maybe!({
 6011            let project = self.project.as_ref()?;
 6012            let dap_store = project.read(cx).dap_store();
 6013            let mut scenarios = vec![];
 6014            let resolved_tasks = resolved_tasks.as_ref()?;
 6015            let buffer = buffer.read(cx);
 6016            let language = buffer.language()?;
 6017            let file = buffer.file();
 6018            let debug_adapter = language_settings(language.name().into(), file, cx)
 6019                .debuggers
 6020                .first()
 6021                .map(SharedString::from)
 6022                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6023
 6024            dap_store.update(cx, |dap_store, cx| {
 6025                for (_, task) in &resolved_tasks.templates {
 6026                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6027                        task.original_task().clone(),
 6028                        debug_adapter.clone().into(),
 6029                        task.display_label().to_owned().into(),
 6030                        cx,
 6031                    );
 6032                    scenarios.push(maybe_scenario);
 6033                }
 6034            });
 6035            Some(cx.background_spawn(async move {
 6036                let scenarios = futures::future::join_all(scenarios)
 6037                    .await
 6038                    .into_iter()
 6039                    .flatten()
 6040                    .collect::<Vec<_>>();
 6041                scenarios
 6042            }))
 6043        })
 6044        .unwrap_or_else(|| Task::ready(vec![]))
 6045    }
 6046
 6047    fn code_actions(
 6048        &mut self,
 6049        buffer_row: u32,
 6050        window: &mut Window,
 6051        cx: &mut Context<Self>,
 6052    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6053        let mut task = self.code_actions_task.take();
 6054        cx.spawn_in(window, async move |editor, cx| {
 6055            while let Some(prev_task) = task {
 6056                prev_task.await.log_err();
 6057                task = editor
 6058                    .update(cx, |this, _| this.code_actions_task.take())
 6059                    .ok()?;
 6060            }
 6061
 6062            editor
 6063                .update(cx, |editor, cx| {
 6064                    editor
 6065                        .available_code_actions
 6066                        .clone()
 6067                        .and_then(|(location, code_actions)| {
 6068                            let snapshot = location.buffer.read(cx).snapshot();
 6069                            let point_range = location.range.to_point(&snapshot);
 6070                            let point_range = point_range.start.row..=point_range.end.row;
 6071                            if point_range.contains(&buffer_row) {
 6072                                Some(code_actions)
 6073                            } else {
 6074                                None
 6075                            }
 6076                        })
 6077                })
 6078                .ok()
 6079                .flatten()
 6080        })
 6081    }
 6082
 6083    pub fn confirm_code_action(
 6084        &mut self,
 6085        action: &ConfirmCodeAction,
 6086        window: &mut Window,
 6087        cx: &mut Context<Self>,
 6088    ) -> Option<Task<Result<()>>> {
 6089        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6090
 6091        let actions_menu =
 6092            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6093                menu
 6094            } else {
 6095                return None;
 6096            };
 6097
 6098        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6099        let action = actions_menu.actions.get(action_ix)?;
 6100        let title = action.label();
 6101        let buffer = actions_menu.buffer;
 6102        let workspace = self.workspace()?;
 6103
 6104        match action {
 6105            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6106                workspace.update(cx, |workspace, cx| {
 6107                    workspace.schedule_resolved_task(
 6108                        task_source_kind,
 6109                        resolved_task,
 6110                        false,
 6111                        window,
 6112                        cx,
 6113                    );
 6114
 6115                    Some(Task::ready(Ok(())))
 6116                })
 6117            }
 6118            CodeActionsItem::CodeAction {
 6119                excerpt_id,
 6120                action,
 6121                provider,
 6122            } => {
 6123                let apply_code_action =
 6124                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6125                let workspace = workspace.downgrade();
 6126                Some(cx.spawn_in(window, async move |editor, cx| {
 6127                    let project_transaction = apply_code_action.await?;
 6128                    Self::open_project_transaction(
 6129                        &editor,
 6130                        workspace,
 6131                        project_transaction,
 6132                        title,
 6133                        cx,
 6134                    )
 6135                    .await
 6136                }))
 6137            }
 6138            CodeActionsItem::DebugScenario(scenario) => {
 6139                let context = actions_menu.actions.context.clone();
 6140
 6141                workspace.update(cx, |workspace, cx| {
 6142                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6143                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6144                });
 6145                Some(Task::ready(Ok(())))
 6146            }
 6147        }
 6148    }
 6149
 6150    pub async fn open_project_transaction(
 6151        this: &WeakEntity<Editor>,
 6152        workspace: WeakEntity<Workspace>,
 6153        transaction: ProjectTransaction,
 6154        title: String,
 6155        cx: &mut AsyncWindowContext,
 6156    ) -> Result<()> {
 6157        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6158        cx.update(|_, cx| {
 6159            entries.sort_unstable_by_key(|(buffer, _)| {
 6160                buffer.read(cx).file().map(|f| f.path().clone())
 6161            });
 6162        })?;
 6163
 6164        // If the project transaction's edits are all contained within this editor, then
 6165        // avoid opening a new editor to display them.
 6166
 6167        if let Some((buffer, transaction)) = entries.first() {
 6168            if entries.len() == 1 {
 6169                let excerpt = this.update(cx, |editor, cx| {
 6170                    editor
 6171                        .buffer()
 6172                        .read(cx)
 6173                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6174                })?;
 6175                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6176                    if excerpted_buffer == *buffer {
 6177                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6178                            let excerpt_range = excerpt_range.to_offset(buffer);
 6179                            buffer
 6180                                .edited_ranges_for_transaction::<usize>(transaction)
 6181                                .all(|range| {
 6182                                    excerpt_range.start <= range.start
 6183                                        && excerpt_range.end >= range.end
 6184                                })
 6185                        })?;
 6186
 6187                        if all_edits_within_excerpt {
 6188                            return Ok(());
 6189                        }
 6190                    }
 6191                }
 6192            }
 6193        } else {
 6194            return Ok(());
 6195        }
 6196
 6197        let mut ranges_to_highlight = Vec::new();
 6198        let excerpt_buffer = cx.new(|cx| {
 6199            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6200            for (buffer_handle, transaction) in &entries {
 6201                let edited_ranges = buffer_handle
 6202                    .read(cx)
 6203                    .edited_ranges_for_transaction::<Point>(transaction)
 6204                    .collect::<Vec<_>>();
 6205                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6206                    PathKey::for_buffer(buffer_handle, cx),
 6207                    buffer_handle.clone(),
 6208                    edited_ranges,
 6209                    DEFAULT_MULTIBUFFER_CONTEXT,
 6210                    cx,
 6211                );
 6212
 6213                ranges_to_highlight.extend(ranges);
 6214            }
 6215            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6216            multibuffer
 6217        })?;
 6218
 6219        workspace.update_in(cx, |workspace, window, cx| {
 6220            let project = workspace.project().clone();
 6221            let editor =
 6222                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6223            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6224            editor.update(cx, |editor, cx| {
 6225                editor.highlight_background::<Self>(
 6226                    &ranges_to_highlight,
 6227                    |theme| theme.colors().editor_highlighted_line_background,
 6228                    cx,
 6229                );
 6230            });
 6231        })?;
 6232
 6233        Ok(())
 6234    }
 6235
 6236    pub fn clear_code_action_providers(&mut self) {
 6237        self.code_action_providers.clear();
 6238        self.available_code_actions.take();
 6239    }
 6240
 6241    pub fn add_code_action_provider(
 6242        &mut self,
 6243        provider: Rc<dyn CodeActionProvider>,
 6244        window: &mut Window,
 6245        cx: &mut Context<Self>,
 6246    ) {
 6247        if self
 6248            .code_action_providers
 6249            .iter()
 6250            .any(|existing_provider| existing_provider.id() == provider.id())
 6251        {
 6252            return;
 6253        }
 6254
 6255        self.code_action_providers.push(provider);
 6256        self.refresh_code_actions(window, cx);
 6257    }
 6258
 6259    pub fn remove_code_action_provider(
 6260        &mut self,
 6261        id: Arc<str>,
 6262        window: &mut Window,
 6263        cx: &mut Context<Self>,
 6264    ) {
 6265        self.code_action_providers
 6266            .retain(|provider| provider.id() != id);
 6267        self.refresh_code_actions(window, cx);
 6268    }
 6269
 6270    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6271        !self.code_action_providers.is_empty()
 6272            && EditorSettings::get_global(cx).toolbar.code_actions
 6273    }
 6274
 6275    pub fn has_available_code_actions(&self) -> bool {
 6276        self.available_code_actions
 6277            .as_ref()
 6278            .is_some_and(|(_, actions)| !actions.is_empty())
 6279    }
 6280
 6281    fn render_inline_code_actions(
 6282        &self,
 6283        icon_size: ui::IconSize,
 6284        display_row: DisplayRow,
 6285        is_active: bool,
 6286        cx: &mut Context<Self>,
 6287    ) -> AnyElement {
 6288        let show_tooltip = !self.context_menu_visible();
 6289        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6290            .icon_size(icon_size)
 6291            .shape(ui::IconButtonShape::Square)
 6292            .style(ButtonStyle::Transparent)
 6293            .icon_color(ui::Color::Hidden)
 6294            .toggle_state(is_active)
 6295            .when(show_tooltip, |this| {
 6296                this.tooltip({
 6297                    let focus_handle = self.focus_handle.clone();
 6298                    move |window, cx| {
 6299                        Tooltip::for_action_in(
 6300                            "Toggle Code Actions",
 6301                            &ToggleCodeActions {
 6302                                deployed_from: None,
 6303                                quick_launch: false,
 6304                            },
 6305                            &focus_handle,
 6306                            window,
 6307                            cx,
 6308                        )
 6309                    }
 6310                })
 6311            })
 6312            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6313                window.focus(&editor.focus_handle(cx));
 6314                editor.toggle_code_actions(
 6315                    &crate::actions::ToggleCodeActions {
 6316                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6317                            display_row,
 6318                        )),
 6319                        quick_launch: false,
 6320                    },
 6321                    window,
 6322                    cx,
 6323                );
 6324            }))
 6325            .into_any_element()
 6326    }
 6327
 6328    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6329        &self.context_menu
 6330    }
 6331
 6332    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6333        let newest_selection = self.selections.newest_anchor().clone();
 6334        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6335        let buffer = self.buffer.read(cx);
 6336        if newest_selection.head().diff_base_anchor.is_some() {
 6337            return None;
 6338        }
 6339        let (start_buffer, start) =
 6340            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6341        let (end_buffer, end) =
 6342            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6343        if start_buffer != end_buffer {
 6344            return None;
 6345        }
 6346
 6347        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6348            cx.background_executor()
 6349                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6350                .await;
 6351
 6352            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6353                let providers = this.code_action_providers.clone();
 6354                let tasks = this
 6355                    .code_action_providers
 6356                    .iter()
 6357                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6358                    .collect::<Vec<_>>();
 6359                (providers, tasks)
 6360            })?;
 6361
 6362            let mut actions = Vec::new();
 6363            for (provider, provider_actions) in
 6364                providers.into_iter().zip(future::join_all(tasks).await)
 6365            {
 6366                if let Some(provider_actions) = provider_actions.log_err() {
 6367                    actions.extend(provider_actions.into_iter().map(|action| {
 6368                        AvailableCodeAction {
 6369                            excerpt_id: newest_selection.start.excerpt_id,
 6370                            action,
 6371                            provider: provider.clone(),
 6372                        }
 6373                    }));
 6374                }
 6375            }
 6376
 6377            this.update(cx, |this, cx| {
 6378                this.available_code_actions = if actions.is_empty() {
 6379                    None
 6380                } else {
 6381                    Some((
 6382                        Location {
 6383                            buffer: start_buffer,
 6384                            range: start..end,
 6385                        },
 6386                        actions.into(),
 6387                    ))
 6388                };
 6389                cx.notify();
 6390            })
 6391        }));
 6392        None
 6393    }
 6394
 6395    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6396        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6397            self.show_git_blame_inline = false;
 6398
 6399            self.show_git_blame_inline_delay_task =
 6400                Some(cx.spawn_in(window, async move |this, cx| {
 6401                    cx.background_executor().timer(delay).await;
 6402
 6403                    this.update(cx, |this, cx| {
 6404                        this.show_git_blame_inline = true;
 6405                        cx.notify();
 6406                    })
 6407                    .log_err();
 6408                }));
 6409        }
 6410    }
 6411
 6412    fn show_blame_popover(
 6413        &mut self,
 6414        blame_entry: &BlameEntry,
 6415        position: gpui::Point<Pixels>,
 6416        cx: &mut Context<Self>,
 6417    ) {
 6418        if let Some(state) = &mut self.inline_blame_popover {
 6419            state.hide_task.take();
 6420        } else {
 6421            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6422            let blame_entry = blame_entry.clone();
 6423            let show_task = cx.spawn(async move |editor, cx| {
 6424                cx.background_executor()
 6425                    .timer(std::time::Duration::from_millis(delay))
 6426                    .await;
 6427                editor
 6428                    .update(cx, |editor, cx| {
 6429                        editor.inline_blame_popover_show_task.take();
 6430                        let Some(blame) = editor.blame.as_ref() else {
 6431                            return;
 6432                        };
 6433                        let blame = blame.read(cx);
 6434                        let details = blame.details_for_entry(&blame_entry);
 6435                        let markdown = cx.new(|cx| {
 6436                            Markdown::new(
 6437                                details
 6438                                    .as_ref()
 6439                                    .map(|message| message.message.clone())
 6440                                    .unwrap_or_default(),
 6441                                None,
 6442                                None,
 6443                                cx,
 6444                            )
 6445                        });
 6446                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6447                            position,
 6448                            hide_task: None,
 6449                            popover_bounds: None,
 6450                            popover_state: InlineBlamePopoverState {
 6451                                scroll_handle: ScrollHandle::new(),
 6452                                commit_message: details,
 6453                                markdown,
 6454                            },
 6455                        });
 6456                        cx.notify();
 6457                    })
 6458                    .ok();
 6459            });
 6460            self.inline_blame_popover_show_task = Some(show_task);
 6461        }
 6462    }
 6463
 6464    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6465        self.inline_blame_popover_show_task.take();
 6466        if let Some(state) = &mut self.inline_blame_popover {
 6467            let hide_task = cx.spawn(async move |editor, cx| {
 6468                cx.background_executor()
 6469                    .timer(std::time::Duration::from_millis(100))
 6470                    .await;
 6471                editor
 6472                    .update(cx, |editor, cx| {
 6473                        editor.inline_blame_popover.take();
 6474                        cx.notify();
 6475                    })
 6476                    .ok();
 6477            });
 6478            state.hide_task = Some(hide_task);
 6479        }
 6480    }
 6481
 6482    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6483        if self.pending_rename.is_some() {
 6484            return None;
 6485        }
 6486
 6487        let provider = self.semantics_provider.clone()?;
 6488        let buffer = self.buffer.read(cx);
 6489        let newest_selection = self.selections.newest_anchor().clone();
 6490        let cursor_position = newest_selection.head();
 6491        let (cursor_buffer, cursor_buffer_position) =
 6492            buffer.text_anchor_for_position(cursor_position, cx)?;
 6493        let (tail_buffer, tail_buffer_position) =
 6494            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6495        if cursor_buffer != tail_buffer {
 6496            return None;
 6497        }
 6498
 6499        let snapshot = cursor_buffer.read(cx).snapshot();
 6500        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6501        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6502        if start_word_range != end_word_range {
 6503            self.document_highlights_task.take();
 6504            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6505            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6506            return None;
 6507        }
 6508
 6509        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6510        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6511            cx.background_executor()
 6512                .timer(Duration::from_millis(debounce))
 6513                .await;
 6514
 6515            let highlights = if let Some(highlights) = cx
 6516                .update(|cx| {
 6517                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6518                })
 6519                .ok()
 6520                .flatten()
 6521            {
 6522                highlights.await.log_err()
 6523            } else {
 6524                None
 6525            };
 6526
 6527            if let Some(highlights) = highlights {
 6528                this.update(cx, |this, cx| {
 6529                    if this.pending_rename.is_some() {
 6530                        return;
 6531                    }
 6532
 6533                    let buffer_id = cursor_position.buffer_id;
 6534                    let buffer = this.buffer.read(cx);
 6535                    if !buffer
 6536                        .text_anchor_for_position(cursor_position, cx)
 6537                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6538                    {
 6539                        return;
 6540                    }
 6541
 6542                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6543                    let mut write_ranges = Vec::new();
 6544                    let mut read_ranges = Vec::new();
 6545                    for highlight in highlights {
 6546                        for (excerpt_id, excerpt_range) in
 6547                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6548                        {
 6549                            let start = highlight
 6550                                .range
 6551                                .start
 6552                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6553                            let end = highlight
 6554                                .range
 6555                                .end
 6556                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6557                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6558                                continue;
 6559                            }
 6560
 6561                            let range = Anchor {
 6562                                buffer_id,
 6563                                excerpt_id,
 6564                                text_anchor: start,
 6565                                diff_base_anchor: None,
 6566                            }..Anchor {
 6567                                buffer_id,
 6568                                excerpt_id,
 6569                                text_anchor: end,
 6570                                diff_base_anchor: None,
 6571                            };
 6572                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6573                                write_ranges.push(range);
 6574                            } else {
 6575                                read_ranges.push(range);
 6576                            }
 6577                        }
 6578                    }
 6579
 6580                    this.highlight_background::<DocumentHighlightRead>(
 6581                        &read_ranges,
 6582                        |theme| theme.colors().editor_document_highlight_read_background,
 6583                        cx,
 6584                    );
 6585                    this.highlight_background::<DocumentHighlightWrite>(
 6586                        &write_ranges,
 6587                        |theme| theme.colors().editor_document_highlight_write_background,
 6588                        cx,
 6589                    );
 6590                    cx.notify();
 6591                })
 6592                .log_err();
 6593            }
 6594        }));
 6595        None
 6596    }
 6597
 6598    fn prepare_highlight_query_from_selection(
 6599        &mut self,
 6600        cx: &mut Context<Editor>,
 6601    ) -> Option<(String, Range<Anchor>)> {
 6602        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6603            return None;
 6604        }
 6605        if !EditorSettings::get_global(cx).selection_highlight {
 6606            return None;
 6607        }
 6608        if self.selections.count() != 1 || self.selections.line_mode {
 6609            return None;
 6610        }
 6611        let selection = self.selections.newest::<Point>(cx);
 6612        if selection.is_empty() || selection.start.row != selection.end.row {
 6613            return None;
 6614        }
 6615        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6616        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6617        let query = multi_buffer_snapshot
 6618            .text_for_range(selection_anchor_range.clone())
 6619            .collect::<String>();
 6620        if query.trim().is_empty() {
 6621            return None;
 6622        }
 6623        Some((query, selection_anchor_range))
 6624    }
 6625
 6626    fn update_selection_occurrence_highlights(
 6627        &mut self,
 6628        query_text: String,
 6629        query_range: Range<Anchor>,
 6630        multi_buffer_range_to_query: Range<Point>,
 6631        use_debounce: bool,
 6632        window: &mut Window,
 6633        cx: &mut Context<Editor>,
 6634    ) -> Task<()> {
 6635        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6636        cx.spawn_in(window, async move |editor, cx| {
 6637            if use_debounce {
 6638                cx.background_executor()
 6639                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6640                    .await;
 6641            }
 6642            let match_task = cx.background_spawn(async move {
 6643                let buffer_ranges = multi_buffer_snapshot
 6644                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6645                    .into_iter()
 6646                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6647                let mut match_ranges = Vec::new();
 6648                let Ok(regex) = project::search::SearchQuery::text(
 6649                    query_text.clone(),
 6650                    false,
 6651                    false,
 6652                    false,
 6653                    Default::default(),
 6654                    Default::default(),
 6655                    false,
 6656                    None,
 6657                ) else {
 6658                    return Vec::default();
 6659                };
 6660                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6661                    match_ranges.extend(
 6662                        regex
 6663                            .search(&buffer_snapshot, Some(search_range.clone()))
 6664                            .await
 6665                            .into_iter()
 6666                            .filter_map(|match_range| {
 6667                                let match_start = buffer_snapshot
 6668                                    .anchor_after(search_range.start + match_range.start);
 6669                                let match_end = buffer_snapshot
 6670                                    .anchor_before(search_range.start + match_range.end);
 6671                                let match_anchor_range = Anchor::range_in_buffer(
 6672                                    excerpt_id,
 6673                                    buffer_snapshot.remote_id(),
 6674                                    match_start..match_end,
 6675                                );
 6676                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6677                            }),
 6678                    );
 6679                }
 6680                match_ranges
 6681            });
 6682            let match_ranges = match_task.await;
 6683            editor
 6684                .update_in(cx, |editor, _, cx| {
 6685                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6686                    if !match_ranges.is_empty() {
 6687                        editor.highlight_background::<SelectedTextHighlight>(
 6688                            &match_ranges,
 6689                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6690                            cx,
 6691                        )
 6692                    }
 6693                })
 6694                .log_err();
 6695        })
 6696    }
 6697
 6698    fn refresh_selected_text_highlights(
 6699        &mut self,
 6700        on_buffer_edit: bool,
 6701        window: &mut Window,
 6702        cx: &mut Context<Editor>,
 6703    ) {
 6704        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6705        else {
 6706            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6707            self.quick_selection_highlight_task.take();
 6708            self.debounced_selection_highlight_task.take();
 6709            return;
 6710        };
 6711        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6712        if on_buffer_edit
 6713            || self
 6714                .quick_selection_highlight_task
 6715                .as_ref()
 6716                .map_or(true, |(prev_anchor_range, _)| {
 6717                    prev_anchor_range != &query_range
 6718                })
 6719        {
 6720            let multi_buffer_visible_start = self
 6721                .scroll_manager
 6722                .anchor()
 6723                .anchor
 6724                .to_point(&multi_buffer_snapshot);
 6725            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6726                multi_buffer_visible_start
 6727                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6728                Bias::Left,
 6729            );
 6730            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6731            self.quick_selection_highlight_task = Some((
 6732                query_range.clone(),
 6733                self.update_selection_occurrence_highlights(
 6734                    query_text.clone(),
 6735                    query_range.clone(),
 6736                    multi_buffer_visible_range,
 6737                    false,
 6738                    window,
 6739                    cx,
 6740                ),
 6741            ));
 6742        }
 6743        if on_buffer_edit
 6744            || self
 6745                .debounced_selection_highlight_task
 6746                .as_ref()
 6747                .map_or(true, |(prev_anchor_range, _)| {
 6748                    prev_anchor_range != &query_range
 6749                })
 6750        {
 6751            let multi_buffer_start = multi_buffer_snapshot
 6752                .anchor_before(0)
 6753                .to_point(&multi_buffer_snapshot);
 6754            let multi_buffer_end = multi_buffer_snapshot
 6755                .anchor_after(multi_buffer_snapshot.len())
 6756                .to_point(&multi_buffer_snapshot);
 6757            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6758            self.debounced_selection_highlight_task = Some((
 6759                query_range.clone(),
 6760                self.update_selection_occurrence_highlights(
 6761                    query_text,
 6762                    query_range,
 6763                    multi_buffer_full_range,
 6764                    true,
 6765                    window,
 6766                    cx,
 6767                ),
 6768            ));
 6769        }
 6770    }
 6771
 6772    pub fn refresh_inline_completion(
 6773        &mut self,
 6774        debounce: bool,
 6775        user_requested: bool,
 6776        window: &mut Window,
 6777        cx: &mut Context<Self>,
 6778    ) -> Option<()> {
 6779        let provider = self.edit_prediction_provider()?;
 6780        let cursor = self.selections.newest_anchor().head();
 6781        let (buffer, cursor_buffer_position) =
 6782            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6783
 6784        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6785            self.discard_inline_completion(false, cx);
 6786            return None;
 6787        }
 6788
 6789        if !user_requested
 6790            && (!self.should_show_edit_predictions()
 6791                || !self.is_focused(window)
 6792                || buffer.read(cx).is_empty())
 6793        {
 6794            self.discard_inline_completion(false, cx);
 6795            return None;
 6796        }
 6797
 6798        self.update_visible_inline_completion(window, cx);
 6799        provider.refresh(
 6800            self.project.clone(),
 6801            buffer,
 6802            cursor_buffer_position,
 6803            debounce,
 6804            cx,
 6805        );
 6806        Some(())
 6807    }
 6808
 6809    fn show_edit_predictions_in_menu(&self) -> bool {
 6810        match self.edit_prediction_settings {
 6811            EditPredictionSettings::Disabled => false,
 6812            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6813        }
 6814    }
 6815
 6816    pub fn edit_predictions_enabled(&self) -> bool {
 6817        match self.edit_prediction_settings {
 6818            EditPredictionSettings::Disabled => false,
 6819            EditPredictionSettings::Enabled { .. } => true,
 6820        }
 6821    }
 6822
 6823    fn edit_prediction_requires_modifier(&self) -> bool {
 6824        match self.edit_prediction_settings {
 6825            EditPredictionSettings::Disabled => false,
 6826            EditPredictionSettings::Enabled {
 6827                preview_requires_modifier,
 6828                ..
 6829            } => preview_requires_modifier,
 6830        }
 6831    }
 6832
 6833    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6834        if self.edit_prediction_provider.is_none() {
 6835            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6836        } else {
 6837            let selection = self.selections.newest_anchor();
 6838            let cursor = selection.head();
 6839
 6840            if let Some((buffer, cursor_buffer_position)) =
 6841                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6842            {
 6843                self.edit_prediction_settings =
 6844                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6845            }
 6846        }
 6847    }
 6848
 6849    fn edit_prediction_settings_at_position(
 6850        &self,
 6851        buffer: &Entity<Buffer>,
 6852        buffer_position: language::Anchor,
 6853        cx: &App,
 6854    ) -> EditPredictionSettings {
 6855        if !self.mode.is_full()
 6856            || !self.show_inline_completions_override.unwrap_or(true)
 6857            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6858        {
 6859            return EditPredictionSettings::Disabled;
 6860        }
 6861
 6862        let buffer = buffer.read(cx);
 6863
 6864        let file = buffer.file();
 6865
 6866        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6867            return EditPredictionSettings::Disabled;
 6868        };
 6869
 6870        let by_provider = matches!(
 6871            self.menu_inline_completions_policy,
 6872            MenuInlineCompletionsPolicy::ByProvider
 6873        );
 6874
 6875        let show_in_menu = by_provider
 6876            && self
 6877                .edit_prediction_provider
 6878                .as_ref()
 6879                .map_or(false, |provider| {
 6880                    provider.provider.show_completions_in_menu()
 6881                });
 6882
 6883        let preview_requires_modifier =
 6884            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6885
 6886        EditPredictionSettings::Enabled {
 6887            show_in_menu,
 6888            preview_requires_modifier,
 6889        }
 6890    }
 6891
 6892    fn should_show_edit_predictions(&self) -> bool {
 6893        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6894    }
 6895
 6896    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6897        matches!(
 6898            self.edit_prediction_preview,
 6899            EditPredictionPreview::Active { .. }
 6900        )
 6901    }
 6902
 6903    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6904        let cursor = self.selections.newest_anchor().head();
 6905        if let Some((buffer, cursor_position)) =
 6906            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6907        {
 6908            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6909        } else {
 6910            false
 6911        }
 6912    }
 6913
 6914    pub fn supports_minimap(&self, cx: &App) -> bool {
 6915        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6916    }
 6917
 6918    fn edit_predictions_enabled_in_buffer(
 6919        &self,
 6920        buffer: &Entity<Buffer>,
 6921        buffer_position: language::Anchor,
 6922        cx: &App,
 6923    ) -> bool {
 6924        maybe!({
 6925            if self.read_only(cx) {
 6926                return Some(false);
 6927            }
 6928            let provider = self.edit_prediction_provider()?;
 6929            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6930                return Some(false);
 6931            }
 6932            let buffer = buffer.read(cx);
 6933            let Some(file) = buffer.file() else {
 6934                return Some(true);
 6935            };
 6936            let settings = all_language_settings(Some(file), cx);
 6937            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6938        })
 6939        .unwrap_or(false)
 6940    }
 6941
 6942    fn cycle_inline_completion(
 6943        &mut self,
 6944        direction: Direction,
 6945        window: &mut Window,
 6946        cx: &mut Context<Self>,
 6947    ) -> Option<()> {
 6948        let provider = self.edit_prediction_provider()?;
 6949        let cursor = self.selections.newest_anchor().head();
 6950        let (buffer, cursor_buffer_position) =
 6951            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6952        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6953            return None;
 6954        }
 6955
 6956        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6957        self.update_visible_inline_completion(window, cx);
 6958
 6959        Some(())
 6960    }
 6961
 6962    pub fn show_inline_completion(
 6963        &mut self,
 6964        _: &ShowEditPrediction,
 6965        window: &mut Window,
 6966        cx: &mut Context<Self>,
 6967    ) {
 6968        if !self.has_active_inline_completion() {
 6969            self.refresh_inline_completion(false, true, window, cx);
 6970            return;
 6971        }
 6972
 6973        self.update_visible_inline_completion(window, cx);
 6974    }
 6975
 6976    pub fn display_cursor_names(
 6977        &mut self,
 6978        _: &DisplayCursorNames,
 6979        window: &mut Window,
 6980        cx: &mut Context<Self>,
 6981    ) {
 6982        self.show_cursor_names(window, cx);
 6983    }
 6984
 6985    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6986        self.show_cursor_names = true;
 6987        cx.notify();
 6988        cx.spawn_in(window, async move |this, cx| {
 6989            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6990            this.update(cx, |this, cx| {
 6991                this.show_cursor_names = false;
 6992                cx.notify()
 6993            })
 6994            .ok()
 6995        })
 6996        .detach();
 6997    }
 6998
 6999    pub fn next_edit_prediction(
 7000        &mut self,
 7001        _: &NextEditPrediction,
 7002        window: &mut Window,
 7003        cx: &mut Context<Self>,
 7004    ) {
 7005        if self.has_active_inline_completion() {
 7006            self.cycle_inline_completion(Direction::Next, window, cx);
 7007        } else {
 7008            let is_copilot_disabled = self
 7009                .refresh_inline_completion(false, true, window, cx)
 7010                .is_none();
 7011            if is_copilot_disabled {
 7012                cx.propagate();
 7013            }
 7014        }
 7015    }
 7016
 7017    pub fn previous_edit_prediction(
 7018        &mut self,
 7019        _: &PreviousEditPrediction,
 7020        window: &mut Window,
 7021        cx: &mut Context<Self>,
 7022    ) {
 7023        if self.has_active_inline_completion() {
 7024            self.cycle_inline_completion(Direction::Prev, window, cx);
 7025        } else {
 7026            let is_copilot_disabled = self
 7027                .refresh_inline_completion(false, true, window, cx)
 7028                .is_none();
 7029            if is_copilot_disabled {
 7030                cx.propagate();
 7031            }
 7032        }
 7033    }
 7034
 7035    pub fn accept_edit_prediction(
 7036        &mut self,
 7037        _: &AcceptEditPrediction,
 7038        window: &mut Window,
 7039        cx: &mut Context<Self>,
 7040    ) {
 7041        if self.show_edit_predictions_in_menu() {
 7042            self.hide_context_menu(window, cx);
 7043        }
 7044
 7045        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7046            return;
 7047        };
 7048
 7049        self.report_inline_completion_event(
 7050            active_inline_completion.completion_id.clone(),
 7051            true,
 7052            cx,
 7053        );
 7054
 7055        match &active_inline_completion.completion {
 7056            InlineCompletion::Move { target, .. } => {
 7057                let target = *target;
 7058
 7059                if let Some(position_map) = &self.last_position_map {
 7060                    if position_map
 7061                        .visible_row_range
 7062                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7063                        || !self.edit_prediction_requires_modifier()
 7064                    {
 7065                        self.unfold_ranges(&[target..target], true, false, cx);
 7066                        // Note that this is also done in vim's handler of the Tab action.
 7067                        self.change_selections(
 7068                            Some(Autoscroll::newest()),
 7069                            window,
 7070                            cx,
 7071                            |selections| {
 7072                                selections.select_anchor_ranges([target..target]);
 7073                            },
 7074                        );
 7075                        self.clear_row_highlights::<EditPredictionPreview>();
 7076
 7077                        self.edit_prediction_preview
 7078                            .set_previous_scroll_position(None);
 7079                    } else {
 7080                        self.edit_prediction_preview
 7081                            .set_previous_scroll_position(Some(
 7082                                position_map.snapshot.scroll_anchor,
 7083                            ));
 7084
 7085                        self.highlight_rows::<EditPredictionPreview>(
 7086                            target..target,
 7087                            cx.theme().colors().editor_highlighted_line_background,
 7088                            RowHighlightOptions {
 7089                                autoscroll: true,
 7090                                ..Default::default()
 7091                            },
 7092                            cx,
 7093                        );
 7094                        self.request_autoscroll(Autoscroll::fit(), cx);
 7095                    }
 7096                }
 7097            }
 7098            InlineCompletion::Edit { edits, .. } => {
 7099                if let Some(provider) = self.edit_prediction_provider() {
 7100                    provider.accept(cx);
 7101                }
 7102
 7103                // Store the transaction ID and selections before applying the edit
 7104                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7105
 7106                let snapshot = self.buffer.read(cx).snapshot(cx);
 7107                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7108
 7109                self.buffer.update(cx, |buffer, cx| {
 7110                    buffer.edit(edits.iter().cloned(), None, cx)
 7111                });
 7112
 7113                self.change_selections(None, window, cx, |s| {
 7114                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7115                });
 7116
 7117                let selections = self.selections.disjoint_anchors();
 7118                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7119                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7120                    if has_new_transaction {
 7121                        self.selection_history
 7122                            .insert_transaction(transaction_id_now, selections);
 7123                    }
 7124                }
 7125
 7126                self.update_visible_inline_completion(window, cx);
 7127                if self.active_inline_completion.is_none() {
 7128                    self.refresh_inline_completion(true, true, window, cx);
 7129                }
 7130
 7131                cx.notify();
 7132            }
 7133        }
 7134
 7135        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7136    }
 7137
 7138    pub fn accept_partial_inline_completion(
 7139        &mut self,
 7140        _: &AcceptPartialEditPrediction,
 7141        window: &mut Window,
 7142        cx: &mut Context<Self>,
 7143    ) {
 7144        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7145            return;
 7146        };
 7147        if self.selections.count() != 1 {
 7148            return;
 7149        }
 7150
 7151        self.report_inline_completion_event(
 7152            active_inline_completion.completion_id.clone(),
 7153            true,
 7154            cx,
 7155        );
 7156
 7157        match &active_inline_completion.completion {
 7158            InlineCompletion::Move { target, .. } => {
 7159                let target = *target;
 7160                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7161                    selections.select_anchor_ranges([target..target]);
 7162                });
 7163            }
 7164            InlineCompletion::Edit { edits, .. } => {
 7165                // Find an insertion that starts at the cursor position.
 7166                let snapshot = self.buffer.read(cx).snapshot(cx);
 7167                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7168                let insertion = edits.iter().find_map(|(range, text)| {
 7169                    let range = range.to_offset(&snapshot);
 7170                    if range.is_empty() && range.start == cursor_offset {
 7171                        Some(text)
 7172                    } else {
 7173                        None
 7174                    }
 7175                });
 7176
 7177                if let Some(text) = insertion {
 7178                    let mut partial_completion = text
 7179                        .chars()
 7180                        .by_ref()
 7181                        .take_while(|c| c.is_alphabetic())
 7182                        .collect::<String>();
 7183                    if partial_completion.is_empty() {
 7184                        partial_completion = text
 7185                            .chars()
 7186                            .by_ref()
 7187                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7188                            .collect::<String>();
 7189                    }
 7190
 7191                    cx.emit(EditorEvent::InputHandled {
 7192                        utf16_range_to_replace: None,
 7193                        text: partial_completion.clone().into(),
 7194                    });
 7195
 7196                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7197
 7198                    self.refresh_inline_completion(true, true, window, cx);
 7199                    cx.notify();
 7200                } else {
 7201                    self.accept_edit_prediction(&Default::default(), window, cx);
 7202                }
 7203            }
 7204        }
 7205    }
 7206
 7207    fn discard_inline_completion(
 7208        &mut self,
 7209        should_report_inline_completion_event: bool,
 7210        cx: &mut Context<Self>,
 7211    ) -> bool {
 7212        if should_report_inline_completion_event {
 7213            let completion_id = self
 7214                .active_inline_completion
 7215                .as_ref()
 7216                .and_then(|active_completion| active_completion.completion_id.clone());
 7217
 7218            self.report_inline_completion_event(completion_id, false, cx);
 7219        }
 7220
 7221        if let Some(provider) = self.edit_prediction_provider() {
 7222            provider.discard(cx);
 7223        }
 7224
 7225        self.take_active_inline_completion(cx)
 7226    }
 7227
 7228    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7229        let Some(provider) = self.edit_prediction_provider() else {
 7230            return;
 7231        };
 7232
 7233        let Some((_, buffer, _)) = self
 7234            .buffer
 7235            .read(cx)
 7236            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7237        else {
 7238            return;
 7239        };
 7240
 7241        let extension = buffer
 7242            .read(cx)
 7243            .file()
 7244            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7245
 7246        let event_type = match accepted {
 7247            true => "Edit Prediction Accepted",
 7248            false => "Edit Prediction Discarded",
 7249        };
 7250        telemetry::event!(
 7251            event_type,
 7252            provider = provider.name(),
 7253            prediction_id = id,
 7254            suggestion_accepted = accepted,
 7255            file_extension = extension,
 7256        );
 7257    }
 7258
 7259    pub fn has_active_inline_completion(&self) -> bool {
 7260        self.active_inline_completion.is_some()
 7261    }
 7262
 7263    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7264        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7265            return false;
 7266        };
 7267
 7268        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7269        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7270        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7271        true
 7272    }
 7273
 7274    /// Returns true when we're displaying the edit prediction popover below the cursor
 7275    /// like we are not previewing and the LSP autocomplete menu is visible
 7276    /// or we are in `when_holding_modifier` mode.
 7277    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7278        if self.edit_prediction_preview_is_active()
 7279            || !self.show_edit_predictions_in_menu()
 7280            || !self.edit_predictions_enabled()
 7281        {
 7282            return false;
 7283        }
 7284
 7285        if self.has_visible_completions_menu() {
 7286            return true;
 7287        }
 7288
 7289        has_completion && self.edit_prediction_requires_modifier()
 7290    }
 7291
 7292    fn handle_modifiers_changed(
 7293        &mut self,
 7294        modifiers: Modifiers,
 7295        position_map: &PositionMap,
 7296        window: &mut Window,
 7297        cx: &mut Context<Self>,
 7298    ) {
 7299        if self.show_edit_predictions_in_menu() {
 7300            self.update_edit_prediction_preview(&modifiers, window, cx);
 7301        }
 7302
 7303        self.update_selection_mode(&modifiers, position_map, window, cx);
 7304
 7305        let mouse_position = window.mouse_position();
 7306        if !position_map.text_hitbox.is_hovered(window) {
 7307            return;
 7308        }
 7309
 7310        self.update_hovered_link(
 7311            position_map.point_for_position(mouse_position),
 7312            &position_map.snapshot,
 7313            modifiers,
 7314            window,
 7315            cx,
 7316        )
 7317    }
 7318
 7319    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7320        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7321        if invert {
 7322            match multi_cursor_setting {
 7323                MultiCursorModifier::Alt => modifiers.alt,
 7324                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7325            }
 7326        } else {
 7327            match multi_cursor_setting {
 7328                MultiCursorModifier::Alt => modifiers.secondary(),
 7329                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7330            }
 7331        }
 7332    }
 7333
 7334    fn columnar_selection_mode(
 7335        modifiers: &Modifiers,
 7336        cx: &mut Context<Self>,
 7337    ) -> Option<ColumnarMode> {
 7338        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7339            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7340                Some(ColumnarMode::FromMouse)
 7341            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7342                Some(ColumnarMode::FromSelection)
 7343            } else {
 7344                None
 7345            }
 7346        } else {
 7347            None
 7348        }
 7349    }
 7350
 7351    fn update_selection_mode(
 7352        &mut self,
 7353        modifiers: &Modifiers,
 7354        position_map: &PositionMap,
 7355        window: &mut Window,
 7356        cx: &mut Context<Self>,
 7357    ) {
 7358        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7359            return;
 7360        };
 7361        if self.selections.pending.is_none() {
 7362            return;
 7363        }
 7364
 7365        let mouse_position = window.mouse_position();
 7366        let point_for_position = position_map.point_for_position(mouse_position);
 7367        let position = point_for_position.previous_valid;
 7368
 7369        self.select(
 7370            SelectPhase::BeginColumnar {
 7371                position,
 7372                reset: false,
 7373                mode,
 7374                goal_column: point_for_position.exact_unclipped.column(),
 7375            },
 7376            window,
 7377            cx,
 7378        );
 7379    }
 7380
 7381    fn update_edit_prediction_preview(
 7382        &mut self,
 7383        modifiers: &Modifiers,
 7384        window: &mut Window,
 7385        cx: &mut Context<Self>,
 7386    ) {
 7387        let mut modifiers_held = false;
 7388        if let Some(accept_keystroke) = self
 7389            .accept_edit_prediction_keybind(false, window, cx)
 7390            .keystroke()
 7391        {
 7392            modifiers_held = modifiers_held
 7393                || (&accept_keystroke.modifiers == modifiers
 7394                    && accept_keystroke.modifiers.modified());
 7395        };
 7396        if let Some(accept_partial_keystroke) = self
 7397            .accept_edit_prediction_keybind(true, window, cx)
 7398            .keystroke()
 7399        {
 7400            modifiers_held = modifiers_held
 7401                || (&accept_partial_keystroke.modifiers == modifiers
 7402                    && accept_partial_keystroke.modifiers.modified());
 7403        }
 7404
 7405        if modifiers_held {
 7406            if matches!(
 7407                self.edit_prediction_preview,
 7408                EditPredictionPreview::Inactive { .. }
 7409            ) {
 7410                self.edit_prediction_preview = EditPredictionPreview::Active {
 7411                    previous_scroll_position: None,
 7412                    since: Instant::now(),
 7413                };
 7414
 7415                self.update_visible_inline_completion(window, cx);
 7416                cx.notify();
 7417            }
 7418        } else if let EditPredictionPreview::Active {
 7419            previous_scroll_position,
 7420            since,
 7421        } = self.edit_prediction_preview
 7422        {
 7423            if let (Some(previous_scroll_position), Some(position_map)) =
 7424                (previous_scroll_position, self.last_position_map.as_ref())
 7425            {
 7426                self.set_scroll_position(
 7427                    previous_scroll_position
 7428                        .scroll_position(&position_map.snapshot.display_snapshot),
 7429                    window,
 7430                    cx,
 7431                );
 7432            }
 7433
 7434            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7435                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7436            };
 7437            self.clear_row_highlights::<EditPredictionPreview>();
 7438            self.update_visible_inline_completion(window, cx);
 7439            cx.notify();
 7440        }
 7441    }
 7442
 7443    fn update_visible_inline_completion(
 7444        &mut self,
 7445        _window: &mut Window,
 7446        cx: &mut Context<Self>,
 7447    ) -> Option<()> {
 7448        let selection = self.selections.newest_anchor();
 7449        let cursor = selection.head();
 7450        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7451        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7452        let excerpt_id = cursor.excerpt_id;
 7453
 7454        let show_in_menu = self.show_edit_predictions_in_menu();
 7455        let completions_menu_has_precedence = !show_in_menu
 7456            && (self.context_menu.borrow().is_some()
 7457                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7458
 7459        if completions_menu_has_precedence
 7460            || !offset_selection.is_empty()
 7461            || self
 7462                .active_inline_completion
 7463                .as_ref()
 7464                .map_or(false, |completion| {
 7465                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7466                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7467                    !invalidation_range.contains(&offset_selection.head())
 7468                })
 7469        {
 7470            self.discard_inline_completion(false, cx);
 7471            return None;
 7472        }
 7473
 7474        self.take_active_inline_completion(cx);
 7475        let Some(provider) = self.edit_prediction_provider() else {
 7476            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7477            return None;
 7478        };
 7479
 7480        let (buffer, cursor_buffer_position) =
 7481            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7482
 7483        self.edit_prediction_settings =
 7484            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7485
 7486        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7487
 7488        if self.edit_prediction_indent_conflict {
 7489            let cursor_point = cursor.to_point(&multibuffer);
 7490
 7491            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7492
 7493            if let Some((_, indent)) = indents.iter().next() {
 7494                if indent.len == cursor_point.column {
 7495                    self.edit_prediction_indent_conflict = false;
 7496                }
 7497            }
 7498        }
 7499
 7500        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7501        let edits = inline_completion
 7502            .edits
 7503            .into_iter()
 7504            .flat_map(|(range, new_text)| {
 7505                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7506                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7507                Some((start..end, new_text))
 7508            })
 7509            .collect::<Vec<_>>();
 7510        if edits.is_empty() {
 7511            return None;
 7512        }
 7513
 7514        let first_edit_start = edits.first().unwrap().0.start;
 7515        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7516        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7517
 7518        let last_edit_end = edits.last().unwrap().0.end;
 7519        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7520        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7521
 7522        let cursor_row = cursor.to_point(&multibuffer).row;
 7523
 7524        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7525
 7526        let mut inlay_ids = Vec::new();
 7527        let invalidation_row_range;
 7528        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7529            Some(cursor_row..edit_end_row)
 7530        } else if cursor_row > edit_end_row {
 7531            Some(edit_start_row..cursor_row)
 7532        } else {
 7533            None
 7534        };
 7535        let is_move =
 7536            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7537        let completion = if is_move {
 7538            invalidation_row_range =
 7539                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7540            let target = first_edit_start;
 7541            InlineCompletion::Move { target, snapshot }
 7542        } else {
 7543            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7544                && !self.inline_completions_hidden_for_vim_mode;
 7545
 7546            if show_completions_in_buffer {
 7547                if edits
 7548                    .iter()
 7549                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7550                {
 7551                    let mut inlays = Vec::new();
 7552                    for (range, new_text) in &edits {
 7553                        let inlay = Inlay::inline_completion(
 7554                            post_inc(&mut self.next_inlay_id),
 7555                            range.start,
 7556                            new_text.as_str(),
 7557                        );
 7558                        inlay_ids.push(inlay.id);
 7559                        inlays.push(inlay);
 7560                    }
 7561
 7562                    self.splice_inlays(&[], inlays, cx);
 7563                } else {
 7564                    let background_color = cx.theme().status().deleted_background;
 7565                    self.highlight_text::<InlineCompletionHighlight>(
 7566                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7567                        HighlightStyle {
 7568                            background_color: Some(background_color),
 7569                            ..Default::default()
 7570                        },
 7571                        cx,
 7572                    );
 7573                }
 7574            }
 7575
 7576            invalidation_row_range = edit_start_row..edit_end_row;
 7577
 7578            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7579                if provider.show_tab_accept_marker() {
 7580                    EditDisplayMode::TabAccept
 7581                } else {
 7582                    EditDisplayMode::Inline
 7583                }
 7584            } else {
 7585                EditDisplayMode::DiffPopover
 7586            };
 7587
 7588            InlineCompletion::Edit {
 7589                edits,
 7590                edit_preview: inline_completion.edit_preview,
 7591                display_mode,
 7592                snapshot,
 7593            }
 7594        };
 7595
 7596        let invalidation_range = multibuffer
 7597            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7598            ..multibuffer.anchor_after(Point::new(
 7599                invalidation_row_range.end,
 7600                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7601            ));
 7602
 7603        self.stale_inline_completion_in_menu = None;
 7604        self.active_inline_completion = Some(InlineCompletionState {
 7605            inlay_ids,
 7606            completion,
 7607            completion_id: inline_completion.id,
 7608            invalidation_range,
 7609        });
 7610
 7611        cx.notify();
 7612
 7613        Some(())
 7614    }
 7615
 7616    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7617        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7618    }
 7619
 7620    fn clear_tasks(&mut self) {
 7621        self.tasks.clear()
 7622    }
 7623
 7624    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7625        if self.tasks.insert(key, value).is_some() {
 7626            // This case should hopefully be rare, but just in case...
 7627            log::error!(
 7628                "multiple different run targets found on a single line, only the last target will be rendered"
 7629            )
 7630        }
 7631    }
 7632
 7633    /// Get all display points of breakpoints that will be rendered within editor
 7634    ///
 7635    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7636    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7637    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7638    fn active_breakpoints(
 7639        &self,
 7640        range: Range<DisplayRow>,
 7641        window: &mut Window,
 7642        cx: &mut Context<Self>,
 7643    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7644        let mut breakpoint_display_points = HashMap::default();
 7645
 7646        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7647            return breakpoint_display_points;
 7648        };
 7649
 7650        let snapshot = self.snapshot(window, cx);
 7651
 7652        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7653        let Some(project) = self.project.as_ref() else {
 7654            return breakpoint_display_points;
 7655        };
 7656
 7657        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7658            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7659
 7660        for (buffer_snapshot, range, excerpt_id) in
 7661            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7662        {
 7663            let Some(buffer) = project
 7664                .read(cx)
 7665                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7666            else {
 7667                continue;
 7668            };
 7669            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7670                &buffer,
 7671                Some(
 7672                    buffer_snapshot.anchor_before(range.start)
 7673                        ..buffer_snapshot.anchor_after(range.end),
 7674                ),
 7675                buffer_snapshot,
 7676                cx,
 7677            );
 7678            for (breakpoint, state) in breakpoints {
 7679                let multi_buffer_anchor =
 7680                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7681                let position = multi_buffer_anchor
 7682                    .to_point(&multi_buffer_snapshot)
 7683                    .to_display_point(&snapshot);
 7684
 7685                breakpoint_display_points.insert(
 7686                    position.row(),
 7687                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7688                );
 7689            }
 7690        }
 7691
 7692        breakpoint_display_points
 7693    }
 7694
 7695    fn breakpoint_context_menu(
 7696        &self,
 7697        anchor: Anchor,
 7698        window: &mut Window,
 7699        cx: &mut Context<Self>,
 7700    ) -> Entity<ui::ContextMenu> {
 7701        let weak_editor = cx.weak_entity();
 7702        let focus_handle = self.focus_handle(cx);
 7703
 7704        let row = self
 7705            .buffer
 7706            .read(cx)
 7707            .snapshot(cx)
 7708            .summary_for_anchor::<Point>(&anchor)
 7709            .row;
 7710
 7711        let breakpoint = self
 7712            .breakpoint_at_row(row, window, cx)
 7713            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7714
 7715        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7716            "Edit Log Breakpoint"
 7717        } else {
 7718            "Set Log Breakpoint"
 7719        };
 7720
 7721        let condition_breakpoint_msg = if breakpoint
 7722            .as_ref()
 7723            .is_some_and(|bp| bp.1.condition.is_some())
 7724        {
 7725            "Edit Condition Breakpoint"
 7726        } else {
 7727            "Set Condition Breakpoint"
 7728        };
 7729
 7730        let hit_condition_breakpoint_msg = if breakpoint
 7731            .as_ref()
 7732            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7733        {
 7734            "Edit Hit Condition Breakpoint"
 7735        } else {
 7736            "Set Hit Condition Breakpoint"
 7737        };
 7738
 7739        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7740            "Unset Breakpoint"
 7741        } else {
 7742            "Set Breakpoint"
 7743        };
 7744
 7745        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7746
 7747        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7748            BreakpointState::Enabled => Some("Disable"),
 7749            BreakpointState::Disabled => Some("Enable"),
 7750        });
 7751
 7752        let (anchor, breakpoint) =
 7753            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7754
 7755        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7756            menu.on_blur_subscription(Subscription::new(|| {}))
 7757                .context(focus_handle)
 7758                .when(run_to_cursor, |this| {
 7759                    let weak_editor = weak_editor.clone();
 7760                    this.entry("Run to cursor", None, move |window, cx| {
 7761                        weak_editor
 7762                            .update(cx, |editor, cx| {
 7763                                editor.change_selections(None, window, cx, |s| {
 7764                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7765                                });
 7766                            })
 7767                            .ok();
 7768
 7769                        window.dispatch_action(Box::new(RunToCursor), cx);
 7770                    })
 7771                    .separator()
 7772                })
 7773                .when_some(toggle_state_msg, |this, msg| {
 7774                    this.entry(msg, None, {
 7775                        let weak_editor = weak_editor.clone();
 7776                        let breakpoint = breakpoint.clone();
 7777                        move |_window, cx| {
 7778                            weak_editor
 7779                                .update(cx, |this, cx| {
 7780                                    this.edit_breakpoint_at_anchor(
 7781                                        anchor,
 7782                                        breakpoint.as_ref().clone(),
 7783                                        BreakpointEditAction::InvertState,
 7784                                        cx,
 7785                                    );
 7786                                })
 7787                                .log_err();
 7788                        }
 7789                    })
 7790                })
 7791                .entry(set_breakpoint_msg, None, {
 7792                    let weak_editor = weak_editor.clone();
 7793                    let breakpoint = breakpoint.clone();
 7794                    move |_window, cx| {
 7795                        weak_editor
 7796                            .update(cx, |this, cx| {
 7797                                this.edit_breakpoint_at_anchor(
 7798                                    anchor,
 7799                                    breakpoint.as_ref().clone(),
 7800                                    BreakpointEditAction::Toggle,
 7801                                    cx,
 7802                                );
 7803                            })
 7804                            .log_err();
 7805                    }
 7806                })
 7807                .entry(log_breakpoint_msg, None, {
 7808                    let breakpoint = breakpoint.clone();
 7809                    let weak_editor = weak_editor.clone();
 7810                    move |window, cx| {
 7811                        weak_editor
 7812                            .update(cx, |this, cx| {
 7813                                this.add_edit_breakpoint_block(
 7814                                    anchor,
 7815                                    breakpoint.as_ref(),
 7816                                    BreakpointPromptEditAction::Log,
 7817                                    window,
 7818                                    cx,
 7819                                );
 7820                            })
 7821                            .log_err();
 7822                    }
 7823                })
 7824                .entry(condition_breakpoint_msg, None, {
 7825                    let breakpoint = breakpoint.clone();
 7826                    let weak_editor = weak_editor.clone();
 7827                    move |window, cx| {
 7828                        weak_editor
 7829                            .update(cx, |this, cx| {
 7830                                this.add_edit_breakpoint_block(
 7831                                    anchor,
 7832                                    breakpoint.as_ref(),
 7833                                    BreakpointPromptEditAction::Condition,
 7834                                    window,
 7835                                    cx,
 7836                                );
 7837                            })
 7838                            .log_err();
 7839                    }
 7840                })
 7841                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7842                    weak_editor
 7843                        .update(cx, |this, cx| {
 7844                            this.add_edit_breakpoint_block(
 7845                                anchor,
 7846                                breakpoint.as_ref(),
 7847                                BreakpointPromptEditAction::HitCondition,
 7848                                window,
 7849                                cx,
 7850                            );
 7851                        })
 7852                        .log_err();
 7853                })
 7854        })
 7855    }
 7856
 7857    fn render_breakpoint(
 7858        &self,
 7859        position: Anchor,
 7860        row: DisplayRow,
 7861        breakpoint: &Breakpoint,
 7862        state: Option<BreakpointSessionState>,
 7863        cx: &mut Context<Self>,
 7864    ) -> IconButton {
 7865        let is_rejected = state.is_some_and(|s| !s.verified);
 7866        // Is it a breakpoint that shows up when hovering over gutter?
 7867        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7868            (false, false),
 7869            |PhantomBreakpointIndicator {
 7870                 is_active,
 7871                 display_row,
 7872                 collides_with_existing_breakpoint,
 7873             }| {
 7874                (
 7875                    is_active && display_row == row,
 7876                    collides_with_existing_breakpoint,
 7877                )
 7878            },
 7879        );
 7880
 7881        let (color, icon) = {
 7882            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7883                (false, false) => ui::IconName::DebugBreakpoint,
 7884                (true, false) => ui::IconName::DebugLogBreakpoint,
 7885                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7886                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7887            };
 7888
 7889            let color = if is_phantom {
 7890                Color::Hint
 7891            } else if is_rejected {
 7892                Color::Disabled
 7893            } else {
 7894                Color::Debugger
 7895            };
 7896
 7897            (color, icon)
 7898        };
 7899
 7900        let breakpoint = Arc::from(breakpoint.clone());
 7901
 7902        let alt_as_text = gpui::Keystroke {
 7903            modifiers: Modifiers::secondary_key(),
 7904            ..Default::default()
 7905        };
 7906        let primary_action_text = if breakpoint.is_disabled() {
 7907            "Enable breakpoint"
 7908        } else if is_phantom && !collides_with_existing {
 7909            "Set breakpoint"
 7910        } else {
 7911            "Unset breakpoint"
 7912        };
 7913        let focus_handle = self.focus_handle.clone();
 7914
 7915        let meta = if is_rejected {
 7916            SharedString::from("No executable code is associated with this line.")
 7917        } else if collides_with_existing && !breakpoint.is_disabled() {
 7918            SharedString::from(format!(
 7919                "{alt_as_text}-click to disable,\nright-click for more options."
 7920            ))
 7921        } else {
 7922            SharedString::from("Right-click for more options.")
 7923        };
 7924        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7925            .icon_size(IconSize::XSmall)
 7926            .size(ui::ButtonSize::None)
 7927            .when(is_rejected, |this| {
 7928                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7929            })
 7930            .icon_color(color)
 7931            .style(ButtonStyle::Transparent)
 7932            .on_click(cx.listener({
 7933                let breakpoint = breakpoint.clone();
 7934
 7935                move |editor, event: &ClickEvent, window, cx| {
 7936                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7937                        BreakpointEditAction::InvertState
 7938                    } else {
 7939                        BreakpointEditAction::Toggle
 7940                    };
 7941
 7942                    window.focus(&editor.focus_handle(cx));
 7943                    editor.edit_breakpoint_at_anchor(
 7944                        position,
 7945                        breakpoint.as_ref().clone(),
 7946                        edit_action,
 7947                        cx,
 7948                    );
 7949                }
 7950            }))
 7951            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7952                editor.set_breakpoint_context_menu(
 7953                    row,
 7954                    Some(position),
 7955                    event.down.position,
 7956                    window,
 7957                    cx,
 7958                );
 7959            }))
 7960            .tooltip(move |window, cx| {
 7961                Tooltip::with_meta_in(
 7962                    primary_action_text,
 7963                    Some(&ToggleBreakpoint),
 7964                    meta.clone(),
 7965                    &focus_handle,
 7966                    window,
 7967                    cx,
 7968                )
 7969            })
 7970    }
 7971
 7972    fn build_tasks_context(
 7973        project: &Entity<Project>,
 7974        buffer: &Entity<Buffer>,
 7975        buffer_row: u32,
 7976        tasks: &Arc<RunnableTasks>,
 7977        cx: &mut Context<Self>,
 7978    ) -> Task<Option<task::TaskContext>> {
 7979        let position = Point::new(buffer_row, tasks.column);
 7980        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7981        let location = Location {
 7982            buffer: buffer.clone(),
 7983            range: range_start..range_start,
 7984        };
 7985        // Fill in the environmental variables from the tree-sitter captures
 7986        let mut captured_task_variables = TaskVariables::default();
 7987        for (capture_name, value) in tasks.extra_variables.clone() {
 7988            captured_task_variables.insert(
 7989                task::VariableName::Custom(capture_name.into()),
 7990                value.clone(),
 7991            );
 7992        }
 7993        project.update(cx, |project, cx| {
 7994            project.task_store().update(cx, |task_store, cx| {
 7995                task_store.task_context_for_location(captured_task_variables, location, cx)
 7996            })
 7997        })
 7998    }
 7999
 8000    pub fn spawn_nearest_task(
 8001        &mut self,
 8002        action: &SpawnNearestTask,
 8003        window: &mut Window,
 8004        cx: &mut Context<Self>,
 8005    ) {
 8006        let Some((workspace, _)) = self.workspace.clone() else {
 8007            return;
 8008        };
 8009        let Some(project) = self.project.clone() else {
 8010            return;
 8011        };
 8012
 8013        // Try to find a closest, enclosing node using tree-sitter that has a
 8014        // task
 8015        let Some((buffer, buffer_row, tasks)) = self
 8016            .find_enclosing_node_task(cx)
 8017            // Or find the task that's closest in row-distance.
 8018            .or_else(|| self.find_closest_task(cx))
 8019        else {
 8020            return;
 8021        };
 8022
 8023        let reveal_strategy = action.reveal;
 8024        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8025        cx.spawn_in(window, async move |_, cx| {
 8026            let context = task_context.await?;
 8027            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8028
 8029            let resolved = &mut resolved_task.resolved;
 8030            resolved.reveal = reveal_strategy;
 8031
 8032            workspace
 8033                .update_in(cx, |workspace, window, cx| {
 8034                    workspace.schedule_resolved_task(
 8035                        task_source_kind,
 8036                        resolved_task,
 8037                        false,
 8038                        window,
 8039                        cx,
 8040                    );
 8041                })
 8042                .ok()
 8043        })
 8044        .detach();
 8045    }
 8046
 8047    fn find_closest_task(
 8048        &mut self,
 8049        cx: &mut Context<Self>,
 8050    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8051        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8052
 8053        let ((buffer_id, row), tasks) = self
 8054            .tasks
 8055            .iter()
 8056            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8057
 8058        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8059        let tasks = Arc::new(tasks.to_owned());
 8060        Some((buffer, *row, tasks))
 8061    }
 8062
 8063    fn find_enclosing_node_task(
 8064        &mut self,
 8065        cx: &mut Context<Self>,
 8066    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8067        let snapshot = self.buffer.read(cx).snapshot(cx);
 8068        let offset = self.selections.newest::<usize>(cx).head();
 8069        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8070        let buffer_id = excerpt.buffer().remote_id();
 8071
 8072        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8073        let mut cursor = layer.node().walk();
 8074
 8075        while cursor.goto_first_child_for_byte(offset).is_some() {
 8076            if cursor.node().end_byte() == offset {
 8077                cursor.goto_next_sibling();
 8078            }
 8079        }
 8080
 8081        // Ascend to the smallest ancestor that contains the range and has a task.
 8082        loop {
 8083            let node = cursor.node();
 8084            let node_range = node.byte_range();
 8085            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8086
 8087            // Check if this node contains our offset
 8088            if node_range.start <= offset && node_range.end >= offset {
 8089                // If it contains offset, check for task
 8090                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8091                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8092                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8093                }
 8094            }
 8095
 8096            if !cursor.goto_parent() {
 8097                break;
 8098            }
 8099        }
 8100        None
 8101    }
 8102
 8103    fn render_run_indicator(
 8104        &self,
 8105        _style: &EditorStyle,
 8106        is_active: bool,
 8107        row: DisplayRow,
 8108        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8109        cx: &mut Context<Self>,
 8110    ) -> IconButton {
 8111        let color = Color::Muted;
 8112        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8113
 8114        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8115            .shape(ui::IconButtonShape::Square)
 8116            .icon_size(IconSize::XSmall)
 8117            .icon_color(color)
 8118            .toggle_state(is_active)
 8119            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8120                let quick_launch = e.down.button == MouseButton::Left;
 8121                window.focus(&editor.focus_handle(cx));
 8122                editor.toggle_code_actions(
 8123                    &ToggleCodeActions {
 8124                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8125                        quick_launch,
 8126                    },
 8127                    window,
 8128                    cx,
 8129                );
 8130            }))
 8131            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8132                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8133            }))
 8134    }
 8135
 8136    pub fn context_menu_visible(&self) -> bool {
 8137        !self.edit_prediction_preview_is_active()
 8138            && self
 8139                .context_menu
 8140                .borrow()
 8141                .as_ref()
 8142                .map_or(false, |menu| menu.visible())
 8143    }
 8144
 8145    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8146        self.context_menu
 8147            .borrow()
 8148            .as_ref()
 8149            .map(|menu| menu.origin())
 8150    }
 8151
 8152    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8153        self.context_menu_options = Some(options);
 8154    }
 8155
 8156    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8157    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8158
 8159    fn render_edit_prediction_popover(
 8160        &mut self,
 8161        text_bounds: &Bounds<Pixels>,
 8162        content_origin: gpui::Point<Pixels>,
 8163        right_margin: Pixels,
 8164        editor_snapshot: &EditorSnapshot,
 8165        visible_row_range: Range<DisplayRow>,
 8166        scroll_top: f32,
 8167        scroll_bottom: f32,
 8168        line_layouts: &[LineWithInvisibles],
 8169        line_height: Pixels,
 8170        scroll_pixel_position: gpui::Point<Pixels>,
 8171        newest_selection_head: Option<DisplayPoint>,
 8172        editor_width: Pixels,
 8173        style: &EditorStyle,
 8174        window: &mut Window,
 8175        cx: &mut App,
 8176    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8177        if self.mode().is_minimap() {
 8178            return None;
 8179        }
 8180        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8181
 8182        if self.edit_prediction_visible_in_cursor_popover(true) {
 8183            return None;
 8184        }
 8185
 8186        match &active_inline_completion.completion {
 8187            InlineCompletion::Move { target, .. } => {
 8188                let target_display_point = target.to_display_point(editor_snapshot);
 8189
 8190                if self.edit_prediction_requires_modifier() {
 8191                    if !self.edit_prediction_preview_is_active() {
 8192                        return None;
 8193                    }
 8194
 8195                    self.render_edit_prediction_modifier_jump_popover(
 8196                        text_bounds,
 8197                        content_origin,
 8198                        visible_row_range,
 8199                        line_layouts,
 8200                        line_height,
 8201                        scroll_pixel_position,
 8202                        newest_selection_head,
 8203                        target_display_point,
 8204                        window,
 8205                        cx,
 8206                    )
 8207                } else {
 8208                    self.render_edit_prediction_eager_jump_popover(
 8209                        text_bounds,
 8210                        content_origin,
 8211                        editor_snapshot,
 8212                        visible_row_range,
 8213                        scroll_top,
 8214                        scroll_bottom,
 8215                        line_height,
 8216                        scroll_pixel_position,
 8217                        target_display_point,
 8218                        editor_width,
 8219                        window,
 8220                        cx,
 8221                    )
 8222                }
 8223            }
 8224            InlineCompletion::Edit {
 8225                display_mode: EditDisplayMode::Inline,
 8226                ..
 8227            } => None,
 8228            InlineCompletion::Edit {
 8229                display_mode: EditDisplayMode::TabAccept,
 8230                edits,
 8231                ..
 8232            } => {
 8233                let range = &edits.first()?.0;
 8234                let target_display_point = range.end.to_display_point(editor_snapshot);
 8235
 8236                self.render_edit_prediction_end_of_line_popover(
 8237                    "Accept",
 8238                    editor_snapshot,
 8239                    visible_row_range,
 8240                    target_display_point,
 8241                    line_height,
 8242                    scroll_pixel_position,
 8243                    content_origin,
 8244                    editor_width,
 8245                    window,
 8246                    cx,
 8247                )
 8248            }
 8249            InlineCompletion::Edit {
 8250                edits,
 8251                edit_preview,
 8252                display_mode: EditDisplayMode::DiffPopover,
 8253                snapshot,
 8254            } => self.render_edit_prediction_diff_popover(
 8255                text_bounds,
 8256                content_origin,
 8257                right_margin,
 8258                editor_snapshot,
 8259                visible_row_range,
 8260                line_layouts,
 8261                line_height,
 8262                scroll_pixel_position,
 8263                newest_selection_head,
 8264                editor_width,
 8265                style,
 8266                edits,
 8267                edit_preview,
 8268                snapshot,
 8269                window,
 8270                cx,
 8271            ),
 8272        }
 8273    }
 8274
 8275    fn render_edit_prediction_modifier_jump_popover(
 8276        &mut self,
 8277        text_bounds: &Bounds<Pixels>,
 8278        content_origin: gpui::Point<Pixels>,
 8279        visible_row_range: Range<DisplayRow>,
 8280        line_layouts: &[LineWithInvisibles],
 8281        line_height: Pixels,
 8282        scroll_pixel_position: gpui::Point<Pixels>,
 8283        newest_selection_head: Option<DisplayPoint>,
 8284        target_display_point: DisplayPoint,
 8285        window: &mut Window,
 8286        cx: &mut App,
 8287    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8288        let scrolled_content_origin =
 8289            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8290
 8291        const SCROLL_PADDING_Y: Pixels = px(12.);
 8292
 8293        if target_display_point.row() < visible_row_range.start {
 8294            return self.render_edit_prediction_scroll_popover(
 8295                |_| SCROLL_PADDING_Y,
 8296                IconName::ArrowUp,
 8297                visible_row_range,
 8298                line_layouts,
 8299                newest_selection_head,
 8300                scrolled_content_origin,
 8301                window,
 8302                cx,
 8303            );
 8304        } else if target_display_point.row() >= visible_row_range.end {
 8305            return self.render_edit_prediction_scroll_popover(
 8306                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8307                IconName::ArrowDown,
 8308                visible_row_range,
 8309                line_layouts,
 8310                newest_selection_head,
 8311                scrolled_content_origin,
 8312                window,
 8313                cx,
 8314            );
 8315        }
 8316
 8317        const POLE_WIDTH: Pixels = px(2.);
 8318
 8319        let line_layout =
 8320            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8321        let target_column = target_display_point.column() as usize;
 8322
 8323        let target_x = line_layout.x_for_index(target_column);
 8324        let target_y =
 8325            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8326
 8327        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8328
 8329        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8330        border_color.l += 0.001;
 8331
 8332        let mut element = v_flex()
 8333            .items_end()
 8334            .when(flag_on_right, |el| el.items_start())
 8335            .child(if flag_on_right {
 8336                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8337                    .rounded_bl(px(0.))
 8338                    .rounded_tl(px(0.))
 8339                    .border_l_2()
 8340                    .border_color(border_color)
 8341            } else {
 8342                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8343                    .rounded_br(px(0.))
 8344                    .rounded_tr(px(0.))
 8345                    .border_r_2()
 8346                    .border_color(border_color)
 8347            })
 8348            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8349            .into_any();
 8350
 8351        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8352
 8353        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8354            - point(
 8355                if flag_on_right {
 8356                    POLE_WIDTH
 8357                } else {
 8358                    size.width - POLE_WIDTH
 8359                },
 8360                size.height - line_height,
 8361            );
 8362
 8363        origin.x = origin.x.max(content_origin.x);
 8364
 8365        element.prepaint_at(origin, window, cx);
 8366
 8367        Some((element, origin))
 8368    }
 8369
 8370    fn render_edit_prediction_scroll_popover(
 8371        &mut self,
 8372        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8373        scroll_icon: IconName,
 8374        visible_row_range: Range<DisplayRow>,
 8375        line_layouts: &[LineWithInvisibles],
 8376        newest_selection_head: Option<DisplayPoint>,
 8377        scrolled_content_origin: gpui::Point<Pixels>,
 8378        window: &mut Window,
 8379        cx: &mut App,
 8380    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8381        let mut element = self
 8382            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8383            .into_any();
 8384
 8385        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8386
 8387        let cursor = newest_selection_head?;
 8388        let cursor_row_layout =
 8389            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8390        let cursor_column = cursor.column() as usize;
 8391
 8392        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8393
 8394        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8395
 8396        element.prepaint_at(origin, window, cx);
 8397        Some((element, origin))
 8398    }
 8399
 8400    fn render_edit_prediction_eager_jump_popover(
 8401        &mut self,
 8402        text_bounds: &Bounds<Pixels>,
 8403        content_origin: gpui::Point<Pixels>,
 8404        editor_snapshot: &EditorSnapshot,
 8405        visible_row_range: Range<DisplayRow>,
 8406        scroll_top: f32,
 8407        scroll_bottom: f32,
 8408        line_height: Pixels,
 8409        scroll_pixel_position: gpui::Point<Pixels>,
 8410        target_display_point: DisplayPoint,
 8411        editor_width: Pixels,
 8412        window: &mut Window,
 8413        cx: &mut App,
 8414    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8415        if target_display_point.row().as_f32() < scroll_top {
 8416            let mut element = self
 8417                .render_edit_prediction_line_popover(
 8418                    "Jump to Edit",
 8419                    Some(IconName::ArrowUp),
 8420                    window,
 8421                    cx,
 8422                )?
 8423                .into_any();
 8424
 8425            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8426            let offset = point(
 8427                (text_bounds.size.width - size.width) / 2.,
 8428                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8429            );
 8430
 8431            let origin = text_bounds.origin + offset;
 8432            element.prepaint_at(origin, window, cx);
 8433            Some((element, origin))
 8434        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8435            let mut element = self
 8436                .render_edit_prediction_line_popover(
 8437                    "Jump to Edit",
 8438                    Some(IconName::ArrowDown),
 8439                    window,
 8440                    cx,
 8441                )?
 8442                .into_any();
 8443
 8444            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8445            let offset = point(
 8446                (text_bounds.size.width - size.width) / 2.,
 8447                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8448            );
 8449
 8450            let origin = text_bounds.origin + offset;
 8451            element.prepaint_at(origin, window, cx);
 8452            Some((element, origin))
 8453        } else {
 8454            self.render_edit_prediction_end_of_line_popover(
 8455                "Jump to Edit",
 8456                editor_snapshot,
 8457                visible_row_range,
 8458                target_display_point,
 8459                line_height,
 8460                scroll_pixel_position,
 8461                content_origin,
 8462                editor_width,
 8463                window,
 8464                cx,
 8465            )
 8466        }
 8467    }
 8468
 8469    fn render_edit_prediction_end_of_line_popover(
 8470        self: &mut Editor,
 8471        label: &'static str,
 8472        editor_snapshot: &EditorSnapshot,
 8473        visible_row_range: Range<DisplayRow>,
 8474        target_display_point: DisplayPoint,
 8475        line_height: Pixels,
 8476        scroll_pixel_position: gpui::Point<Pixels>,
 8477        content_origin: gpui::Point<Pixels>,
 8478        editor_width: Pixels,
 8479        window: &mut Window,
 8480        cx: &mut App,
 8481    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8482        let target_line_end = DisplayPoint::new(
 8483            target_display_point.row(),
 8484            editor_snapshot.line_len(target_display_point.row()),
 8485        );
 8486
 8487        let mut element = self
 8488            .render_edit_prediction_line_popover(label, None, window, cx)?
 8489            .into_any();
 8490
 8491        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8492
 8493        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8494
 8495        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8496        let mut origin = start_point
 8497            + line_origin
 8498            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8499        origin.x = origin.x.max(content_origin.x);
 8500
 8501        let max_x = content_origin.x + editor_width - size.width;
 8502
 8503        if origin.x > max_x {
 8504            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8505
 8506            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8507                origin.y += offset;
 8508                IconName::ArrowUp
 8509            } else {
 8510                origin.y -= offset;
 8511                IconName::ArrowDown
 8512            };
 8513
 8514            element = self
 8515                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8516                .into_any();
 8517
 8518            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8519
 8520            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8521        }
 8522
 8523        element.prepaint_at(origin, window, cx);
 8524        Some((element, origin))
 8525    }
 8526
 8527    fn render_edit_prediction_diff_popover(
 8528        self: &Editor,
 8529        text_bounds: &Bounds<Pixels>,
 8530        content_origin: gpui::Point<Pixels>,
 8531        right_margin: Pixels,
 8532        editor_snapshot: &EditorSnapshot,
 8533        visible_row_range: Range<DisplayRow>,
 8534        line_layouts: &[LineWithInvisibles],
 8535        line_height: Pixels,
 8536        scroll_pixel_position: gpui::Point<Pixels>,
 8537        newest_selection_head: Option<DisplayPoint>,
 8538        editor_width: Pixels,
 8539        style: &EditorStyle,
 8540        edits: &Vec<(Range<Anchor>, String)>,
 8541        edit_preview: &Option<language::EditPreview>,
 8542        snapshot: &language::BufferSnapshot,
 8543        window: &mut Window,
 8544        cx: &mut App,
 8545    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8546        let edit_start = edits
 8547            .first()
 8548            .unwrap()
 8549            .0
 8550            .start
 8551            .to_display_point(editor_snapshot);
 8552        let edit_end = edits
 8553            .last()
 8554            .unwrap()
 8555            .0
 8556            .end
 8557            .to_display_point(editor_snapshot);
 8558
 8559        let is_visible = visible_row_range.contains(&edit_start.row())
 8560            || visible_row_range.contains(&edit_end.row());
 8561        if !is_visible {
 8562            return None;
 8563        }
 8564
 8565        let highlighted_edits =
 8566            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8567
 8568        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8569        let line_count = highlighted_edits.text.lines().count();
 8570
 8571        const BORDER_WIDTH: Pixels = px(1.);
 8572
 8573        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8574        let has_keybind = keybind.is_some();
 8575
 8576        let mut element = h_flex()
 8577            .items_start()
 8578            .child(
 8579                h_flex()
 8580                    .bg(cx.theme().colors().editor_background)
 8581                    .border(BORDER_WIDTH)
 8582                    .shadow_sm()
 8583                    .border_color(cx.theme().colors().border)
 8584                    .rounded_l_lg()
 8585                    .when(line_count > 1, |el| el.rounded_br_lg())
 8586                    .pr_1()
 8587                    .child(styled_text),
 8588            )
 8589            .child(
 8590                h_flex()
 8591                    .h(line_height + BORDER_WIDTH * 2.)
 8592                    .px_1p5()
 8593                    .gap_1()
 8594                    // Workaround: For some reason, there's a gap if we don't do this
 8595                    .ml(-BORDER_WIDTH)
 8596                    .shadow(vec![gpui::BoxShadow {
 8597                        color: gpui::black().opacity(0.05),
 8598                        offset: point(px(1.), px(1.)),
 8599                        blur_radius: px(2.),
 8600                        spread_radius: px(0.),
 8601                    }])
 8602                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8603                    .border(BORDER_WIDTH)
 8604                    .border_color(cx.theme().colors().border)
 8605                    .rounded_r_lg()
 8606                    .id("edit_prediction_diff_popover_keybind")
 8607                    .when(!has_keybind, |el| {
 8608                        let status_colors = cx.theme().status();
 8609
 8610                        el.bg(status_colors.error_background)
 8611                            .border_color(status_colors.error.opacity(0.6))
 8612                            .child(Icon::new(IconName::Info).color(Color::Error))
 8613                            .cursor_default()
 8614                            .hoverable_tooltip(move |_window, cx| {
 8615                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8616                            })
 8617                    })
 8618                    .children(keybind),
 8619            )
 8620            .into_any();
 8621
 8622        let longest_row =
 8623            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8624        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8625            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8626        } else {
 8627            layout_line(
 8628                longest_row,
 8629                editor_snapshot,
 8630                style,
 8631                editor_width,
 8632                |_| false,
 8633                window,
 8634                cx,
 8635            )
 8636            .width
 8637        };
 8638
 8639        let viewport_bounds =
 8640            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8641                right: -right_margin,
 8642                ..Default::default()
 8643            });
 8644
 8645        let x_after_longest =
 8646            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8647                - scroll_pixel_position.x;
 8648
 8649        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8650
 8651        // Fully visible if it can be displayed within the window (allow overlapping other
 8652        // panes). However, this is only allowed if the popover starts within text_bounds.
 8653        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8654            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8655
 8656        let mut origin = if can_position_to_the_right {
 8657            point(
 8658                x_after_longest,
 8659                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8660                    - scroll_pixel_position.y,
 8661            )
 8662        } else {
 8663            let cursor_row = newest_selection_head.map(|head| head.row());
 8664            let above_edit = edit_start
 8665                .row()
 8666                .0
 8667                .checked_sub(line_count as u32)
 8668                .map(DisplayRow);
 8669            let below_edit = Some(edit_end.row() + 1);
 8670            let above_cursor =
 8671                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8672            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8673
 8674            // Place the edit popover adjacent to the edit if there is a location
 8675            // available that is onscreen and does not obscure the cursor. Otherwise,
 8676            // place it adjacent to the cursor.
 8677            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8678                .into_iter()
 8679                .flatten()
 8680                .find(|&start_row| {
 8681                    let end_row = start_row + line_count as u32;
 8682                    visible_row_range.contains(&start_row)
 8683                        && visible_row_range.contains(&end_row)
 8684                        && cursor_row.map_or(true, |cursor_row| {
 8685                            !((start_row..end_row).contains(&cursor_row))
 8686                        })
 8687                })?;
 8688
 8689            content_origin
 8690                + point(
 8691                    -scroll_pixel_position.x,
 8692                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8693                )
 8694        };
 8695
 8696        origin.x -= BORDER_WIDTH;
 8697
 8698        window.defer_draw(element, origin, 1);
 8699
 8700        // Do not return an element, since it will already be drawn due to defer_draw.
 8701        None
 8702    }
 8703
 8704    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8705        px(30.)
 8706    }
 8707
 8708    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8709        if self.read_only(cx) {
 8710            cx.theme().players().read_only()
 8711        } else {
 8712            self.style.as_ref().unwrap().local_player
 8713        }
 8714    }
 8715
 8716    fn render_edit_prediction_accept_keybind(
 8717        &self,
 8718        window: &mut Window,
 8719        cx: &App,
 8720    ) -> Option<AnyElement> {
 8721        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8722        let accept_keystroke = accept_binding.keystroke()?;
 8723
 8724        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8725
 8726        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8727            Color::Accent
 8728        } else {
 8729            Color::Muted
 8730        };
 8731
 8732        h_flex()
 8733            .px_0p5()
 8734            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8735            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8736            .text_size(TextSize::XSmall.rems(cx))
 8737            .child(h_flex().children(ui::render_modifiers(
 8738                &accept_keystroke.modifiers,
 8739                PlatformStyle::platform(),
 8740                Some(modifiers_color),
 8741                Some(IconSize::XSmall.rems().into()),
 8742                true,
 8743            )))
 8744            .when(is_platform_style_mac, |parent| {
 8745                parent.child(accept_keystroke.key.clone())
 8746            })
 8747            .when(!is_platform_style_mac, |parent| {
 8748                parent.child(
 8749                    Key::new(
 8750                        util::capitalize(&accept_keystroke.key),
 8751                        Some(Color::Default),
 8752                    )
 8753                    .size(Some(IconSize::XSmall.rems().into())),
 8754                )
 8755            })
 8756            .into_any()
 8757            .into()
 8758    }
 8759
 8760    fn render_edit_prediction_line_popover(
 8761        &self,
 8762        label: impl Into<SharedString>,
 8763        icon: Option<IconName>,
 8764        window: &mut Window,
 8765        cx: &App,
 8766    ) -> Option<Stateful<Div>> {
 8767        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8768
 8769        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8770        let has_keybind = keybind.is_some();
 8771
 8772        let result = h_flex()
 8773            .id("ep-line-popover")
 8774            .py_0p5()
 8775            .pl_1()
 8776            .pr(padding_right)
 8777            .gap_1()
 8778            .rounded_md()
 8779            .border_1()
 8780            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8781            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8782            .shadow_sm()
 8783            .when(!has_keybind, |el| {
 8784                let status_colors = cx.theme().status();
 8785
 8786                el.bg(status_colors.error_background)
 8787                    .border_color(status_colors.error.opacity(0.6))
 8788                    .pl_2()
 8789                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8790                    .cursor_default()
 8791                    .hoverable_tooltip(move |_window, cx| {
 8792                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8793                    })
 8794            })
 8795            .children(keybind)
 8796            .child(
 8797                Label::new(label)
 8798                    .size(LabelSize::Small)
 8799                    .when(!has_keybind, |el| {
 8800                        el.color(cx.theme().status().error.into()).strikethrough()
 8801                    }),
 8802            )
 8803            .when(!has_keybind, |el| {
 8804                el.child(
 8805                    h_flex().ml_1().child(
 8806                        Icon::new(IconName::Info)
 8807                            .size(IconSize::Small)
 8808                            .color(cx.theme().status().error.into()),
 8809                    ),
 8810                )
 8811            })
 8812            .when_some(icon, |element, icon| {
 8813                element.child(
 8814                    div()
 8815                        .mt(px(1.5))
 8816                        .child(Icon::new(icon).size(IconSize::Small)),
 8817                )
 8818            });
 8819
 8820        Some(result)
 8821    }
 8822
 8823    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8824        let accent_color = cx.theme().colors().text_accent;
 8825        let editor_bg_color = cx.theme().colors().editor_background;
 8826        editor_bg_color.blend(accent_color.opacity(0.1))
 8827    }
 8828
 8829    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8830        let accent_color = cx.theme().colors().text_accent;
 8831        let editor_bg_color = cx.theme().colors().editor_background;
 8832        editor_bg_color.blend(accent_color.opacity(0.6))
 8833    }
 8834
 8835    fn render_edit_prediction_cursor_popover(
 8836        &self,
 8837        min_width: Pixels,
 8838        max_width: Pixels,
 8839        cursor_point: Point,
 8840        style: &EditorStyle,
 8841        accept_keystroke: Option<&gpui::Keystroke>,
 8842        _window: &Window,
 8843        cx: &mut Context<Editor>,
 8844    ) -> Option<AnyElement> {
 8845        let provider = self.edit_prediction_provider.as_ref()?;
 8846
 8847        if provider.provider.needs_terms_acceptance(cx) {
 8848            return Some(
 8849                h_flex()
 8850                    .min_w(min_width)
 8851                    .flex_1()
 8852                    .px_2()
 8853                    .py_1()
 8854                    .gap_3()
 8855                    .elevation_2(cx)
 8856                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8857                    .id("accept-terms")
 8858                    .cursor_pointer()
 8859                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8860                    .on_click(cx.listener(|this, _event, window, cx| {
 8861                        cx.stop_propagation();
 8862                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8863                        window.dispatch_action(
 8864                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8865                            cx,
 8866                        );
 8867                    }))
 8868                    .child(
 8869                        h_flex()
 8870                            .flex_1()
 8871                            .gap_2()
 8872                            .child(Icon::new(IconName::ZedPredict))
 8873                            .child(Label::new("Accept Terms of Service"))
 8874                            .child(div().w_full())
 8875                            .child(
 8876                                Icon::new(IconName::ArrowUpRight)
 8877                                    .color(Color::Muted)
 8878                                    .size(IconSize::Small),
 8879                            )
 8880                            .into_any_element(),
 8881                    )
 8882                    .into_any(),
 8883            );
 8884        }
 8885
 8886        let is_refreshing = provider.provider.is_refreshing(cx);
 8887
 8888        fn pending_completion_container() -> Div {
 8889            h_flex()
 8890                .h_full()
 8891                .flex_1()
 8892                .gap_2()
 8893                .child(Icon::new(IconName::ZedPredict))
 8894        }
 8895
 8896        let completion = match &self.active_inline_completion {
 8897            Some(prediction) => {
 8898                if !self.has_visible_completions_menu() {
 8899                    const RADIUS: Pixels = px(6.);
 8900                    const BORDER_WIDTH: Pixels = px(1.);
 8901
 8902                    return Some(
 8903                        h_flex()
 8904                            .elevation_2(cx)
 8905                            .border(BORDER_WIDTH)
 8906                            .border_color(cx.theme().colors().border)
 8907                            .when(accept_keystroke.is_none(), |el| {
 8908                                el.border_color(cx.theme().status().error)
 8909                            })
 8910                            .rounded(RADIUS)
 8911                            .rounded_tl(px(0.))
 8912                            .overflow_hidden()
 8913                            .child(div().px_1p5().child(match &prediction.completion {
 8914                                InlineCompletion::Move { target, snapshot } => {
 8915                                    use text::ToPoint as _;
 8916                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8917                                    {
 8918                                        Icon::new(IconName::ZedPredictDown)
 8919                                    } else {
 8920                                        Icon::new(IconName::ZedPredictUp)
 8921                                    }
 8922                                }
 8923                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8924                            }))
 8925                            .child(
 8926                                h_flex()
 8927                                    .gap_1()
 8928                                    .py_1()
 8929                                    .px_2()
 8930                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8931                                    .border_l_1()
 8932                                    .border_color(cx.theme().colors().border)
 8933                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8934                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8935                                        el.child(
 8936                                            Label::new("Hold")
 8937                                                .size(LabelSize::Small)
 8938                                                .when(accept_keystroke.is_none(), |el| {
 8939                                                    el.strikethrough()
 8940                                                })
 8941                                                .line_height_style(LineHeightStyle::UiLabel),
 8942                                        )
 8943                                    })
 8944                                    .id("edit_prediction_cursor_popover_keybind")
 8945                                    .when(accept_keystroke.is_none(), |el| {
 8946                                        let status_colors = cx.theme().status();
 8947
 8948                                        el.bg(status_colors.error_background)
 8949                                            .border_color(status_colors.error.opacity(0.6))
 8950                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8951                                            .cursor_default()
 8952                                            .hoverable_tooltip(move |_window, cx| {
 8953                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8954                                                    .into()
 8955                                            })
 8956                                    })
 8957                                    .when_some(
 8958                                        accept_keystroke.as_ref(),
 8959                                        |el, accept_keystroke| {
 8960                                            el.child(h_flex().children(ui::render_modifiers(
 8961                                                &accept_keystroke.modifiers,
 8962                                                PlatformStyle::platform(),
 8963                                                Some(Color::Default),
 8964                                                Some(IconSize::XSmall.rems().into()),
 8965                                                false,
 8966                                            )))
 8967                                        },
 8968                                    ),
 8969                            )
 8970                            .into_any(),
 8971                    );
 8972                }
 8973
 8974                self.render_edit_prediction_cursor_popover_preview(
 8975                    prediction,
 8976                    cursor_point,
 8977                    style,
 8978                    cx,
 8979                )?
 8980            }
 8981
 8982            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8983                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8984                    stale_completion,
 8985                    cursor_point,
 8986                    style,
 8987                    cx,
 8988                )?,
 8989
 8990                None => {
 8991                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8992                }
 8993            },
 8994
 8995            None => pending_completion_container().child(Label::new("No Prediction")),
 8996        };
 8997
 8998        let completion = if is_refreshing {
 8999            completion
 9000                .with_animation(
 9001                    "loading-completion",
 9002                    Animation::new(Duration::from_secs(2))
 9003                        .repeat()
 9004                        .with_easing(pulsating_between(0.4, 0.8)),
 9005                    |label, delta| label.opacity(delta),
 9006                )
 9007                .into_any_element()
 9008        } else {
 9009            completion.into_any_element()
 9010        };
 9011
 9012        let has_completion = self.active_inline_completion.is_some();
 9013
 9014        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9015        Some(
 9016            h_flex()
 9017                .min_w(min_width)
 9018                .max_w(max_width)
 9019                .flex_1()
 9020                .elevation_2(cx)
 9021                .border_color(cx.theme().colors().border)
 9022                .child(
 9023                    div()
 9024                        .flex_1()
 9025                        .py_1()
 9026                        .px_2()
 9027                        .overflow_hidden()
 9028                        .child(completion),
 9029                )
 9030                .when_some(accept_keystroke, |el, accept_keystroke| {
 9031                    if !accept_keystroke.modifiers.modified() {
 9032                        return el;
 9033                    }
 9034
 9035                    el.child(
 9036                        h_flex()
 9037                            .h_full()
 9038                            .border_l_1()
 9039                            .rounded_r_lg()
 9040                            .border_color(cx.theme().colors().border)
 9041                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9042                            .gap_1()
 9043                            .py_1()
 9044                            .px_2()
 9045                            .child(
 9046                                h_flex()
 9047                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9048                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9049                                    .child(h_flex().children(ui::render_modifiers(
 9050                                        &accept_keystroke.modifiers,
 9051                                        PlatformStyle::platform(),
 9052                                        Some(if !has_completion {
 9053                                            Color::Muted
 9054                                        } else {
 9055                                            Color::Default
 9056                                        }),
 9057                                        None,
 9058                                        false,
 9059                                    ))),
 9060                            )
 9061                            .child(Label::new("Preview").into_any_element())
 9062                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9063                    )
 9064                })
 9065                .into_any(),
 9066        )
 9067    }
 9068
 9069    fn render_edit_prediction_cursor_popover_preview(
 9070        &self,
 9071        completion: &InlineCompletionState,
 9072        cursor_point: Point,
 9073        style: &EditorStyle,
 9074        cx: &mut Context<Editor>,
 9075    ) -> Option<Div> {
 9076        use text::ToPoint as _;
 9077
 9078        fn render_relative_row_jump(
 9079            prefix: impl Into<String>,
 9080            current_row: u32,
 9081            target_row: u32,
 9082        ) -> Div {
 9083            let (row_diff, arrow) = if target_row < current_row {
 9084                (current_row - target_row, IconName::ArrowUp)
 9085            } else {
 9086                (target_row - current_row, IconName::ArrowDown)
 9087            };
 9088
 9089            h_flex()
 9090                .child(
 9091                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9092                        .color(Color::Muted)
 9093                        .size(LabelSize::Small),
 9094                )
 9095                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9096        }
 9097
 9098        match &completion.completion {
 9099            InlineCompletion::Move {
 9100                target, snapshot, ..
 9101            } => Some(
 9102                h_flex()
 9103                    .px_2()
 9104                    .gap_2()
 9105                    .flex_1()
 9106                    .child(
 9107                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9108                            Icon::new(IconName::ZedPredictDown)
 9109                        } else {
 9110                            Icon::new(IconName::ZedPredictUp)
 9111                        },
 9112                    )
 9113                    .child(Label::new("Jump to Edit")),
 9114            ),
 9115
 9116            InlineCompletion::Edit {
 9117                edits,
 9118                edit_preview,
 9119                snapshot,
 9120                display_mode: _,
 9121            } => {
 9122                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9123
 9124                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9125                    &snapshot,
 9126                    &edits,
 9127                    edit_preview.as_ref()?,
 9128                    true,
 9129                    cx,
 9130                )
 9131                .first_line_preview();
 9132
 9133                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9134                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9135
 9136                let preview = h_flex()
 9137                    .gap_1()
 9138                    .min_w_16()
 9139                    .child(styled_text)
 9140                    .when(has_more_lines, |parent| parent.child(""));
 9141
 9142                let left = if first_edit_row != cursor_point.row {
 9143                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9144                        .into_any_element()
 9145                } else {
 9146                    Icon::new(IconName::ZedPredict).into_any_element()
 9147                };
 9148
 9149                Some(
 9150                    h_flex()
 9151                        .h_full()
 9152                        .flex_1()
 9153                        .gap_2()
 9154                        .pr_1()
 9155                        .overflow_x_hidden()
 9156                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9157                        .child(left)
 9158                        .child(preview),
 9159                )
 9160            }
 9161        }
 9162    }
 9163
 9164    pub fn render_context_menu(
 9165        &self,
 9166        style: &EditorStyle,
 9167        max_height_in_lines: u32,
 9168        window: &mut Window,
 9169        cx: &mut Context<Editor>,
 9170    ) -> Option<AnyElement> {
 9171        let menu = self.context_menu.borrow();
 9172        let menu = menu.as_ref()?;
 9173        if !menu.visible() {
 9174            return None;
 9175        };
 9176        Some(menu.render(style, max_height_in_lines, window, cx))
 9177    }
 9178
 9179    fn render_context_menu_aside(
 9180        &mut self,
 9181        max_size: Size<Pixels>,
 9182        window: &mut Window,
 9183        cx: &mut Context<Editor>,
 9184    ) -> Option<AnyElement> {
 9185        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9186            if menu.visible() {
 9187                menu.render_aside(max_size, window, cx)
 9188            } else {
 9189                None
 9190            }
 9191        })
 9192    }
 9193
 9194    fn hide_context_menu(
 9195        &mut self,
 9196        window: &mut Window,
 9197        cx: &mut Context<Self>,
 9198    ) -> Option<CodeContextMenu> {
 9199        cx.notify();
 9200        self.completion_tasks.clear();
 9201        let context_menu = self.context_menu.borrow_mut().take();
 9202        self.stale_inline_completion_in_menu.take();
 9203        self.update_visible_inline_completion(window, cx);
 9204        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9205            if let Some(completion_provider) = &self.completion_provider {
 9206                completion_provider.selection_changed(None, window, cx);
 9207            }
 9208        }
 9209        context_menu
 9210    }
 9211
 9212    fn show_snippet_choices(
 9213        &mut self,
 9214        choices: &Vec<String>,
 9215        selection: Range<Anchor>,
 9216        cx: &mut Context<Self>,
 9217    ) {
 9218        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9219            (Some(a), Some(b)) if a == b => a,
 9220            _ => {
 9221                log::error!("expected anchor range to have matching buffer IDs");
 9222                return;
 9223            }
 9224        };
 9225        let multi_buffer = self.buffer().read(cx);
 9226        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9227            return;
 9228        };
 9229
 9230        let id = post_inc(&mut self.next_completion_id);
 9231        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9232        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9233            CompletionsMenu::new_snippet_choices(
 9234                id,
 9235                true,
 9236                choices,
 9237                selection,
 9238                buffer,
 9239                snippet_sort_order,
 9240            ),
 9241        ));
 9242    }
 9243
 9244    pub fn insert_snippet(
 9245        &mut self,
 9246        insertion_ranges: &[Range<usize>],
 9247        snippet: Snippet,
 9248        window: &mut Window,
 9249        cx: &mut Context<Self>,
 9250    ) -> Result<()> {
 9251        struct Tabstop<T> {
 9252            is_end_tabstop: bool,
 9253            ranges: Vec<Range<T>>,
 9254            choices: Option<Vec<String>>,
 9255        }
 9256
 9257        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9258            let snippet_text: Arc<str> = snippet.text.clone().into();
 9259            let edits = insertion_ranges
 9260                .iter()
 9261                .cloned()
 9262                .map(|range| (range, snippet_text.clone()));
 9263            let autoindent_mode = AutoindentMode::Block {
 9264                original_indent_columns: Vec::new(),
 9265            };
 9266            buffer.edit(edits, Some(autoindent_mode), cx);
 9267
 9268            let snapshot = &*buffer.read(cx);
 9269            let snippet = &snippet;
 9270            snippet
 9271                .tabstops
 9272                .iter()
 9273                .map(|tabstop| {
 9274                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9275                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9276                    });
 9277                    let mut tabstop_ranges = tabstop
 9278                        .ranges
 9279                        .iter()
 9280                        .flat_map(|tabstop_range| {
 9281                            let mut delta = 0_isize;
 9282                            insertion_ranges.iter().map(move |insertion_range| {
 9283                                let insertion_start = insertion_range.start as isize + delta;
 9284                                delta +=
 9285                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9286
 9287                                let start = ((insertion_start + tabstop_range.start) as usize)
 9288                                    .min(snapshot.len());
 9289                                let end = ((insertion_start + tabstop_range.end) as usize)
 9290                                    .min(snapshot.len());
 9291                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9292                            })
 9293                        })
 9294                        .collect::<Vec<_>>();
 9295                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9296
 9297                    Tabstop {
 9298                        is_end_tabstop,
 9299                        ranges: tabstop_ranges,
 9300                        choices: tabstop.choices.clone(),
 9301                    }
 9302                })
 9303                .collect::<Vec<_>>()
 9304        });
 9305        if let Some(tabstop) = tabstops.first() {
 9306            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9307                // Reverse order so that the first range is the newest created selection.
 9308                // Completions will use it and autoscroll will prioritize it.
 9309                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9310            });
 9311
 9312            if let Some(choices) = &tabstop.choices {
 9313                if let Some(selection) = tabstop.ranges.first() {
 9314                    self.show_snippet_choices(choices, selection.clone(), cx)
 9315                }
 9316            }
 9317
 9318            // If we're already at the last tabstop and it's at the end of the snippet,
 9319            // we're done, we don't need to keep the state around.
 9320            if !tabstop.is_end_tabstop {
 9321                let choices = tabstops
 9322                    .iter()
 9323                    .map(|tabstop| tabstop.choices.clone())
 9324                    .collect();
 9325
 9326                let ranges = tabstops
 9327                    .into_iter()
 9328                    .map(|tabstop| tabstop.ranges)
 9329                    .collect::<Vec<_>>();
 9330
 9331                self.snippet_stack.push(SnippetState {
 9332                    active_index: 0,
 9333                    ranges,
 9334                    choices,
 9335                });
 9336            }
 9337
 9338            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9339            if self.autoclose_regions.is_empty() {
 9340                let snapshot = self.buffer.read(cx).snapshot(cx);
 9341                for selection in &mut self.selections.all::<Point>(cx) {
 9342                    let selection_head = selection.head();
 9343                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9344                        continue;
 9345                    };
 9346
 9347                    let mut bracket_pair = None;
 9348                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9349                    let prev_chars = snapshot
 9350                        .reversed_chars_at(selection_head)
 9351                        .collect::<String>();
 9352                    for (pair, enabled) in scope.brackets() {
 9353                        if enabled
 9354                            && pair.close
 9355                            && prev_chars.starts_with(pair.start.as_str())
 9356                            && next_chars.starts_with(pair.end.as_str())
 9357                        {
 9358                            bracket_pair = Some(pair.clone());
 9359                            break;
 9360                        }
 9361                    }
 9362                    if let Some(pair) = bracket_pair {
 9363                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9364                        let autoclose_enabled =
 9365                            self.use_autoclose && snapshot_settings.use_autoclose;
 9366                        if autoclose_enabled {
 9367                            let start = snapshot.anchor_after(selection_head);
 9368                            let end = snapshot.anchor_after(selection_head);
 9369                            self.autoclose_regions.push(AutocloseRegion {
 9370                                selection_id: selection.id,
 9371                                range: start..end,
 9372                                pair,
 9373                            });
 9374                        }
 9375                    }
 9376                }
 9377            }
 9378        }
 9379        Ok(())
 9380    }
 9381
 9382    pub fn move_to_next_snippet_tabstop(
 9383        &mut self,
 9384        window: &mut Window,
 9385        cx: &mut Context<Self>,
 9386    ) -> bool {
 9387        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9388    }
 9389
 9390    pub fn move_to_prev_snippet_tabstop(
 9391        &mut self,
 9392        window: &mut Window,
 9393        cx: &mut Context<Self>,
 9394    ) -> bool {
 9395        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9396    }
 9397
 9398    pub fn move_to_snippet_tabstop(
 9399        &mut self,
 9400        bias: Bias,
 9401        window: &mut Window,
 9402        cx: &mut Context<Self>,
 9403    ) -> bool {
 9404        if let Some(mut snippet) = self.snippet_stack.pop() {
 9405            match bias {
 9406                Bias::Left => {
 9407                    if snippet.active_index > 0 {
 9408                        snippet.active_index -= 1;
 9409                    } else {
 9410                        self.snippet_stack.push(snippet);
 9411                        return false;
 9412                    }
 9413                }
 9414                Bias::Right => {
 9415                    if snippet.active_index + 1 < snippet.ranges.len() {
 9416                        snippet.active_index += 1;
 9417                    } else {
 9418                        self.snippet_stack.push(snippet);
 9419                        return false;
 9420                    }
 9421                }
 9422            }
 9423            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9424                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9425                    // Reverse order so that the first range is the newest created selection.
 9426                    // Completions will use it and autoscroll will prioritize it.
 9427                    s.select_ranges(current_ranges.iter().rev().cloned())
 9428                });
 9429
 9430                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9431                    if let Some(selection) = current_ranges.first() {
 9432                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9433                    }
 9434                }
 9435
 9436                // If snippet state is not at the last tabstop, push it back on the stack
 9437                if snippet.active_index + 1 < snippet.ranges.len() {
 9438                    self.snippet_stack.push(snippet);
 9439                }
 9440                return true;
 9441            }
 9442        }
 9443
 9444        false
 9445    }
 9446
 9447    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9448        self.transact(window, cx, |this, window, cx| {
 9449            this.select_all(&SelectAll, window, cx);
 9450            this.insert("", window, cx);
 9451        });
 9452    }
 9453
 9454    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9455        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9456        self.transact(window, cx, |this, window, cx| {
 9457            this.select_autoclose_pair(window, cx);
 9458            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9459            if !this.linked_edit_ranges.is_empty() {
 9460                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9461                let snapshot = this.buffer.read(cx).snapshot(cx);
 9462
 9463                for selection in selections.iter() {
 9464                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9465                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9466                    if selection_start.buffer_id != selection_end.buffer_id {
 9467                        continue;
 9468                    }
 9469                    if let Some(ranges) =
 9470                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9471                    {
 9472                        for (buffer, entries) in ranges {
 9473                            linked_ranges.entry(buffer).or_default().extend(entries);
 9474                        }
 9475                    }
 9476                }
 9477            }
 9478
 9479            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9480            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9481            for selection in &mut selections {
 9482                if selection.is_empty() {
 9483                    let old_head = selection.head();
 9484                    let mut new_head =
 9485                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9486                            .to_point(&display_map);
 9487                    if let Some((buffer, line_buffer_range)) = display_map
 9488                        .buffer_snapshot
 9489                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9490                    {
 9491                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9492                        let indent_len = match indent_size.kind {
 9493                            IndentKind::Space => {
 9494                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9495                            }
 9496                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9497                        };
 9498                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9499                            let indent_len = indent_len.get();
 9500                            new_head = cmp::min(
 9501                                new_head,
 9502                                MultiBufferPoint::new(
 9503                                    old_head.row,
 9504                                    ((old_head.column - 1) / indent_len) * indent_len,
 9505                                ),
 9506                            );
 9507                        }
 9508                    }
 9509
 9510                    selection.set_head(new_head, SelectionGoal::None);
 9511                }
 9512            }
 9513
 9514            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9515                s.select(selections)
 9516            });
 9517            this.insert("", window, cx);
 9518            let empty_str: Arc<str> = Arc::from("");
 9519            for (buffer, edits) in linked_ranges {
 9520                let snapshot = buffer.read(cx).snapshot();
 9521                use text::ToPoint as TP;
 9522
 9523                let edits = edits
 9524                    .into_iter()
 9525                    .map(|range| {
 9526                        let end_point = TP::to_point(&range.end, &snapshot);
 9527                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9528
 9529                        if end_point == start_point {
 9530                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9531                                .saturating_sub(1);
 9532                            start_point =
 9533                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9534                        };
 9535
 9536                        (start_point..end_point, empty_str.clone())
 9537                    })
 9538                    .sorted_by_key(|(range, _)| range.start)
 9539                    .collect::<Vec<_>>();
 9540                buffer.update(cx, |this, cx| {
 9541                    this.edit(edits, None, cx);
 9542                })
 9543            }
 9544            this.refresh_inline_completion(true, false, window, cx);
 9545            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9546        });
 9547    }
 9548
 9549    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9550        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9551        self.transact(window, cx, |this, window, cx| {
 9552            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9553                s.move_with(|map, selection| {
 9554                    if selection.is_empty() {
 9555                        let cursor = movement::right(map, selection.head());
 9556                        selection.end = cursor;
 9557                        selection.reversed = true;
 9558                        selection.goal = SelectionGoal::None;
 9559                    }
 9560                })
 9561            });
 9562            this.insert("", window, cx);
 9563            this.refresh_inline_completion(true, false, window, cx);
 9564        });
 9565    }
 9566
 9567    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9568        if self.mode.is_single_line() {
 9569            cx.propagate();
 9570            return;
 9571        }
 9572
 9573        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9574        if self.move_to_prev_snippet_tabstop(window, cx) {
 9575            return;
 9576        }
 9577        self.outdent(&Outdent, window, cx);
 9578    }
 9579
 9580    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9581        if self.mode.is_single_line() {
 9582            cx.propagate();
 9583            return;
 9584        }
 9585
 9586        if self.move_to_next_snippet_tabstop(window, cx) {
 9587            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9588            return;
 9589        }
 9590        if self.read_only(cx) {
 9591            return;
 9592        }
 9593        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9594        let mut selections = self.selections.all_adjusted(cx);
 9595        let buffer = self.buffer.read(cx);
 9596        let snapshot = buffer.snapshot(cx);
 9597        let rows_iter = selections.iter().map(|s| s.head().row);
 9598        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9599
 9600        let has_some_cursor_in_whitespace = selections
 9601            .iter()
 9602            .filter(|selection| selection.is_empty())
 9603            .any(|selection| {
 9604                let cursor = selection.head();
 9605                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9606                cursor.column < current_indent.len
 9607            });
 9608
 9609        let mut edits = Vec::new();
 9610        let mut prev_edited_row = 0;
 9611        let mut row_delta = 0;
 9612        for selection in &mut selections {
 9613            if selection.start.row != prev_edited_row {
 9614                row_delta = 0;
 9615            }
 9616            prev_edited_row = selection.end.row;
 9617
 9618            // If the selection is non-empty, then increase the indentation of the selected lines.
 9619            if !selection.is_empty() {
 9620                row_delta =
 9621                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9622                continue;
 9623            }
 9624
 9625            let cursor = selection.head();
 9626            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9627            if let Some(suggested_indent) =
 9628                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9629            {
 9630                // Don't do anything if already at suggested indent
 9631                // and there is any other cursor which is not
 9632                if has_some_cursor_in_whitespace
 9633                    && cursor.column == current_indent.len
 9634                    && current_indent.len == suggested_indent.len
 9635                {
 9636                    continue;
 9637                }
 9638
 9639                // Adjust line and move cursor to suggested indent
 9640                // if cursor is not at suggested indent
 9641                if cursor.column < suggested_indent.len
 9642                    && cursor.column <= current_indent.len
 9643                    && current_indent.len <= suggested_indent.len
 9644                {
 9645                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9646                    selection.end = selection.start;
 9647                    if row_delta == 0 {
 9648                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9649                            cursor.row,
 9650                            current_indent,
 9651                            suggested_indent,
 9652                        ));
 9653                        row_delta = suggested_indent.len - current_indent.len;
 9654                    }
 9655                    continue;
 9656                }
 9657
 9658                // If current indent is more than suggested indent
 9659                // only move cursor to current indent and skip indent
 9660                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9661                    selection.start = Point::new(cursor.row, current_indent.len);
 9662                    selection.end = selection.start;
 9663                    continue;
 9664                }
 9665            }
 9666
 9667            // Otherwise, insert a hard or soft tab.
 9668            let settings = buffer.language_settings_at(cursor, cx);
 9669            let tab_size = if settings.hard_tabs {
 9670                IndentSize::tab()
 9671            } else {
 9672                let tab_size = settings.tab_size.get();
 9673                let indent_remainder = snapshot
 9674                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9675                    .flat_map(str::chars)
 9676                    .fold(row_delta % tab_size, |counter: u32, c| {
 9677                        if c == '\t' {
 9678                            0
 9679                        } else {
 9680                            (counter + 1) % tab_size
 9681                        }
 9682                    });
 9683
 9684                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9685                IndentSize::spaces(chars_to_next_tab_stop)
 9686            };
 9687            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9688            selection.end = selection.start;
 9689            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9690            row_delta += tab_size.len;
 9691        }
 9692
 9693        self.transact(window, cx, |this, window, cx| {
 9694            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9695            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9696                s.select(selections)
 9697            });
 9698            this.refresh_inline_completion(true, false, window, cx);
 9699        });
 9700    }
 9701
 9702    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9703        if self.read_only(cx) {
 9704            return;
 9705        }
 9706        if self.mode.is_single_line() {
 9707            cx.propagate();
 9708            return;
 9709        }
 9710
 9711        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9712        let mut selections = self.selections.all::<Point>(cx);
 9713        let mut prev_edited_row = 0;
 9714        let mut row_delta = 0;
 9715        let mut edits = Vec::new();
 9716        let buffer = self.buffer.read(cx);
 9717        let snapshot = buffer.snapshot(cx);
 9718        for selection in &mut selections {
 9719            if selection.start.row != prev_edited_row {
 9720                row_delta = 0;
 9721            }
 9722            prev_edited_row = selection.end.row;
 9723
 9724            row_delta =
 9725                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9726        }
 9727
 9728        self.transact(window, cx, |this, window, cx| {
 9729            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9730            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9731                s.select(selections)
 9732            });
 9733        });
 9734    }
 9735
 9736    fn indent_selection(
 9737        buffer: &MultiBuffer,
 9738        snapshot: &MultiBufferSnapshot,
 9739        selection: &mut Selection<Point>,
 9740        edits: &mut Vec<(Range<Point>, String)>,
 9741        delta_for_start_row: u32,
 9742        cx: &App,
 9743    ) -> u32 {
 9744        let settings = buffer.language_settings_at(selection.start, cx);
 9745        let tab_size = settings.tab_size.get();
 9746        let indent_kind = if settings.hard_tabs {
 9747            IndentKind::Tab
 9748        } else {
 9749            IndentKind::Space
 9750        };
 9751        let mut start_row = selection.start.row;
 9752        let mut end_row = selection.end.row + 1;
 9753
 9754        // If a selection ends at the beginning of a line, don't indent
 9755        // that last line.
 9756        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9757            end_row -= 1;
 9758        }
 9759
 9760        // Avoid re-indenting a row that has already been indented by a
 9761        // previous selection, but still update this selection's column
 9762        // to reflect that indentation.
 9763        if delta_for_start_row > 0 {
 9764            start_row += 1;
 9765            selection.start.column += delta_for_start_row;
 9766            if selection.end.row == selection.start.row {
 9767                selection.end.column += delta_for_start_row;
 9768            }
 9769        }
 9770
 9771        let mut delta_for_end_row = 0;
 9772        let has_multiple_rows = start_row + 1 != end_row;
 9773        for row in start_row..end_row {
 9774            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9775            let indent_delta = match (current_indent.kind, indent_kind) {
 9776                (IndentKind::Space, IndentKind::Space) => {
 9777                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9778                    IndentSize::spaces(columns_to_next_tab_stop)
 9779                }
 9780                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9781                (_, IndentKind::Tab) => IndentSize::tab(),
 9782            };
 9783
 9784            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9785                0
 9786            } else {
 9787                selection.start.column
 9788            };
 9789            let row_start = Point::new(row, start);
 9790            edits.push((
 9791                row_start..row_start,
 9792                indent_delta.chars().collect::<String>(),
 9793            ));
 9794
 9795            // Update this selection's endpoints to reflect the indentation.
 9796            if row == selection.start.row {
 9797                selection.start.column += indent_delta.len;
 9798            }
 9799            if row == selection.end.row {
 9800                selection.end.column += indent_delta.len;
 9801                delta_for_end_row = indent_delta.len;
 9802            }
 9803        }
 9804
 9805        if selection.start.row == selection.end.row {
 9806            delta_for_start_row + delta_for_end_row
 9807        } else {
 9808            delta_for_end_row
 9809        }
 9810    }
 9811
 9812    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9813        if self.read_only(cx) {
 9814            return;
 9815        }
 9816        if self.mode.is_single_line() {
 9817            cx.propagate();
 9818            return;
 9819        }
 9820
 9821        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9822        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9823        let selections = self.selections.all::<Point>(cx);
 9824        let mut deletion_ranges = Vec::new();
 9825        let mut last_outdent = None;
 9826        {
 9827            let buffer = self.buffer.read(cx);
 9828            let snapshot = buffer.snapshot(cx);
 9829            for selection in &selections {
 9830                let settings = buffer.language_settings_at(selection.start, cx);
 9831                let tab_size = settings.tab_size.get();
 9832                let mut rows = selection.spanned_rows(false, &display_map);
 9833
 9834                // Avoid re-outdenting a row that has already been outdented by a
 9835                // previous selection.
 9836                if let Some(last_row) = last_outdent {
 9837                    if last_row == rows.start {
 9838                        rows.start = rows.start.next_row();
 9839                    }
 9840                }
 9841                let has_multiple_rows = rows.len() > 1;
 9842                for row in rows.iter_rows() {
 9843                    let indent_size = snapshot.indent_size_for_line(row);
 9844                    if indent_size.len > 0 {
 9845                        let deletion_len = match indent_size.kind {
 9846                            IndentKind::Space => {
 9847                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9848                                if columns_to_prev_tab_stop == 0 {
 9849                                    tab_size
 9850                                } else {
 9851                                    columns_to_prev_tab_stop
 9852                                }
 9853                            }
 9854                            IndentKind::Tab => 1,
 9855                        };
 9856                        let start = if has_multiple_rows
 9857                            || deletion_len > selection.start.column
 9858                            || indent_size.len < selection.start.column
 9859                        {
 9860                            0
 9861                        } else {
 9862                            selection.start.column - deletion_len
 9863                        };
 9864                        deletion_ranges.push(
 9865                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9866                        );
 9867                        last_outdent = Some(row);
 9868                    }
 9869                }
 9870            }
 9871        }
 9872
 9873        self.transact(window, cx, |this, window, cx| {
 9874            this.buffer.update(cx, |buffer, cx| {
 9875                let empty_str: Arc<str> = Arc::default();
 9876                buffer.edit(
 9877                    deletion_ranges
 9878                        .into_iter()
 9879                        .map(|range| (range, empty_str.clone())),
 9880                    None,
 9881                    cx,
 9882                );
 9883            });
 9884            let selections = this.selections.all::<usize>(cx);
 9885            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9886                s.select(selections)
 9887            });
 9888        });
 9889    }
 9890
 9891    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9892        if self.read_only(cx) {
 9893            return;
 9894        }
 9895        if self.mode.is_single_line() {
 9896            cx.propagate();
 9897            return;
 9898        }
 9899
 9900        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9901        let selections = self
 9902            .selections
 9903            .all::<usize>(cx)
 9904            .into_iter()
 9905            .map(|s| s.range());
 9906
 9907        self.transact(window, cx, |this, window, cx| {
 9908            this.buffer.update(cx, |buffer, cx| {
 9909                buffer.autoindent_ranges(selections, cx);
 9910            });
 9911            let selections = this.selections.all::<usize>(cx);
 9912            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9913                s.select(selections)
 9914            });
 9915        });
 9916    }
 9917
 9918    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9919        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9920        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9921        let selections = self.selections.all::<Point>(cx);
 9922
 9923        let mut new_cursors = Vec::new();
 9924        let mut edit_ranges = Vec::new();
 9925        let mut selections = selections.iter().peekable();
 9926        while let Some(selection) = selections.next() {
 9927            let mut rows = selection.spanned_rows(false, &display_map);
 9928            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9929
 9930            // Accumulate contiguous regions of rows that we want to delete.
 9931            while let Some(next_selection) = selections.peek() {
 9932                let next_rows = next_selection.spanned_rows(false, &display_map);
 9933                if next_rows.start <= rows.end {
 9934                    rows.end = next_rows.end;
 9935                    selections.next().unwrap();
 9936                } else {
 9937                    break;
 9938                }
 9939            }
 9940
 9941            let buffer = &display_map.buffer_snapshot;
 9942            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9943            let edit_end;
 9944            let cursor_buffer_row;
 9945            if buffer.max_point().row >= rows.end.0 {
 9946                // If there's a line after the range, delete the \n from the end of the row range
 9947                // and position the cursor on the next line.
 9948                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9949                cursor_buffer_row = rows.end;
 9950            } else {
 9951                // If there isn't a line after the range, delete the \n from the line before the
 9952                // start of the row range and position the cursor there.
 9953                edit_start = edit_start.saturating_sub(1);
 9954                edit_end = buffer.len();
 9955                cursor_buffer_row = rows.start.previous_row();
 9956            }
 9957
 9958            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9959            *cursor.column_mut() =
 9960                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9961
 9962            new_cursors.push((
 9963                selection.id,
 9964                buffer.anchor_after(cursor.to_point(&display_map)),
 9965            ));
 9966            edit_ranges.push(edit_start..edit_end);
 9967        }
 9968
 9969        self.transact(window, cx, |this, window, cx| {
 9970            let buffer = this.buffer.update(cx, |buffer, cx| {
 9971                let empty_str: Arc<str> = Arc::default();
 9972                buffer.edit(
 9973                    edit_ranges
 9974                        .into_iter()
 9975                        .map(|range| (range, empty_str.clone())),
 9976                    None,
 9977                    cx,
 9978                );
 9979                buffer.snapshot(cx)
 9980            });
 9981            let new_selections = new_cursors
 9982                .into_iter()
 9983                .map(|(id, cursor)| {
 9984                    let cursor = cursor.to_point(&buffer);
 9985                    Selection {
 9986                        id,
 9987                        start: cursor,
 9988                        end: cursor,
 9989                        reversed: false,
 9990                        goal: SelectionGoal::None,
 9991                    }
 9992                })
 9993                .collect();
 9994
 9995            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9996                s.select(new_selections);
 9997            });
 9998        });
 9999    }
10000
10001    pub fn join_lines_impl(
10002        &mut self,
10003        insert_whitespace: bool,
10004        window: &mut Window,
10005        cx: &mut Context<Self>,
10006    ) {
10007        if self.read_only(cx) {
10008            return;
10009        }
10010        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10011        for selection in self.selections.all::<Point>(cx) {
10012            let start = MultiBufferRow(selection.start.row);
10013            // Treat single line selections as if they include the next line. Otherwise this action
10014            // would do nothing for single line selections individual cursors.
10015            let end = if selection.start.row == selection.end.row {
10016                MultiBufferRow(selection.start.row + 1)
10017            } else {
10018                MultiBufferRow(selection.end.row)
10019            };
10020
10021            if let Some(last_row_range) = row_ranges.last_mut() {
10022                if start <= last_row_range.end {
10023                    last_row_range.end = end;
10024                    continue;
10025                }
10026            }
10027            row_ranges.push(start..end);
10028        }
10029
10030        let snapshot = self.buffer.read(cx).snapshot(cx);
10031        let mut cursor_positions = Vec::new();
10032        for row_range in &row_ranges {
10033            let anchor = snapshot.anchor_before(Point::new(
10034                row_range.end.previous_row().0,
10035                snapshot.line_len(row_range.end.previous_row()),
10036            ));
10037            cursor_positions.push(anchor..anchor);
10038        }
10039
10040        self.transact(window, cx, |this, window, cx| {
10041            for row_range in row_ranges.into_iter().rev() {
10042                for row in row_range.iter_rows().rev() {
10043                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10044                    let next_line_row = row.next_row();
10045                    let indent = snapshot.indent_size_for_line(next_line_row);
10046                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10047
10048                    let replace =
10049                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10050                            " "
10051                        } else {
10052                            ""
10053                        };
10054
10055                    this.buffer.update(cx, |buffer, cx| {
10056                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10057                    });
10058                }
10059            }
10060
10061            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10062                s.select_anchor_ranges(cursor_positions)
10063            });
10064        });
10065    }
10066
10067    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10068        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10069        self.join_lines_impl(true, window, cx);
10070    }
10071
10072    pub fn sort_lines_case_sensitive(
10073        &mut self,
10074        _: &SortLinesCaseSensitive,
10075        window: &mut Window,
10076        cx: &mut Context<Self>,
10077    ) {
10078        self.manipulate_lines(window, cx, |lines| lines.sort())
10079    }
10080
10081    pub fn sort_lines_case_insensitive(
10082        &mut self,
10083        _: &SortLinesCaseInsensitive,
10084        window: &mut Window,
10085        cx: &mut Context<Self>,
10086    ) {
10087        self.manipulate_lines(window, cx, |lines| {
10088            lines.sort_by_key(|line| line.to_lowercase())
10089        })
10090    }
10091
10092    pub fn unique_lines_case_insensitive(
10093        &mut self,
10094        _: &UniqueLinesCaseInsensitive,
10095        window: &mut Window,
10096        cx: &mut Context<Self>,
10097    ) {
10098        self.manipulate_lines(window, cx, |lines| {
10099            let mut seen = HashSet::default();
10100            lines.retain(|line| seen.insert(line.to_lowercase()));
10101        })
10102    }
10103
10104    pub fn unique_lines_case_sensitive(
10105        &mut self,
10106        _: &UniqueLinesCaseSensitive,
10107        window: &mut Window,
10108        cx: &mut Context<Self>,
10109    ) {
10110        self.manipulate_lines(window, cx, |lines| {
10111            let mut seen = HashSet::default();
10112            lines.retain(|line| seen.insert(*line));
10113        })
10114    }
10115
10116    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10117        let Some(project) = self.project.clone() else {
10118            return;
10119        };
10120        self.reload(project, window, cx)
10121            .detach_and_notify_err(window, cx);
10122    }
10123
10124    pub fn restore_file(
10125        &mut self,
10126        _: &::git::RestoreFile,
10127        window: &mut Window,
10128        cx: &mut Context<Self>,
10129    ) {
10130        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10131        let mut buffer_ids = HashSet::default();
10132        let snapshot = self.buffer().read(cx).snapshot(cx);
10133        for selection in self.selections.all::<usize>(cx) {
10134            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10135        }
10136
10137        let buffer = self.buffer().read(cx);
10138        let ranges = buffer_ids
10139            .into_iter()
10140            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10141            .collect::<Vec<_>>();
10142
10143        self.restore_hunks_in_ranges(ranges, window, cx);
10144    }
10145
10146    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10147        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10148        let selections = self
10149            .selections
10150            .all(cx)
10151            .into_iter()
10152            .map(|s| s.range())
10153            .collect();
10154        self.restore_hunks_in_ranges(selections, window, cx);
10155    }
10156
10157    pub fn restore_hunks_in_ranges(
10158        &mut self,
10159        ranges: Vec<Range<Point>>,
10160        window: &mut Window,
10161        cx: &mut Context<Editor>,
10162    ) {
10163        let mut revert_changes = HashMap::default();
10164        let chunk_by = self
10165            .snapshot(window, cx)
10166            .hunks_for_ranges(ranges)
10167            .into_iter()
10168            .chunk_by(|hunk| hunk.buffer_id);
10169        for (buffer_id, hunks) in &chunk_by {
10170            let hunks = hunks.collect::<Vec<_>>();
10171            for hunk in &hunks {
10172                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10173            }
10174            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10175        }
10176        drop(chunk_by);
10177        if !revert_changes.is_empty() {
10178            self.transact(window, cx, |editor, window, cx| {
10179                editor.restore(revert_changes, window, cx);
10180            });
10181        }
10182    }
10183
10184    pub fn open_active_item_in_terminal(
10185        &mut self,
10186        _: &OpenInTerminal,
10187        window: &mut Window,
10188        cx: &mut Context<Self>,
10189    ) {
10190        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10191            let project_path = buffer.read(cx).project_path(cx)?;
10192            let project = self.project.as_ref()?.read(cx);
10193            let entry = project.entry_for_path(&project_path, cx)?;
10194            let parent = match &entry.canonical_path {
10195                Some(canonical_path) => canonical_path.to_path_buf(),
10196                None => project.absolute_path(&project_path, cx)?,
10197            }
10198            .parent()?
10199            .to_path_buf();
10200            Some(parent)
10201        }) {
10202            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10203        }
10204    }
10205
10206    fn set_breakpoint_context_menu(
10207        &mut self,
10208        display_row: DisplayRow,
10209        position: Option<Anchor>,
10210        clicked_point: gpui::Point<Pixels>,
10211        window: &mut Window,
10212        cx: &mut Context<Self>,
10213    ) {
10214        let source = self
10215            .buffer
10216            .read(cx)
10217            .snapshot(cx)
10218            .anchor_before(Point::new(display_row.0, 0u32));
10219
10220        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10221
10222        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10223            self,
10224            source,
10225            clicked_point,
10226            context_menu,
10227            window,
10228            cx,
10229        );
10230    }
10231
10232    fn add_edit_breakpoint_block(
10233        &mut self,
10234        anchor: Anchor,
10235        breakpoint: &Breakpoint,
10236        edit_action: BreakpointPromptEditAction,
10237        window: &mut Window,
10238        cx: &mut Context<Self>,
10239    ) {
10240        let weak_editor = cx.weak_entity();
10241        let bp_prompt = cx.new(|cx| {
10242            BreakpointPromptEditor::new(
10243                weak_editor,
10244                anchor,
10245                breakpoint.clone(),
10246                edit_action,
10247                window,
10248                cx,
10249            )
10250        });
10251
10252        let height = bp_prompt.update(cx, |this, cx| {
10253            this.prompt
10254                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10255        });
10256        let cloned_prompt = bp_prompt.clone();
10257        let blocks = vec![BlockProperties {
10258            style: BlockStyle::Sticky,
10259            placement: BlockPlacement::Above(anchor),
10260            height: Some(height),
10261            render: Arc::new(move |cx| {
10262                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10263                cloned_prompt.clone().into_any_element()
10264            }),
10265            priority: 0,
10266            render_in_minimap: true,
10267        }];
10268
10269        let focus_handle = bp_prompt.focus_handle(cx);
10270        window.focus(&focus_handle);
10271
10272        let block_ids = self.insert_blocks(blocks, None, cx);
10273        bp_prompt.update(cx, |prompt, _| {
10274            prompt.add_block_ids(block_ids);
10275        });
10276    }
10277
10278    pub(crate) fn breakpoint_at_row(
10279        &self,
10280        row: u32,
10281        window: &mut Window,
10282        cx: &mut Context<Self>,
10283    ) -> Option<(Anchor, Breakpoint)> {
10284        let snapshot = self.snapshot(window, cx);
10285        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10286
10287        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10288    }
10289
10290    pub(crate) fn breakpoint_at_anchor(
10291        &self,
10292        breakpoint_position: Anchor,
10293        snapshot: &EditorSnapshot,
10294        cx: &mut Context<Self>,
10295    ) -> Option<(Anchor, Breakpoint)> {
10296        let project = self.project.clone()?;
10297
10298        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10299            snapshot
10300                .buffer_snapshot
10301                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10302        })?;
10303
10304        let enclosing_excerpt = breakpoint_position.excerpt_id;
10305        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10306        let buffer_snapshot = buffer.read(cx).snapshot();
10307
10308        let row = buffer_snapshot
10309            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10310            .row;
10311
10312        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10313        let anchor_end = snapshot
10314            .buffer_snapshot
10315            .anchor_after(Point::new(row, line_len));
10316
10317        let bp = self
10318            .breakpoint_store
10319            .as_ref()?
10320            .read_with(cx, |breakpoint_store, cx| {
10321                breakpoint_store
10322                    .breakpoints(
10323                        &buffer,
10324                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10325                        &buffer_snapshot,
10326                        cx,
10327                    )
10328                    .next()
10329                    .and_then(|(bp, _)| {
10330                        let breakpoint_row = buffer_snapshot
10331                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10332                            .row;
10333
10334                        if breakpoint_row == row {
10335                            snapshot
10336                                .buffer_snapshot
10337                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10338                                .map(|position| (position, bp.bp.clone()))
10339                        } else {
10340                            None
10341                        }
10342                    })
10343            });
10344        bp
10345    }
10346
10347    pub fn edit_log_breakpoint(
10348        &mut self,
10349        _: &EditLogBreakpoint,
10350        window: &mut Window,
10351        cx: &mut Context<Self>,
10352    ) {
10353        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10354            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10355                message: None,
10356                state: BreakpointState::Enabled,
10357                condition: None,
10358                hit_condition: None,
10359            });
10360
10361            self.add_edit_breakpoint_block(
10362                anchor,
10363                &breakpoint,
10364                BreakpointPromptEditAction::Log,
10365                window,
10366                cx,
10367            );
10368        }
10369    }
10370
10371    fn breakpoints_at_cursors(
10372        &self,
10373        window: &mut Window,
10374        cx: &mut Context<Self>,
10375    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10376        let snapshot = self.snapshot(window, cx);
10377        let cursors = self
10378            .selections
10379            .disjoint_anchors()
10380            .into_iter()
10381            .map(|selection| {
10382                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10383
10384                let breakpoint_position = self
10385                    .breakpoint_at_row(cursor_position.row, window, cx)
10386                    .map(|bp| bp.0)
10387                    .unwrap_or_else(|| {
10388                        snapshot
10389                            .display_snapshot
10390                            .buffer_snapshot
10391                            .anchor_after(Point::new(cursor_position.row, 0))
10392                    });
10393
10394                let breakpoint = self
10395                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10396                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10397
10398                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10399            })
10400            // 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.
10401            .collect::<HashMap<Anchor, _>>();
10402
10403        cursors.into_iter().collect()
10404    }
10405
10406    pub fn enable_breakpoint(
10407        &mut self,
10408        _: &crate::actions::EnableBreakpoint,
10409        window: &mut Window,
10410        cx: &mut Context<Self>,
10411    ) {
10412        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10413            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10414                continue;
10415            };
10416            self.edit_breakpoint_at_anchor(
10417                anchor,
10418                breakpoint,
10419                BreakpointEditAction::InvertState,
10420                cx,
10421            );
10422        }
10423    }
10424
10425    pub fn disable_breakpoint(
10426        &mut self,
10427        _: &crate::actions::DisableBreakpoint,
10428        window: &mut Window,
10429        cx: &mut Context<Self>,
10430    ) {
10431        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10432            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10433                continue;
10434            };
10435            self.edit_breakpoint_at_anchor(
10436                anchor,
10437                breakpoint,
10438                BreakpointEditAction::InvertState,
10439                cx,
10440            );
10441        }
10442    }
10443
10444    pub fn toggle_breakpoint(
10445        &mut self,
10446        _: &crate::actions::ToggleBreakpoint,
10447        window: &mut Window,
10448        cx: &mut Context<Self>,
10449    ) {
10450        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10451            if let Some(breakpoint) = breakpoint {
10452                self.edit_breakpoint_at_anchor(
10453                    anchor,
10454                    breakpoint,
10455                    BreakpointEditAction::Toggle,
10456                    cx,
10457                );
10458            } else {
10459                self.edit_breakpoint_at_anchor(
10460                    anchor,
10461                    Breakpoint::new_standard(),
10462                    BreakpointEditAction::Toggle,
10463                    cx,
10464                );
10465            }
10466        }
10467    }
10468
10469    pub fn edit_breakpoint_at_anchor(
10470        &mut self,
10471        breakpoint_position: Anchor,
10472        breakpoint: Breakpoint,
10473        edit_action: BreakpointEditAction,
10474        cx: &mut Context<Self>,
10475    ) {
10476        let Some(breakpoint_store) = &self.breakpoint_store else {
10477            return;
10478        };
10479
10480        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10481            if breakpoint_position == Anchor::min() {
10482                self.buffer()
10483                    .read(cx)
10484                    .excerpt_buffer_ids()
10485                    .into_iter()
10486                    .next()
10487            } else {
10488                None
10489            }
10490        }) else {
10491            return;
10492        };
10493
10494        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10495            return;
10496        };
10497
10498        breakpoint_store.update(cx, |breakpoint_store, cx| {
10499            breakpoint_store.toggle_breakpoint(
10500                buffer,
10501                BreakpointWithPosition {
10502                    position: breakpoint_position.text_anchor,
10503                    bp: breakpoint,
10504                },
10505                edit_action,
10506                cx,
10507            );
10508        });
10509
10510        cx.notify();
10511    }
10512
10513    #[cfg(any(test, feature = "test-support"))]
10514    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10515        self.breakpoint_store.clone()
10516    }
10517
10518    pub fn prepare_restore_change(
10519        &self,
10520        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10521        hunk: &MultiBufferDiffHunk,
10522        cx: &mut App,
10523    ) -> Option<()> {
10524        if hunk.is_created_file() {
10525            return None;
10526        }
10527        let buffer = self.buffer.read(cx);
10528        let diff = buffer.diff_for(hunk.buffer_id)?;
10529        let buffer = buffer.buffer(hunk.buffer_id)?;
10530        let buffer = buffer.read(cx);
10531        let original_text = diff
10532            .read(cx)
10533            .base_text()
10534            .as_rope()
10535            .slice(hunk.diff_base_byte_range.clone());
10536        let buffer_snapshot = buffer.snapshot();
10537        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10538        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10539            probe
10540                .0
10541                .start
10542                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10543                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10544        }) {
10545            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10546            Some(())
10547        } else {
10548            None
10549        }
10550    }
10551
10552    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10553        self.manipulate_lines(window, cx, |lines| lines.reverse())
10554    }
10555
10556    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10557        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10558    }
10559
10560    fn manipulate_lines<Fn>(
10561        &mut self,
10562        window: &mut Window,
10563        cx: &mut Context<Self>,
10564        mut callback: Fn,
10565    ) where
10566        Fn: FnMut(&mut Vec<&str>),
10567    {
10568        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10569
10570        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10571        let buffer = self.buffer.read(cx).snapshot(cx);
10572
10573        let mut edits = Vec::new();
10574
10575        let selections = self.selections.all::<Point>(cx);
10576        let mut selections = selections.iter().peekable();
10577        let mut contiguous_row_selections = Vec::new();
10578        let mut new_selections = Vec::new();
10579        let mut added_lines = 0;
10580        let mut removed_lines = 0;
10581
10582        while let Some(selection) = selections.next() {
10583            let (start_row, end_row) = consume_contiguous_rows(
10584                &mut contiguous_row_selections,
10585                selection,
10586                &display_map,
10587                &mut selections,
10588            );
10589
10590            let start_point = Point::new(start_row.0, 0);
10591            let end_point = Point::new(
10592                end_row.previous_row().0,
10593                buffer.line_len(end_row.previous_row()),
10594            );
10595            let text = buffer
10596                .text_for_range(start_point..end_point)
10597                .collect::<String>();
10598
10599            let mut lines = text.split('\n').collect_vec();
10600
10601            let lines_before = lines.len();
10602            callback(&mut lines);
10603            let lines_after = lines.len();
10604
10605            edits.push((start_point..end_point, lines.join("\n")));
10606
10607            // Selections must change based on added and removed line count
10608            let start_row =
10609                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10610            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10611            new_selections.push(Selection {
10612                id: selection.id,
10613                start: start_row,
10614                end: end_row,
10615                goal: SelectionGoal::None,
10616                reversed: selection.reversed,
10617            });
10618
10619            if lines_after > lines_before {
10620                added_lines += lines_after - lines_before;
10621            } else if lines_before > lines_after {
10622                removed_lines += lines_before - lines_after;
10623            }
10624        }
10625
10626        self.transact(window, cx, |this, window, cx| {
10627            let buffer = this.buffer.update(cx, |buffer, cx| {
10628                buffer.edit(edits, None, cx);
10629                buffer.snapshot(cx)
10630            });
10631
10632            // Recalculate offsets on newly edited buffer
10633            let new_selections = new_selections
10634                .iter()
10635                .map(|s| {
10636                    let start_point = Point::new(s.start.0, 0);
10637                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10638                    Selection {
10639                        id: s.id,
10640                        start: buffer.point_to_offset(start_point),
10641                        end: buffer.point_to_offset(end_point),
10642                        goal: s.goal,
10643                        reversed: s.reversed,
10644                    }
10645                })
10646                .collect();
10647
10648            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10649                s.select(new_selections);
10650            });
10651
10652            this.request_autoscroll(Autoscroll::fit(), cx);
10653        });
10654    }
10655
10656    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10657        self.manipulate_text(window, cx, |text| {
10658            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10659            if has_upper_case_characters {
10660                text.to_lowercase()
10661            } else {
10662                text.to_uppercase()
10663            }
10664        })
10665    }
10666
10667    pub fn convert_to_upper_case(
10668        &mut self,
10669        _: &ConvertToUpperCase,
10670        window: &mut Window,
10671        cx: &mut Context<Self>,
10672    ) {
10673        self.manipulate_text(window, cx, |text| text.to_uppercase())
10674    }
10675
10676    pub fn convert_to_lower_case(
10677        &mut self,
10678        _: &ConvertToLowerCase,
10679        window: &mut Window,
10680        cx: &mut Context<Self>,
10681    ) {
10682        self.manipulate_text(window, cx, |text| text.to_lowercase())
10683    }
10684
10685    pub fn convert_to_title_case(
10686        &mut self,
10687        _: &ConvertToTitleCase,
10688        window: &mut Window,
10689        cx: &mut Context<Self>,
10690    ) {
10691        self.manipulate_text(window, cx, |text| {
10692            text.split('\n')
10693                .map(|line| line.to_case(Case::Title))
10694                .join("\n")
10695        })
10696    }
10697
10698    pub fn convert_to_snake_case(
10699        &mut self,
10700        _: &ConvertToSnakeCase,
10701        window: &mut Window,
10702        cx: &mut Context<Self>,
10703    ) {
10704        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10705    }
10706
10707    pub fn convert_to_kebab_case(
10708        &mut self,
10709        _: &ConvertToKebabCase,
10710        window: &mut Window,
10711        cx: &mut Context<Self>,
10712    ) {
10713        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10714    }
10715
10716    pub fn convert_to_upper_camel_case(
10717        &mut self,
10718        _: &ConvertToUpperCamelCase,
10719        window: &mut Window,
10720        cx: &mut Context<Self>,
10721    ) {
10722        self.manipulate_text(window, cx, |text| {
10723            text.split('\n')
10724                .map(|line| line.to_case(Case::UpperCamel))
10725                .join("\n")
10726        })
10727    }
10728
10729    pub fn convert_to_lower_camel_case(
10730        &mut self,
10731        _: &ConvertToLowerCamelCase,
10732        window: &mut Window,
10733        cx: &mut Context<Self>,
10734    ) {
10735        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10736    }
10737
10738    pub fn convert_to_opposite_case(
10739        &mut self,
10740        _: &ConvertToOppositeCase,
10741        window: &mut Window,
10742        cx: &mut Context<Self>,
10743    ) {
10744        self.manipulate_text(window, cx, |text| {
10745            text.chars()
10746                .fold(String::with_capacity(text.len()), |mut t, c| {
10747                    if c.is_uppercase() {
10748                        t.extend(c.to_lowercase());
10749                    } else {
10750                        t.extend(c.to_uppercase());
10751                    }
10752                    t
10753                })
10754        })
10755    }
10756
10757    pub fn convert_to_rot13(
10758        &mut self,
10759        _: &ConvertToRot13,
10760        window: &mut Window,
10761        cx: &mut Context<Self>,
10762    ) {
10763        self.manipulate_text(window, cx, |text| {
10764            text.chars()
10765                .map(|c| match c {
10766                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10767                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10768                    _ => c,
10769                })
10770                .collect()
10771        })
10772    }
10773
10774    pub fn convert_to_rot47(
10775        &mut self,
10776        _: &ConvertToRot47,
10777        window: &mut Window,
10778        cx: &mut Context<Self>,
10779    ) {
10780        self.manipulate_text(window, cx, |text| {
10781            text.chars()
10782                .map(|c| {
10783                    let code_point = c as u32;
10784                    if code_point >= 33 && code_point <= 126 {
10785                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10786                    }
10787                    c
10788                })
10789                .collect()
10790        })
10791    }
10792
10793    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10794    where
10795        Fn: FnMut(&str) -> String,
10796    {
10797        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10798        let buffer = self.buffer.read(cx).snapshot(cx);
10799
10800        let mut new_selections = Vec::new();
10801        let mut edits = Vec::new();
10802        let mut selection_adjustment = 0i32;
10803
10804        for selection in self.selections.all::<usize>(cx) {
10805            let selection_is_empty = selection.is_empty();
10806
10807            let (start, end) = if selection_is_empty {
10808                let word_range = movement::surrounding_word(
10809                    &display_map,
10810                    selection.start.to_display_point(&display_map),
10811                );
10812                let start = word_range.start.to_offset(&display_map, Bias::Left);
10813                let end = word_range.end.to_offset(&display_map, Bias::Left);
10814                (start, end)
10815            } else {
10816                (selection.start, selection.end)
10817            };
10818
10819            let text = buffer.text_for_range(start..end).collect::<String>();
10820            let old_length = text.len() as i32;
10821            let text = callback(&text);
10822
10823            new_selections.push(Selection {
10824                start: (start as i32 - selection_adjustment) as usize,
10825                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10826                goal: SelectionGoal::None,
10827                ..selection
10828            });
10829
10830            selection_adjustment += old_length - text.len() as i32;
10831
10832            edits.push((start..end, text));
10833        }
10834
10835        self.transact(window, cx, |this, window, cx| {
10836            this.buffer.update(cx, |buffer, cx| {
10837                buffer.edit(edits, None, cx);
10838            });
10839
10840            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10841                s.select(new_selections);
10842            });
10843
10844            this.request_autoscroll(Autoscroll::fit(), cx);
10845        });
10846    }
10847
10848    pub fn move_selection_on_drop(
10849        &mut self,
10850        selection: &Selection<Anchor>,
10851        target: DisplayPoint,
10852        is_cut: bool,
10853        window: &mut Window,
10854        cx: &mut Context<Self>,
10855    ) {
10856        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10857        let buffer = &display_map.buffer_snapshot;
10858        let mut edits = Vec::new();
10859        let insert_point = display_map
10860            .clip_point(target, Bias::Left)
10861            .to_point(&display_map);
10862        let text = buffer
10863            .text_for_range(selection.start..selection.end)
10864            .collect::<String>();
10865        if is_cut {
10866            edits.push(((selection.start..selection.end), String::new()));
10867        }
10868        let insert_anchor = buffer.anchor_before(insert_point);
10869        edits.push(((insert_anchor..insert_anchor), text));
10870        let last_edit_start = insert_anchor.bias_left(buffer);
10871        let last_edit_end = insert_anchor.bias_right(buffer);
10872        self.transact(window, cx, |this, window, cx| {
10873            this.buffer.update(cx, |buffer, cx| {
10874                buffer.edit(edits, None, cx);
10875            });
10876            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10877                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10878            });
10879        });
10880    }
10881
10882    pub fn clear_selection_drag_state(&mut self) {
10883        self.selection_drag_state = SelectionDragState::None;
10884    }
10885
10886    pub fn duplicate(
10887        &mut self,
10888        upwards: bool,
10889        whole_lines: bool,
10890        window: &mut Window,
10891        cx: &mut Context<Self>,
10892    ) {
10893        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10894
10895        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10896        let buffer = &display_map.buffer_snapshot;
10897        let selections = self.selections.all::<Point>(cx);
10898
10899        let mut edits = Vec::new();
10900        let mut selections_iter = selections.iter().peekable();
10901        while let Some(selection) = selections_iter.next() {
10902            let mut rows = selection.spanned_rows(false, &display_map);
10903            // duplicate line-wise
10904            if whole_lines || selection.start == selection.end {
10905                // Avoid duplicating the same lines twice.
10906                while let Some(next_selection) = selections_iter.peek() {
10907                    let next_rows = next_selection.spanned_rows(false, &display_map);
10908                    if next_rows.start < rows.end {
10909                        rows.end = next_rows.end;
10910                        selections_iter.next().unwrap();
10911                    } else {
10912                        break;
10913                    }
10914                }
10915
10916                // Copy the text from the selected row region and splice it either at the start
10917                // or end of the region.
10918                let start = Point::new(rows.start.0, 0);
10919                let end = Point::new(
10920                    rows.end.previous_row().0,
10921                    buffer.line_len(rows.end.previous_row()),
10922                );
10923                let text = buffer
10924                    .text_for_range(start..end)
10925                    .chain(Some("\n"))
10926                    .collect::<String>();
10927                let insert_location = if upwards {
10928                    Point::new(rows.end.0, 0)
10929                } else {
10930                    start
10931                };
10932                edits.push((insert_location..insert_location, text));
10933            } else {
10934                // duplicate character-wise
10935                let start = selection.start;
10936                let end = selection.end;
10937                let text = buffer.text_for_range(start..end).collect::<String>();
10938                edits.push((selection.end..selection.end, text));
10939            }
10940        }
10941
10942        self.transact(window, cx, |this, _, cx| {
10943            this.buffer.update(cx, |buffer, cx| {
10944                buffer.edit(edits, None, cx);
10945            });
10946
10947            this.request_autoscroll(Autoscroll::fit(), cx);
10948        });
10949    }
10950
10951    pub fn duplicate_line_up(
10952        &mut self,
10953        _: &DuplicateLineUp,
10954        window: &mut Window,
10955        cx: &mut Context<Self>,
10956    ) {
10957        self.duplicate(true, true, window, cx);
10958    }
10959
10960    pub fn duplicate_line_down(
10961        &mut self,
10962        _: &DuplicateLineDown,
10963        window: &mut Window,
10964        cx: &mut Context<Self>,
10965    ) {
10966        self.duplicate(false, true, window, cx);
10967    }
10968
10969    pub fn duplicate_selection(
10970        &mut self,
10971        _: &DuplicateSelection,
10972        window: &mut Window,
10973        cx: &mut Context<Self>,
10974    ) {
10975        self.duplicate(false, false, window, cx);
10976    }
10977
10978    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10979        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10980        if self.mode.is_single_line() {
10981            cx.propagate();
10982            return;
10983        }
10984
10985        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10986        let buffer = self.buffer.read(cx).snapshot(cx);
10987
10988        let mut edits = Vec::new();
10989        let mut unfold_ranges = Vec::new();
10990        let mut refold_creases = Vec::new();
10991
10992        let selections = self.selections.all::<Point>(cx);
10993        let mut selections = selections.iter().peekable();
10994        let mut contiguous_row_selections = Vec::new();
10995        let mut new_selections = Vec::new();
10996
10997        while let Some(selection) = selections.next() {
10998            // Find all the selections that span a contiguous row range
10999            let (start_row, end_row) = consume_contiguous_rows(
11000                &mut contiguous_row_selections,
11001                selection,
11002                &display_map,
11003                &mut selections,
11004            );
11005
11006            // Move the text spanned by the row range to be before the line preceding the row range
11007            if start_row.0 > 0 {
11008                let range_to_move = Point::new(
11009                    start_row.previous_row().0,
11010                    buffer.line_len(start_row.previous_row()),
11011                )
11012                    ..Point::new(
11013                        end_row.previous_row().0,
11014                        buffer.line_len(end_row.previous_row()),
11015                    );
11016                let insertion_point = display_map
11017                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11018                    .0;
11019
11020                // Don't move lines across excerpts
11021                if buffer
11022                    .excerpt_containing(insertion_point..range_to_move.end)
11023                    .is_some()
11024                {
11025                    let text = buffer
11026                        .text_for_range(range_to_move.clone())
11027                        .flat_map(|s| s.chars())
11028                        .skip(1)
11029                        .chain(['\n'])
11030                        .collect::<String>();
11031
11032                    edits.push((
11033                        buffer.anchor_after(range_to_move.start)
11034                            ..buffer.anchor_before(range_to_move.end),
11035                        String::new(),
11036                    ));
11037                    let insertion_anchor = buffer.anchor_after(insertion_point);
11038                    edits.push((insertion_anchor..insertion_anchor, text));
11039
11040                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11041
11042                    // Move selections up
11043                    new_selections.extend(contiguous_row_selections.drain(..).map(
11044                        |mut selection| {
11045                            selection.start.row -= row_delta;
11046                            selection.end.row -= row_delta;
11047                            selection
11048                        },
11049                    ));
11050
11051                    // Move folds up
11052                    unfold_ranges.push(range_to_move.clone());
11053                    for fold in display_map.folds_in_range(
11054                        buffer.anchor_before(range_to_move.start)
11055                            ..buffer.anchor_after(range_to_move.end),
11056                    ) {
11057                        let mut start = fold.range.start.to_point(&buffer);
11058                        let mut end = fold.range.end.to_point(&buffer);
11059                        start.row -= row_delta;
11060                        end.row -= row_delta;
11061                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11062                    }
11063                }
11064            }
11065
11066            // If we didn't move line(s), preserve the existing selections
11067            new_selections.append(&mut contiguous_row_selections);
11068        }
11069
11070        self.transact(window, cx, |this, window, cx| {
11071            this.unfold_ranges(&unfold_ranges, true, true, cx);
11072            this.buffer.update(cx, |buffer, cx| {
11073                for (range, text) in edits {
11074                    buffer.edit([(range, text)], None, cx);
11075                }
11076            });
11077            this.fold_creases(refold_creases, true, window, cx);
11078            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11079                s.select(new_selections);
11080            })
11081        });
11082    }
11083
11084    pub fn move_line_down(
11085        &mut self,
11086        _: &MoveLineDown,
11087        window: &mut Window,
11088        cx: &mut Context<Self>,
11089    ) {
11090        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11091        if self.mode.is_single_line() {
11092            cx.propagate();
11093            return;
11094        }
11095
11096        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11097        let buffer = self.buffer.read(cx).snapshot(cx);
11098
11099        let mut edits = Vec::new();
11100        let mut unfold_ranges = Vec::new();
11101        let mut refold_creases = Vec::new();
11102
11103        let selections = self.selections.all::<Point>(cx);
11104        let mut selections = selections.iter().peekable();
11105        let mut contiguous_row_selections = Vec::new();
11106        let mut new_selections = Vec::new();
11107
11108        while let Some(selection) = selections.next() {
11109            // Find all the selections that span a contiguous row range
11110            let (start_row, end_row) = consume_contiguous_rows(
11111                &mut contiguous_row_selections,
11112                selection,
11113                &display_map,
11114                &mut selections,
11115            );
11116
11117            // Move the text spanned by the row range to be after the last line of the row range
11118            if end_row.0 <= buffer.max_point().row {
11119                let range_to_move =
11120                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11121                let insertion_point = display_map
11122                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11123                    .0;
11124
11125                // Don't move lines across excerpt boundaries
11126                if buffer
11127                    .excerpt_containing(range_to_move.start..insertion_point)
11128                    .is_some()
11129                {
11130                    let mut text = String::from("\n");
11131                    text.extend(buffer.text_for_range(range_to_move.clone()));
11132                    text.pop(); // Drop trailing newline
11133                    edits.push((
11134                        buffer.anchor_after(range_to_move.start)
11135                            ..buffer.anchor_before(range_to_move.end),
11136                        String::new(),
11137                    ));
11138                    let insertion_anchor = buffer.anchor_after(insertion_point);
11139                    edits.push((insertion_anchor..insertion_anchor, text));
11140
11141                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11142
11143                    // Move selections down
11144                    new_selections.extend(contiguous_row_selections.drain(..).map(
11145                        |mut selection| {
11146                            selection.start.row += row_delta;
11147                            selection.end.row += row_delta;
11148                            selection
11149                        },
11150                    ));
11151
11152                    // Move folds down
11153                    unfold_ranges.push(range_to_move.clone());
11154                    for fold in display_map.folds_in_range(
11155                        buffer.anchor_before(range_to_move.start)
11156                            ..buffer.anchor_after(range_to_move.end),
11157                    ) {
11158                        let mut start = fold.range.start.to_point(&buffer);
11159                        let mut end = fold.range.end.to_point(&buffer);
11160                        start.row += row_delta;
11161                        end.row += row_delta;
11162                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11163                    }
11164                }
11165            }
11166
11167            // If we didn't move line(s), preserve the existing selections
11168            new_selections.append(&mut contiguous_row_selections);
11169        }
11170
11171        self.transact(window, cx, |this, window, cx| {
11172            this.unfold_ranges(&unfold_ranges, true, true, cx);
11173            this.buffer.update(cx, |buffer, cx| {
11174                for (range, text) in edits {
11175                    buffer.edit([(range, text)], None, cx);
11176                }
11177            });
11178            this.fold_creases(refold_creases, true, window, cx);
11179            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11180                s.select(new_selections)
11181            });
11182        });
11183    }
11184
11185    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11186        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11187        let text_layout_details = &self.text_layout_details(window);
11188        self.transact(window, cx, |this, window, cx| {
11189            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11190                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11191                s.move_with(|display_map, selection| {
11192                    if !selection.is_empty() {
11193                        return;
11194                    }
11195
11196                    let mut head = selection.head();
11197                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11198                    if head.column() == display_map.line_len(head.row()) {
11199                        transpose_offset = display_map
11200                            .buffer_snapshot
11201                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11202                    }
11203
11204                    if transpose_offset == 0 {
11205                        return;
11206                    }
11207
11208                    *head.column_mut() += 1;
11209                    head = display_map.clip_point(head, Bias::Right);
11210                    let goal = SelectionGoal::HorizontalPosition(
11211                        display_map
11212                            .x_for_display_point(head, text_layout_details)
11213                            .into(),
11214                    );
11215                    selection.collapse_to(head, goal);
11216
11217                    let transpose_start = display_map
11218                        .buffer_snapshot
11219                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11220                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11221                        let transpose_end = display_map
11222                            .buffer_snapshot
11223                            .clip_offset(transpose_offset + 1, Bias::Right);
11224                        if let Some(ch) =
11225                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11226                        {
11227                            edits.push((transpose_start..transpose_offset, String::new()));
11228                            edits.push((transpose_end..transpose_end, ch.to_string()));
11229                        }
11230                    }
11231                });
11232                edits
11233            });
11234            this.buffer
11235                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11236            let selections = this.selections.all::<usize>(cx);
11237            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11238                s.select(selections);
11239            });
11240        });
11241    }
11242
11243    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11244        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11245        if self.mode.is_single_line() {
11246            cx.propagate();
11247            return;
11248        }
11249
11250        self.rewrap_impl(RewrapOptions::default(), cx)
11251    }
11252
11253    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11254        let buffer = self.buffer.read(cx).snapshot(cx);
11255        let selections = self.selections.all::<Point>(cx);
11256
11257        // Shrink and split selections to respect paragraph boundaries.
11258        let ranges = selections.into_iter().flat_map(|selection| {
11259            let language_settings = buffer.language_settings_at(selection.head(), cx);
11260            let language_scope = buffer.language_scope_at(selection.head());
11261
11262            let Some(start_row) = (selection.start.row..=selection.end.row)
11263                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11264            else {
11265                return vec![];
11266            };
11267            let Some(end_row) = (selection.start.row..=selection.end.row)
11268                .rev()
11269                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11270            else {
11271                return vec![];
11272            };
11273
11274            let mut row = start_row;
11275            let mut ranges = Vec::new();
11276            while let Some(blank_row) =
11277                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11278            {
11279                let next_paragraph_start = (blank_row + 1..=end_row)
11280                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11281                    .unwrap();
11282                ranges.push((
11283                    language_settings.clone(),
11284                    language_scope.clone(),
11285                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11286                ));
11287                row = next_paragraph_start;
11288            }
11289            ranges.push((
11290                language_settings.clone(),
11291                language_scope.clone(),
11292                Point::new(row, 0)..Point::new(end_row, 0),
11293            ));
11294
11295            ranges
11296        });
11297
11298        let mut edits = Vec::new();
11299        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11300
11301        for (language_settings, language_scope, range) in ranges {
11302            let mut start_row = range.start.row;
11303            let mut end_row = range.end.row;
11304
11305            // Skip selections that overlap with a range that has already been rewrapped.
11306            let selection_range = start_row..end_row;
11307            if rewrapped_row_ranges
11308                .iter()
11309                .any(|range| range.overlaps(&selection_range))
11310            {
11311                continue;
11312            }
11313
11314            let tab_size = language_settings.tab_size;
11315
11316            // Since not all lines in the selection may be at the same indent
11317            // level, choose the indent size that is the most common between all
11318            // of the lines.
11319            //
11320            // If there is a tie, we use the deepest indent.
11321            let (indent_size, indent_end) = {
11322                let mut indent_size_occurrences = HashMap::default();
11323                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11324
11325                for row in start_row..=end_row {
11326                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11327                    rows_by_indent_size.entry(indent).or_default().push(row);
11328                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11329                }
11330
11331                let indent_size = indent_size_occurrences
11332                    .into_iter()
11333                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11334                    .map(|(indent, _)| indent)
11335                    .unwrap_or_default();
11336                let row = rows_by_indent_size[&indent_size][0];
11337                let indent_end = Point::new(row, indent_size.len);
11338
11339                (indent_size, indent_end)
11340            };
11341
11342            let mut line_prefix = indent_size.chars().collect::<String>();
11343
11344            let mut inside_comment = false;
11345            if let Some(comment_prefix) = language_scope.and_then(|language| {
11346                language
11347                    .line_comment_prefixes()
11348                    .iter()
11349                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11350                    .cloned()
11351            }) {
11352                line_prefix.push_str(&comment_prefix);
11353                inside_comment = true;
11354            }
11355
11356            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11357                RewrapBehavior::InComments => inside_comment,
11358                RewrapBehavior::InSelections => !range.is_empty(),
11359                RewrapBehavior::Anywhere => true,
11360            };
11361
11362            let should_rewrap = options.override_language_settings
11363                || allow_rewrap_based_on_language
11364                || self.hard_wrap.is_some();
11365            if !should_rewrap {
11366                continue;
11367            }
11368
11369            if range.is_empty() {
11370                'expand_upwards: while start_row > 0 {
11371                    let prev_row = start_row - 1;
11372                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11373                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11374                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11375                    {
11376                        start_row = prev_row;
11377                    } else {
11378                        break 'expand_upwards;
11379                    }
11380                }
11381
11382                'expand_downwards: while end_row < buffer.max_point().row {
11383                    let next_row = end_row + 1;
11384                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11385                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11386                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11387                    {
11388                        end_row = next_row;
11389                    } else {
11390                        break 'expand_downwards;
11391                    }
11392                }
11393            }
11394
11395            let start = Point::new(start_row, 0);
11396            let start_offset = start.to_offset(&buffer);
11397            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11398            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11399            let Some(lines_without_prefixes) = selection_text
11400                .lines()
11401                .map(|line| {
11402                    line.strip_prefix(&line_prefix)
11403                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11404                        .with_context(|| {
11405                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11406                        })
11407                })
11408                .collect::<Result<Vec<_>, _>>()
11409                .log_err()
11410            else {
11411                continue;
11412            };
11413
11414            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11415                buffer
11416                    .language_settings_at(Point::new(start_row, 0), cx)
11417                    .preferred_line_length as usize
11418            });
11419            let wrapped_text = wrap_with_prefix(
11420                line_prefix,
11421                lines_without_prefixes.join("\n"),
11422                wrap_column,
11423                tab_size,
11424                options.preserve_existing_whitespace,
11425            );
11426
11427            // TODO: should always use char-based diff while still supporting cursor behavior that
11428            // matches vim.
11429            let mut diff_options = DiffOptions::default();
11430            if options.override_language_settings {
11431                diff_options.max_word_diff_len = 0;
11432                diff_options.max_word_diff_line_count = 0;
11433            } else {
11434                diff_options.max_word_diff_len = usize::MAX;
11435                diff_options.max_word_diff_line_count = usize::MAX;
11436            }
11437
11438            for (old_range, new_text) in
11439                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11440            {
11441                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11442                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11443                edits.push((edit_start..edit_end, new_text));
11444            }
11445
11446            rewrapped_row_ranges.push(start_row..=end_row);
11447        }
11448
11449        self.buffer
11450            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11451    }
11452
11453    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11454        let mut text = String::new();
11455        let buffer = self.buffer.read(cx).snapshot(cx);
11456        let mut selections = self.selections.all::<Point>(cx);
11457        let mut clipboard_selections = Vec::with_capacity(selections.len());
11458        {
11459            let max_point = buffer.max_point();
11460            let mut is_first = true;
11461            for selection in &mut selections {
11462                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11463                if is_entire_line {
11464                    selection.start = Point::new(selection.start.row, 0);
11465                    if !selection.is_empty() && selection.end.column == 0 {
11466                        selection.end = cmp::min(max_point, selection.end);
11467                    } else {
11468                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11469                    }
11470                    selection.goal = SelectionGoal::None;
11471                }
11472                if is_first {
11473                    is_first = false;
11474                } else {
11475                    text += "\n";
11476                }
11477                let mut len = 0;
11478                for chunk in buffer.text_for_range(selection.start..selection.end) {
11479                    text.push_str(chunk);
11480                    len += chunk.len();
11481                }
11482                clipboard_selections.push(ClipboardSelection {
11483                    len,
11484                    is_entire_line,
11485                    first_line_indent: buffer
11486                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11487                        .len,
11488                });
11489            }
11490        }
11491
11492        self.transact(window, cx, |this, window, cx| {
11493            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11494                s.select(selections);
11495            });
11496            this.insert("", window, cx);
11497        });
11498        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11499    }
11500
11501    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11502        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11503        let item = self.cut_common(window, cx);
11504        cx.write_to_clipboard(item);
11505    }
11506
11507    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11508        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11509        self.change_selections(None, window, cx, |s| {
11510            s.move_with(|snapshot, sel| {
11511                if sel.is_empty() {
11512                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11513                }
11514            });
11515        });
11516        let item = self.cut_common(window, cx);
11517        cx.set_global(KillRing(item))
11518    }
11519
11520    pub fn kill_ring_yank(
11521        &mut self,
11522        _: &KillRingYank,
11523        window: &mut Window,
11524        cx: &mut Context<Self>,
11525    ) {
11526        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11527        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11528            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11529                (kill_ring.text().to_string(), kill_ring.metadata_json())
11530            } else {
11531                return;
11532            }
11533        } else {
11534            return;
11535        };
11536        self.do_paste(&text, metadata, false, window, cx);
11537    }
11538
11539    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11540        self.do_copy(true, cx);
11541    }
11542
11543    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11544        self.do_copy(false, cx);
11545    }
11546
11547    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11548        let selections = self.selections.all::<Point>(cx);
11549        let buffer = self.buffer.read(cx).read(cx);
11550        let mut text = String::new();
11551
11552        let mut clipboard_selections = Vec::with_capacity(selections.len());
11553        {
11554            let max_point = buffer.max_point();
11555            let mut is_first = true;
11556            for selection in &selections {
11557                let mut start = selection.start;
11558                let mut end = selection.end;
11559                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11560                if is_entire_line {
11561                    start = Point::new(start.row, 0);
11562                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11563                }
11564
11565                let mut trimmed_selections = Vec::new();
11566                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11567                    let row = MultiBufferRow(start.row);
11568                    let first_indent = buffer.indent_size_for_line(row);
11569                    if first_indent.len == 0 || start.column > first_indent.len {
11570                        trimmed_selections.push(start..end);
11571                    } else {
11572                        trimmed_selections.push(
11573                            Point::new(row.0, first_indent.len)
11574                                ..Point::new(row.0, buffer.line_len(row)),
11575                        );
11576                        for row in start.row + 1..=end.row {
11577                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11578                            if row == end.row {
11579                                line_len = end.column;
11580                            }
11581                            if line_len == 0 {
11582                                trimmed_selections
11583                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11584                                continue;
11585                            }
11586                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11587                            if row_indent_size.len >= first_indent.len {
11588                                trimmed_selections.push(
11589                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11590                                );
11591                            } else {
11592                                trimmed_selections.clear();
11593                                trimmed_selections.push(start..end);
11594                                break;
11595                            }
11596                        }
11597                    }
11598                } else {
11599                    trimmed_selections.push(start..end);
11600                }
11601
11602                for trimmed_range in trimmed_selections {
11603                    if is_first {
11604                        is_first = false;
11605                    } else {
11606                        text += "\n";
11607                    }
11608                    let mut len = 0;
11609                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11610                        text.push_str(chunk);
11611                        len += chunk.len();
11612                    }
11613                    clipboard_selections.push(ClipboardSelection {
11614                        len,
11615                        is_entire_line,
11616                        first_line_indent: buffer
11617                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11618                            .len,
11619                    });
11620                }
11621            }
11622        }
11623
11624        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11625            text,
11626            clipboard_selections,
11627        ));
11628    }
11629
11630    pub fn do_paste(
11631        &mut self,
11632        text: &String,
11633        clipboard_selections: Option<Vec<ClipboardSelection>>,
11634        handle_entire_lines: bool,
11635        window: &mut Window,
11636        cx: &mut Context<Self>,
11637    ) {
11638        if self.read_only(cx) {
11639            return;
11640        }
11641
11642        let clipboard_text = Cow::Borrowed(text);
11643
11644        self.transact(window, cx, |this, window, cx| {
11645            if let Some(mut clipboard_selections) = clipboard_selections {
11646                let old_selections = this.selections.all::<usize>(cx);
11647                let all_selections_were_entire_line =
11648                    clipboard_selections.iter().all(|s| s.is_entire_line);
11649                let first_selection_indent_column =
11650                    clipboard_selections.first().map(|s| s.first_line_indent);
11651                if clipboard_selections.len() != old_selections.len() {
11652                    clipboard_selections.drain(..);
11653                }
11654                let cursor_offset = this.selections.last::<usize>(cx).head();
11655                let mut auto_indent_on_paste = true;
11656
11657                this.buffer.update(cx, |buffer, cx| {
11658                    let snapshot = buffer.read(cx);
11659                    auto_indent_on_paste = snapshot
11660                        .language_settings_at(cursor_offset, cx)
11661                        .auto_indent_on_paste;
11662
11663                    let mut start_offset = 0;
11664                    let mut edits = Vec::new();
11665                    let mut original_indent_columns = Vec::new();
11666                    for (ix, selection) in old_selections.iter().enumerate() {
11667                        let to_insert;
11668                        let entire_line;
11669                        let original_indent_column;
11670                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11671                            let end_offset = start_offset + clipboard_selection.len;
11672                            to_insert = &clipboard_text[start_offset..end_offset];
11673                            entire_line = clipboard_selection.is_entire_line;
11674                            start_offset = end_offset + 1;
11675                            original_indent_column = Some(clipboard_selection.first_line_indent);
11676                        } else {
11677                            to_insert = clipboard_text.as_str();
11678                            entire_line = all_selections_were_entire_line;
11679                            original_indent_column = first_selection_indent_column
11680                        }
11681
11682                        // If the corresponding selection was empty when this slice of the
11683                        // clipboard text was written, then the entire line containing the
11684                        // selection was copied. If this selection is also currently empty,
11685                        // then paste the line before the current line of the buffer.
11686                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11687                            let column = selection.start.to_point(&snapshot).column as usize;
11688                            let line_start = selection.start - column;
11689                            line_start..line_start
11690                        } else {
11691                            selection.range()
11692                        };
11693
11694                        edits.push((range, to_insert));
11695                        original_indent_columns.push(original_indent_column);
11696                    }
11697                    drop(snapshot);
11698
11699                    buffer.edit(
11700                        edits,
11701                        if auto_indent_on_paste {
11702                            Some(AutoindentMode::Block {
11703                                original_indent_columns,
11704                            })
11705                        } else {
11706                            None
11707                        },
11708                        cx,
11709                    );
11710                });
11711
11712                let selections = this.selections.all::<usize>(cx);
11713                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11714                    s.select(selections)
11715                });
11716            } else {
11717                this.insert(&clipboard_text, window, cx);
11718            }
11719        });
11720    }
11721
11722    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11723        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11724        if let Some(item) = cx.read_from_clipboard() {
11725            let entries = item.entries();
11726
11727            match entries.first() {
11728                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11729                // of all the pasted entries.
11730                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11731                    .do_paste(
11732                        clipboard_string.text(),
11733                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11734                        true,
11735                        window,
11736                        cx,
11737                    ),
11738                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11739            }
11740        }
11741    }
11742
11743    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11744        if self.read_only(cx) {
11745            return;
11746        }
11747
11748        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11749
11750        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11751            if let Some((selections, _)) =
11752                self.selection_history.transaction(transaction_id).cloned()
11753            {
11754                self.change_selections(None, window, cx, |s| {
11755                    s.select_anchors(selections.to_vec());
11756                });
11757            } else {
11758                log::error!(
11759                    "No entry in selection_history found for undo. \
11760                     This may correspond to a bug where undo does not update the selection. \
11761                     If this is occurring, please add details to \
11762                     https://github.com/zed-industries/zed/issues/22692"
11763                );
11764            }
11765            self.request_autoscroll(Autoscroll::fit(), cx);
11766            self.unmark_text(window, cx);
11767            self.refresh_inline_completion(true, false, window, cx);
11768            cx.emit(EditorEvent::Edited { transaction_id });
11769            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11770        }
11771    }
11772
11773    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11774        if self.read_only(cx) {
11775            return;
11776        }
11777
11778        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11779
11780        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11781            if let Some((_, Some(selections))) =
11782                self.selection_history.transaction(transaction_id).cloned()
11783            {
11784                self.change_selections(None, window, cx, |s| {
11785                    s.select_anchors(selections.to_vec());
11786                });
11787            } else {
11788                log::error!(
11789                    "No entry in selection_history found for redo. \
11790                     This may correspond to a bug where undo does not update the selection. \
11791                     If this is occurring, please add details to \
11792                     https://github.com/zed-industries/zed/issues/22692"
11793                );
11794            }
11795            self.request_autoscroll(Autoscroll::fit(), cx);
11796            self.unmark_text(window, cx);
11797            self.refresh_inline_completion(true, false, window, cx);
11798            cx.emit(EditorEvent::Edited { transaction_id });
11799        }
11800    }
11801
11802    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11803        self.buffer
11804            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11805    }
11806
11807    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11808        self.buffer
11809            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11810    }
11811
11812    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11813        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11814        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11815            s.move_with(|map, selection| {
11816                let cursor = if selection.is_empty() {
11817                    movement::left(map, selection.start)
11818                } else {
11819                    selection.start
11820                };
11821                selection.collapse_to(cursor, SelectionGoal::None);
11822            });
11823        })
11824    }
11825
11826    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11827        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11828        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11829            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11830        })
11831    }
11832
11833    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11834        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11835        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11836            s.move_with(|map, selection| {
11837                let cursor = if selection.is_empty() {
11838                    movement::right(map, selection.end)
11839                } else {
11840                    selection.end
11841                };
11842                selection.collapse_to(cursor, SelectionGoal::None)
11843            });
11844        })
11845    }
11846
11847    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11848        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11849        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11850            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11851        })
11852    }
11853
11854    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11855        if self.take_rename(true, window, cx).is_some() {
11856            return;
11857        }
11858
11859        if self.mode.is_single_line() {
11860            cx.propagate();
11861            return;
11862        }
11863
11864        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11865
11866        let text_layout_details = &self.text_layout_details(window);
11867        let selection_count = self.selections.count();
11868        let first_selection = self.selections.first_anchor();
11869
11870        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11871            s.move_with(|map, selection| {
11872                if !selection.is_empty() {
11873                    selection.goal = SelectionGoal::None;
11874                }
11875                let (cursor, goal) = movement::up(
11876                    map,
11877                    selection.start,
11878                    selection.goal,
11879                    false,
11880                    text_layout_details,
11881                );
11882                selection.collapse_to(cursor, goal);
11883            });
11884        });
11885
11886        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11887        {
11888            cx.propagate();
11889        }
11890    }
11891
11892    pub fn move_up_by_lines(
11893        &mut self,
11894        action: &MoveUpByLines,
11895        window: &mut Window,
11896        cx: &mut Context<Self>,
11897    ) {
11898        if self.take_rename(true, window, cx).is_some() {
11899            return;
11900        }
11901
11902        if self.mode.is_single_line() {
11903            cx.propagate();
11904            return;
11905        }
11906
11907        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11908
11909        let text_layout_details = &self.text_layout_details(window);
11910
11911        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11912            s.move_with(|map, selection| {
11913                if !selection.is_empty() {
11914                    selection.goal = SelectionGoal::None;
11915                }
11916                let (cursor, goal) = movement::up_by_rows(
11917                    map,
11918                    selection.start,
11919                    action.lines,
11920                    selection.goal,
11921                    false,
11922                    text_layout_details,
11923                );
11924                selection.collapse_to(cursor, goal);
11925            });
11926        })
11927    }
11928
11929    pub fn move_down_by_lines(
11930        &mut self,
11931        action: &MoveDownByLines,
11932        window: &mut Window,
11933        cx: &mut Context<Self>,
11934    ) {
11935        if self.take_rename(true, window, cx).is_some() {
11936            return;
11937        }
11938
11939        if self.mode.is_single_line() {
11940            cx.propagate();
11941            return;
11942        }
11943
11944        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11945
11946        let text_layout_details = &self.text_layout_details(window);
11947
11948        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11949            s.move_with(|map, selection| {
11950                if !selection.is_empty() {
11951                    selection.goal = SelectionGoal::None;
11952                }
11953                let (cursor, goal) = movement::down_by_rows(
11954                    map,
11955                    selection.start,
11956                    action.lines,
11957                    selection.goal,
11958                    false,
11959                    text_layout_details,
11960                );
11961                selection.collapse_to(cursor, goal);
11962            });
11963        })
11964    }
11965
11966    pub fn select_down_by_lines(
11967        &mut self,
11968        action: &SelectDownByLines,
11969        window: &mut Window,
11970        cx: &mut Context<Self>,
11971    ) {
11972        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11973        let text_layout_details = &self.text_layout_details(window);
11974        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11975            s.move_heads_with(|map, head, goal| {
11976                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11977            })
11978        })
11979    }
11980
11981    pub fn select_up_by_lines(
11982        &mut self,
11983        action: &SelectUpByLines,
11984        window: &mut Window,
11985        cx: &mut Context<Self>,
11986    ) {
11987        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11988        let text_layout_details = &self.text_layout_details(window);
11989        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11990            s.move_heads_with(|map, head, goal| {
11991                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11992            })
11993        })
11994    }
11995
11996    pub fn select_page_up(
11997        &mut self,
11998        _: &SelectPageUp,
11999        window: &mut Window,
12000        cx: &mut Context<Self>,
12001    ) {
12002        let Some(row_count) = self.visible_row_count() else {
12003            return;
12004        };
12005
12006        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12007
12008        let text_layout_details = &self.text_layout_details(window);
12009
12010        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12011            s.move_heads_with(|map, head, goal| {
12012                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12013            })
12014        })
12015    }
12016
12017    pub fn move_page_up(
12018        &mut self,
12019        action: &MovePageUp,
12020        window: &mut Window,
12021        cx: &mut Context<Self>,
12022    ) {
12023        if self.take_rename(true, window, cx).is_some() {
12024            return;
12025        }
12026
12027        if self
12028            .context_menu
12029            .borrow_mut()
12030            .as_mut()
12031            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12032            .unwrap_or(false)
12033        {
12034            return;
12035        }
12036
12037        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12038            cx.propagate();
12039            return;
12040        }
12041
12042        let Some(row_count) = self.visible_row_count() else {
12043            return;
12044        };
12045
12046        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12047
12048        let autoscroll = if action.center_cursor {
12049            Autoscroll::center()
12050        } else {
12051            Autoscroll::fit()
12052        };
12053
12054        let text_layout_details = &self.text_layout_details(window);
12055
12056        self.change_selections(Some(autoscroll), window, cx, |s| {
12057            s.move_with(|map, selection| {
12058                if !selection.is_empty() {
12059                    selection.goal = SelectionGoal::None;
12060                }
12061                let (cursor, goal) = movement::up_by_rows(
12062                    map,
12063                    selection.end,
12064                    row_count,
12065                    selection.goal,
12066                    false,
12067                    text_layout_details,
12068                );
12069                selection.collapse_to(cursor, goal);
12070            });
12071        });
12072    }
12073
12074    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12075        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12076        let text_layout_details = &self.text_layout_details(window);
12077        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12078            s.move_heads_with(|map, head, goal| {
12079                movement::up(map, head, goal, false, text_layout_details)
12080            })
12081        })
12082    }
12083
12084    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12085        self.take_rename(true, window, cx);
12086
12087        if self.mode.is_single_line() {
12088            cx.propagate();
12089            return;
12090        }
12091
12092        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12093
12094        let text_layout_details = &self.text_layout_details(window);
12095        let selection_count = self.selections.count();
12096        let first_selection = self.selections.first_anchor();
12097
12098        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12099            s.move_with(|map, selection| {
12100                if !selection.is_empty() {
12101                    selection.goal = SelectionGoal::None;
12102                }
12103                let (cursor, goal) = movement::down(
12104                    map,
12105                    selection.end,
12106                    selection.goal,
12107                    false,
12108                    text_layout_details,
12109                );
12110                selection.collapse_to(cursor, goal);
12111            });
12112        });
12113
12114        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12115        {
12116            cx.propagate();
12117        }
12118    }
12119
12120    pub fn select_page_down(
12121        &mut self,
12122        _: &SelectPageDown,
12123        window: &mut Window,
12124        cx: &mut Context<Self>,
12125    ) {
12126        let Some(row_count) = self.visible_row_count() else {
12127            return;
12128        };
12129
12130        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12131
12132        let text_layout_details = &self.text_layout_details(window);
12133
12134        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12135            s.move_heads_with(|map, head, goal| {
12136                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12137            })
12138        })
12139    }
12140
12141    pub fn move_page_down(
12142        &mut self,
12143        action: &MovePageDown,
12144        window: &mut Window,
12145        cx: &mut Context<Self>,
12146    ) {
12147        if self.take_rename(true, window, cx).is_some() {
12148            return;
12149        }
12150
12151        if self
12152            .context_menu
12153            .borrow_mut()
12154            .as_mut()
12155            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12156            .unwrap_or(false)
12157        {
12158            return;
12159        }
12160
12161        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12162            cx.propagate();
12163            return;
12164        }
12165
12166        let Some(row_count) = self.visible_row_count() else {
12167            return;
12168        };
12169
12170        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12171
12172        let autoscroll = if action.center_cursor {
12173            Autoscroll::center()
12174        } else {
12175            Autoscroll::fit()
12176        };
12177
12178        let text_layout_details = &self.text_layout_details(window);
12179        self.change_selections(Some(autoscroll), window, cx, |s| {
12180            s.move_with(|map, selection| {
12181                if !selection.is_empty() {
12182                    selection.goal = SelectionGoal::None;
12183                }
12184                let (cursor, goal) = movement::down_by_rows(
12185                    map,
12186                    selection.end,
12187                    row_count,
12188                    selection.goal,
12189                    false,
12190                    text_layout_details,
12191                );
12192                selection.collapse_to(cursor, goal);
12193            });
12194        });
12195    }
12196
12197    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12198        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12199        let text_layout_details = &self.text_layout_details(window);
12200        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12201            s.move_heads_with(|map, head, goal| {
12202                movement::down(map, head, goal, false, text_layout_details)
12203            })
12204        });
12205    }
12206
12207    pub fn context_menu_first(
12208        &mut self,
12209        _: &ContextMenuFirst,
12210        window: &mut Window,
12211        cx: &mut Context<Self>,
12212    ) {
12213        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12214            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12215        }
12216    }
12217
12218    pub fn context_menu_prev(
12219        &mut self,
12220        _: &ContextMenuPrevious,
12221        window: &mut Window,
12222        cx: &mut Context<Self>,
12223    ) {
12224        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12225            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12226        }
12227    }
12228
12229    pub fn context_menu_next(
12230        &mut self,
12231        _: &ContextMenuNext,
12232        window: &mut Window,
12233        cx: &mut Context<Self>,
12234    ) {
12235        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12236            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12237        }
12238    }
12239
12240    pub fn context_menu_last(
12241        &mut self,
12242        _: &ContextMenuLast,
12243        window: &mut Window,
12244        cx: &mut Context<Self>,
12245    ) {
12246        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12247            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12248        }
12249    }
12250
12251    pub fn move_to_previous_word_start(
12252        &mut self,
12253        _: &MoveToPreviousWordStart,
12254        window: &mut Window,
12255        cx: &mut Context<Self>,
12256    ) {
12257        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12258        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12259            s.move_cursors_with(|map, head, _| {
12260                (
12261                    movement::previous_word_start(map, head),
12262                    SelectionGoal::None,
12263                )
12264            });
12265        })
12266    }
12267
12268    pub fn move_to_previous_subword_start(
12269        &mut self,
12270        _: &MoveToPreviousSubwordStart,
12271        window: &mut Window,
12272        cx: &mut Context<Self>,
12273    ) {
12274        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12275        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12276            s.move_cursors_with(|map, head, _| {
12277                (
12278                    movement::previous_subword_start(map, head),
12279                    SelectionGoal::None,
12280                )
12281            });
12282        })
12283    }
12284
12285    pub fn select_to_previous_word_start(
12286        &mut self,
12287        _: &SelectToPreviousWordStart,
12288        window: &mut Window,
12289        cx: &mut Context<Self>,
12290    ) {
12291        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12292        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12293            s.move_heads_with(|map, head, _| {
12294                (
12295                    movement::previous_word_start(map, head),
12296                    SelectionGoal::None,
12297                )
12298            });
12299        })
12300    }
12301
12302    pub fn select_to_previous_subword_start(
12303        &mut self,
12304        _: &SelectToPreviousSubwordStart,
12305        window: &mut Window,
12306        cx: &mut Context<Self>,
12307    ) {
12308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12309        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12310            s.move_heads_with(|map, head, _| {
12311                (
12312                    movement::previous_subword_start(map, head),
12313                    SelectionGoal::None,
12314                )
12315            });
12316        })
12317    }
12318
12319    pub fn delete_to_previous_word_start(
12320        &mut self,
12321        action: &DeleteToPreviousWordStart,
12322        window: &mut Window,
12323        cx: &mut Context<Self>,
12324    ) {
12325        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12326        self.transact(window, cx, |this, window, cx| {
12327            this.select_autoclose_pair(window, cx);
12328            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12329                s.move_with(|map, selection| {
12330                    if selection.is_empty() {
12331                        let cursor = if action.ignore_newlines {
12332                            movement::previous_word_start(map, selection.head())
12333                        } else {
12334                            movement::previous_word_start_or_newline(map, selection.head())
12335                        };
12336                        selection.set_head(cursor, SelectionGoal::None);
12337                    }
12338                });
12339            });
12340            this.insert("", window, cx);
12341        });
12342    }
12343
12344    pub fn delete_to_previous_subword_start(
12345        &mut self,
12346        _: &DeleteToPreviousSubwordStart,
12347        window: &mut Window,
12348        cx: &mut Context<Self>,
12349    ) {
12350        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12351        self.transact(window, cx, |this, window, cx| {
12352            this.select_autoclose_pair(window, cx);
12353            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12354                s.move_with(|map, selection| {
12355                    if selection.is_empty() {
12356                        let cursor = movement::previous_subword_start(map, selection.head());
12357                        selection.set_head(cursor, SelectionGoal::None);
12358                    }
12359                });
12360            });
12361            this.insert("", window, cx);
12362        });
12363    }
12364
12365    pub fn move_to_next_word_end(
12366        &mut self,
12367        _: &MoveToNextWordEnd,
12368        window: &mut Window,
12369        cx: &mut Context<Self>,
12370    ) {
12371        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12372        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12373            s.move_cursors_with(|map, head, _| {
12374                (movement::next_word_end(map, head), SelectionGoal::None)
12375            });
12376        })
12377    }
12378
12379    pub fn move_to_next_subword_end(
12380        &mut self,
12381        _: &MoveToNextSubwordEnd,
12382        window: &mut Window,
12383        cx: &mut Context<Self>,
12384    ) {
12385        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12386        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12387            s.move_cursors_with(|map, head, _| {
12388                (movement::next_subword_end(map, head), SelectionGoal::None)
12389            });
12390        })
12391    }
12392
12393    pub fn select_to_next_word_end(
12394        &mut self,
12395        _: &SelectToNextWordEnd,
12396        window: &mut Window,
12397        cx: &mut Context<Self>,
12398    ) {
12399        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12400        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12401            s.move_heads_with(|map, head, _| {
12402                (movement::next_word_end(map, head), SelectionGoal::None)
12403            });
12404        })
12405    }
12406
12407    pub fn select_to_next_subword_end(
12408        &mut self,
12409        _: &SelectToNextSubwordEnd,
12410        window: &mut Window,
12411        cx: &mut Context<Self>,
12412    ) {
12413        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12414        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12415            s.move_heads_with(|map, head, _| {
12416                (movement::next_subword_end(map, head), SelectionGoal::None)
12417            });
12418        })
12419    }
12420
12421    pub fn delete_to_next_word_end(
12422        &mut self,
12423        action: &DeleteToNextWordEnd,
12424        window: &mut Window,
12425        cx: &mut Context<Self>,
12426    ) {
12427        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12428        self.transact(window, cx, |this, window, cx| {
12429            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12430                s.move_with(|map, selection| {
12431                    if selection.is_empty() {
12432                        let cursor = if action.ignore_newlines {
12433                            movement::next_word_end(map, selection.head())
12434                        } else {
12435                            movement::next_word_end_or_newline(map, selection.head())
12436                        };
12437                        selection.set_head(cursor, SelectionGoal::None);
12438                    }
12439                });
12440            });
12441            this.insert("", window, cx);
12442        });
12443    }
12444
12445    pub fn delete_to_next_subword_end(
12446        &mut self,
12447        _: &DeleteToNextSubwordEnd,
12448        window: &mut Window,
12449        cx: &mut Context<Self>,
12450    ) {
12451        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12452        self.transact(window, cx, |this, window, cx| {
12453            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12454                s.move_with(|map, selection| {
12455                    if selection.is_empty() {
12456                        let cursor = movement::next_subword_end(map, selection.head());
12457                        selection.set_head(cursor, SelectionGoal::None);
12458                    }
12459                });
12460            });
12461            this.insert("", window, cx);
12462        });
12463    }
12464
12465    pub fn move_to_beginning_of_line(
12466        &mut self,
12467        action: &MoveToBeginningOfLine,
12468        window: &mut Window,
12469        cx: &mut Context<Self>,
12470    ) {
12471        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12472        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12473            s.move_cursors_with(|map, head, _| {
12474                (
12475                    movement::indented_line_beginning(
12476                        map,
12477                        head,
12478                        action.stop_at_soft_wraps,
12479                        action.stop_at_indent,
12480                    ),
12481                    SelectionGoal::None,
12482                )
12483            });
12484        })
12485    }
12486
12487    pub fn select_to_beginning_of_line(
12488        &mut self,
12489        action: &SelectToBeginningOfLine,
12490        window: &mut Window,
12491        cx: &mut Context<Self>,
12492    ) {
12493        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12494        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12495            s.move_heads_with(|map, head, _| {
12496                (
12497                    movement::indented_line_beginning(
12498                        map,
12499                        head,
12500                        action.stop_at_soft_wraps,
12501                        action.stop_at_indent,
12502                    ),
12503                    SelectionGoal::None,
12504                )
12505            });
12506        });
12507    }
12508
12509    pub fn delete_to_beginning_of_line(
12510        &mut self,
12511        action: &DeleteToBeginningOfLine,
12512        window: &mut Window,
12513        cx: &mut Context<Self>,
12514    ) {
12515        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12516        self.transact(window, cx, |this, window, cx| {
12517            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12518                s.move_with(|_, selection| {
12519                    selection.reversed = true;
12520                });
12521            });
12522
12523            this.select_to_beginning_of_line(
12524                &SelectToBeginningOfLine {
12525                    stop_at_soft_wraps: false,
12526                    stop_at_indent: action.stop_at_indent,
12527                },
12528                window,
12529                cx,
12530            );
12531            this.backspace(&Backspace, window, cx);
12532        });
12533    }
12534
12535    pub fn move_to_end_of_line(
12536        &mut self,
12537        action: &MoveToEndOfLine,
12538        window: &mut Window,
12539        cx: &mut Context<Self>,
12540    ) {
12541        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12542        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12543            s.move_cursors_with(|map, head, _| {
12544                (
12545                    movement::line_end(map, head, action.stop_at_soft_wraps),
12546                    SelectionGoal::None,
12547                )
12548            });
12549        })
12550    }
12551
12552    pub fn select_to_end_of_line(
12553        &mut self,
12554        action: &SelectToEndOfLine,
12555        window: &mut Window,
12556        cx: &mut Context<Self>,
12557    ) {
12558        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12559        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12560            s.move_heads_with(|map, head, _| {
12561                (
12562                    movement::line_end(map, head, action.stop_at_soft_wraps),
12563                    SelectionGoal::None,
12564                )
12565            });
12566        })
12567    }
12568
12569    pub fn delete_to_end_of_line(
12570        &mut self,
12571        _: &DeleteToEndOfLine,
12572        window: &mut Window,
12573        cx: &mut Context<Self>,
12574    ) {
12575        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12576        self.transact(window, cx, |this, window, cx| {
12577            this.select_to_end_of_line(
12578                &SelectToEndOfLine {
12579                    stop_at_soft_wraps: false,
12580                },
12581                window,
12582                cx,
12583            );
12584            this.delete(&Delete, window, cx);
12585        });
12586    }
12587
12588    pub fn cut_to_end_of_line(
12589        &mut self,
12590        _: &CutToEndOfLine,
12591        window: &mut Window,
12592        cx: &mut Context<Self>,
12593    ) {
12594        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12595        self.transact(window, cx, |this, window, cx| {
12596            this.select_to_end_of_line(
12597                &SelectToEndOfLine {
12598                    stop_at_soft_wraps: false,
12599                },
12600                window,
12601                cx,
12602            );
12603            this.cut(&Cut, window, cx);
12604        });
12605    }
12606
12607    pub fn move_to_start_of_paragraph(
12608        &mut self,
12609        _: &MoveToStartOfParagraph,
12610        window: &mut Window,
12611        cx: &mut Context<Self>,
12612    ) {
12613        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12614            cx.propagate();
12615            return;
12616        }
12617        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12618        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12619            s.move_with(|map, selection| {
12620                selection.collapse_to(
12621                    movement::start_of_paragraph(map, selection.head(), 1),
12622                    SelectionGoal::None,
12623                )
12624            });
12625        })
12626    }
12627
12628    pub fn move_to_end_of_paragraph(
12629        &mut self,
12630        _: &MoveToEndOfParagraph,
12631        window: &mut Window,
12632        cx: &mut Context<Self>,
12633    ) {
12634        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12635            cx.propagate();
12636            return;
12637        }
12638        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12639        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12640            s.move_with(|map, selection| {
12641                selection.collapse_to(
12642                    movement::end_of_paragraph(map, selection.head(), 1),
12643                    SelectionGoal::None,
12644                )
12645            });
12646        })
12647    }
12648
12649    pub fn select_to_start_of_paragraph(
12650        &mut self,
12651        _: &SelectToStartOfParagraph,
12652        window: &mut Window,
12653        cx: &mut Context<Self>,
12654    ) {
12655        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12656            cx.propagate();
12657            return;
12658        }
12659        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12660        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12661            s.move_heads_with(|map, head, _| {
12662                (
12663                    movement::start_of_paragraph(map, head, 1),
12664                    SelectionGoal::None,
12665                )
12666            });
12667        })
12668    }
12669
12670    pub fn select_to_end_of_paragraph(
12671        &mut self,
12672        _: &SelectToEndOfParagraph,
12673        window: &mut Window,
12674        cx: &mut Context<Self>,
12675    ) {
12676        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12677            cx.propagate();
12678            return;
12679        }
12680        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12681        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12682            s.move_heads_with(|map, head, _| {
12683                (
12684                    movement::end_of_paragraph(map, head, 1),
12685                    SelectionGoal::None,
12686                )
12687            });
12688        })
12689    }
12690
12691    pub fn move_to_start_of_excerpt(
12692        &mut self,
12693        _: &MoveToStartOfExcerpt,
12694        window: &mut Window,
12695        cx: &mut Context<Self>,
12696    ) {
12697        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12698            cx.propagate();
12699            return;
12700        }
12701        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12702        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12703            s.move_with(|map, selection| {
12704                selection.collapse_to(
12705                    movement::start_of_excerpt(
12706                        map,
12707                        selection.head(),
12708                        workspace::searchable::Direction::Prev,
12709                    ),
12710                    SelectionGoal::None,
12711                )
12712            });
12713        })
12714    }
12715
12716    pub fn move_to_start_of_next_excerpt(
12717        &mut self,
12718        _: &MoveToStartOfNextExcerpt,
12719        window: &mut Window,
12720        cx: &mut Context<Self>,
12721    ) {
12722        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12723            cx.propagate();
12724            return;
12725        }
12726
12727        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12728            s.move_with(|map, selection| {
12729                selection.collapse_to(
12730                    movement::start_of_excerpt(
12731                        map,
12732                        selection.head(),
12733                        workspace::searchable::Direction::Next,
12734                    ),
12735                    SelectionGoal::None,
12736                )
12737            });
12738        })
12739    }
12740
12741    pub fn move_to_end_of_excerpt(
12742        &mut self,
12743        _: &MoveToEndOfExcerpt,
12744        window: &mut Window,
12745        cx: &mut Context<Self>,
12746    ) {
12747        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12748            cx.propagate();
12749            return;
12750        }
12751        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12752        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12753            s.move_with(|map, selection| {
12754                selection.collapse_to(
12755                    movement::end_of_excerpt(
12756                        map,
12757                        selection.head(),
12758                        workspace::searchable::Direction::Next,
12759                    ),
12760                    SelectionGoal::None,
12761                )
12762            });
12763        })
12764    }
12765
12766    pub fn move_to_end_of_previous_excerpt(
12767        &mut self,
12768        _: &MoveToEndOfPreviousExcerpt,
12769        window: &mut Window,
12770        cx: &mut Context<Self>,
12771    ) {
12772        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12773            cx.propagate();
12774            return;
12775        }
12776        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12777        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12778            s.move_with(|map, selection| {
12779                selection.collapse_to(
12780                    movement::end_of_excerpt(
12781                        map,
12782                        selection.head(),
12783                        workspace::searchable::Direction::Prev,
12784                    ),
12785                    SelectionGoal::None,
12786                )
12787            });
12788        })
12789    }
12790
12791    pub fn select_to_start_of_excerpt(
12792        &mut self,
12793        _: &SelectToStartOfExcerpt,
12794        window: &mut Window,
12795        cx: &mut Context<Self>,
12796    ) {
12797        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12798            cx.propagate();
12799            return;
12800        }
12801        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12802        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12803            s.move_heads_with(|map, head, _| {
12804                (
12805                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12806                    SelectionGoal::None,
12807                )
12808            });
12809        })
12810    }
12811
12812    pub fn select_to_start_of_next_excerpt(
12813        &mut self,
12814        _: &SelectToStartOfNextExcerpt,
12815        window: &mut Window,
12816        cx: &mut Context<Self>,
12817    ) {
12818        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12819            cx.propagate();
12820            return;
12821        }
12822        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12823        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12824            s.move_heads_with(|map, head, _| {
12825                (
12826                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12827                    SelectionGoal::None,
12828                )
12829            });
12830        })
12831    }
12832
12833    pub fn select_to_end_of_excerpt(
12834        &mut self,
12835        _: &SelectToEndOfExcerpt,
12836        window: &mut Window,
12837        cx: &mut Context<Self>,
12838    ) {
12839        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12840            cx.propagate();
12841            return;
12842        }
12843        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12844        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12845            s.move_heads_with(|map, head, _| {
12846                (
12847                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12848                    SelectionGoal::None,
12849                )
12850            });
12851        })
12852    }
12853
12854    pub fn select_to_end_of_previous_excerpt(
12855        &mut self,
12856        _: &SelectToEndOfPreviousExcerpt,
12857        window: &mut Window,
12858        cx: &mut Context<Self>,
12859    ) {
12860        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12861            cx.propagate();
12862            return;
12863        }
12864        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12865        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12866            s.move_heads_with(|map, head, _| {
12867                (
12868                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12869                    SelectionGoal::None,
12870                )
12871            });
12872        })
12873    }
12874
12875    pub fn move_to_beginning(
12876        &mut self,
12877        _: &MoveToBeginning,
12878        window: &mut Window,
12879        cx: &mut Context<Self>,
12880    ) {
12881        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12882            cx.propagate();
12883            return;
12884        }
12885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12886        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12887            s.select_ranges(vec![0..0]);
12888        });
12889    }
12890
12891    pub fn select_to_beginning(
12892        &mut self,
12893        _: &SelectToBeginning,
12894        window: &mut Window,
12895        cx: &mut Context<Self>,
12896    ) {
12897        let mut selection = self.selections.last::<Point>(cx);
12898        selection.set_head(Point::zero(), SelectionGoal::None);
12899        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12900        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12901            s.select(vec![selection]);
12902        });
12903    }
12904
12905    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12906        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12907            cx.propagate();
12908            return;
12909        }
12910        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12911        let cursor = self.buffer.read(cx).read(cx).len();
12912        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12913            s.select_ranges(vec![cursor..cursor])
12914        });
12915    }
12916
12917    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12918        self.nav_history = nav_history;
12919    }
12920
12921    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12922        self.nav_history.as_ref()
12923    }
12924
12925    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12926        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12927    }
12928
12929    fn push_to_nav_history(
12930        &mut self,
12931        cursor_anchor: Anchor,
12932        new_position: Option<Point>,
12933        is_deactivate: bool,
12934        cx: &mut Context<Self>,
12935    ) {
12936        if let Some(nav_history) = self.nav_history.as_mut() {
12937            let buffer = self.buffer.read(cx).read(cx);
12938            let cursor_position = cursor_anchor.to_point(&buffer);
12939            let scroll_state = self.scroll_manager.anchor();
12940            let scroll_top_row = scroll_state.top_row(&buffer);
12941            drop(buffer);
12942
12943            if let Some(new_position) = new_position {
12944                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12945                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12946                    return;
12947                }
12948            }
12949
12950            nav_history.push(
12951                Some(NavigationData {
12952                    cursor_anchor,
12953                    cursor_position,
12954                    scroll_anchor: scroll_state,
12955                    scroll_top_row,
12956                }),
12957                cx,
12958            );
12959            cx.emit(EditorEvent::PushedToNavHistory {
12960                anchor: cursor_anchor,
12961                is_deactivate,
12962            })
12963        }
12964    }
12965
12966    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12968        let buffer = self.buffer.read(cx).snapshot(cx);
12969        let mut selection = self.selections.first::<usize>(cx);
12970        selection.set_head(buffer.len(), SelectionGoal::None);
12971        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12972            s.select(vec![selection]);
12973        });
12974    }
12975
12976    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12978        let end = self.buffer.read(cx).read(cx).len();
12979        self.change_selections(None, window, cx, |s| {
12980            s.select_ranges(vec![0..end]);
12981        });
12982    }
12983
12984    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12985        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12986        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12987        let mut selections = self.selections.all::<Point>(cx);
12988        let max_point = display_map.buffer_snapshot.max_point();
12989        for selection in &mut selections {
12990            let rows = selection.spanned_rows(true, &display_map);
12991            selection.start = Point::new(rows.start.0, 0);
12992            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12993            selection.reversed = false;
12994        }
12995        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12996            s.select(selections);
12997        });
12998    }
12999
13000    pub fn split_selection_into_lines(
13001        &mut self,
13002        _: &SplitSelectionIntoLines,
13003        window: &mut Window,
13004        cx: &mut Context<Self>,
13005    ) {
13006        let selections = self
13007            .selections
13008            .all::<Point>(cx)
13009            .into_iter()
13010            .map(|selection| selection.start..selection.end)
13011            .collect::<Vec<_>>();
13012        self.unfold_ranges(&selections, true, true, cx);
13013
13014        let mut new_selection_ranges = Vec::new();
13015        {
13016            let buffer = self.buffer.read(cx).read(cx);
13017            for selection in selections {
13018                for row in selection.start.row..selection.end.row {
13019                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13020                    new_selection_ranges.push(cursor..cursor);
13021                }
13022
13023                let is_multiline_selection = selection.start.row != selection.end.row;
13024                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13025                // so this action feels more ergonomic when paired with other selection operations
13026                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13027                if !should_skip_last {
13028                    new_selection_ranges.push(selection.end..selection.end);
13029                }
13030            }
13031        }
13032        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13033            s.select_ranges(new_selection_ranges);
13034        });
13035    }
13036
13037    pub fn add_selection_above(
13038        &mut self,
13039        _: &AddSelectionAbove,
13040        window: &mut Window,
13041        cx: &mut Context<Self>,
13042    ) {
13043        self.add_selection(true, window, cx);
13044    }
13045
13046    pub fn add_selection_below(
13047        &mut self,
13048        _: &AddSelectionBelow,
13049        window: &mut Window,
13050        cx: &mut Context<Self>,
13051    ) {
13052        self.add_selection(false, window, cx);
13053    }
13054
13055    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13056        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13057
13058        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13059        let all_selections = self.selections.all::<Point>(cx);
13060        let text_layout_details = self.text_layout_details(window);
13061
13062        let (mut columnar_selections, new_selections_to_columnarize) = {
13063            if let Some(state) = self.add_selections_state.as_ref() {
13064                let columnar_selection_ids: HashSet<_> = state
13065                    .groups
13066                    .iter()
13067                    .flat_map(|group| group.stack.iter())
13068                    .copied()
13069                    .collect();
13070
13071                all_selections
13072                    .into_iter()
13073                    .partition(|s| columnar_selection_ids.contains(&s.id))
13074            } else {
13075                (Vec::new(), all_selections)
13076            }
13077        };
13078
13079        let mut state = self
13080            .add_selections_state
13081            .take()
13082            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13083
13084        for selection in new_selections_to_columnarize {
13085            let range = selection.display_range(&display_map).sorted();
13086            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13087            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13088            let positions = start_x.min(end_x)..start_x.max(end_x);
13089            let mut stack = Vec::new();
13090            for row in range.start.row().0..=range.end.row().0 {
13091                if let Some(selection) = self.selections.build_columnar_selection(
13092                    &display_map,
13093                    DisplayRow(row),
13094                    &positions,
13095                    selection.reversed,
13096                    &text_layout_details,
13097                ) {
13098                    stack.push(selection.id);
13099                    columnar_selections.push(selection);
13100                }
13101            }
13102            if !stack.is_empty() {
13103                if above {
13104                    stack.reverse();
13105                }
13106                state.groups.push(AddSelectionsGroup { above, stack });
13107            }
13108        }
13109
13110        let mut final_selections = Vec::new();
13111        let end_row = if above {
13112            DisplayRow(0)
13113        } else {
13114            display_map.max_point().row()
13115        };
13116
13117        let mut last_added_item_per_group = HashMap::default();
13118        for group in state.groups.iter_mut() {
13119            if let Some(last_id) = group.stack.last() {
13120                last_added_item_per_group.insert(*last_id, group);
13121            }
13122        }
13123
13124        for selection in columnar_selections {
13125            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13126                if above == group.above {
13127                    let range = selection.display_range(&display_map).sorted();
13128                    debug_assert_eq!(range.start.row(), range.end.row());
13129                    let mut row = range.start.row();
13130                    let positions =
13131                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13132                            px(start)..px(end)
13133                        } else {
13134                            let start_x =
13135                                display_map.x_for_display_point(range.start, &text_layout_details);
13136                            let end_x =
13137                                display_map.x_for_display_point(range.end, &text_layout_details);
13138                            start_x.min(end_x)..start_x.max(end_x)
13139                        };
13140
13141                    let mut maybe_new_selection = None;
13142                    while row != end_row {
13143                        if above {
13144                            row.0 -= 1;
13145                        } else {
13146                            row.0 += 1;
13147                        }
13148                        if let Some(new_selection) = self.selections.build_columnar_selection(
13149                            &display_map,
13150                            row,
13151                            &positions,
13152                            selection.reversed,
13153                            &text_layout_details,
13154                        ) {
13155                            maybe_new_selection = Some(new_selection);
13156                            break;
13157                        }
13158                    }
13159
13160                    if let Some(new_selection) = maybe_new_selection {
13161                        group.stack.push(new_selection.id);
13162                        if above {
13163                            final_selections.push(new_selection);
13164                            final_selections.push(selection);
13165                        } else {
13166                            final_selections.push(selection);
13167                            final_selections.push(new_selection);
13168                        }
13169                    } else {
13170                        final_selections.push(selection);
13171                    }
13172                } else {
13173                    group.stack.pop();
13174                }
13175            } else {
13176                final_selections.push(selection);
13177            }
13178        }
13179
13180        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13181            s.select(final_selections);
13182        });
13183
13184        let final_selection_ids: HashSet<_> = self
13185            .selections
13186            .all::<Point>(cx)
13187            .iter()
13188            .map(|s| s.id)
13189            .collect();
13190        state.groups.retain_mut(|group| {
13191            // selections might get merged above so we remove invalid items from stacks
13192            group.stack.retain(|id| final_selection_ids.contains(id));
13193
13194            // single selection in stack can be treated as initial state
13195            group.stack.len() > 1
13196        });
13197
13198        if !state.groups.is_empty() {
13199            self.add_selections_state = Some(state);
13200        }
13201    }
13202
13203    fn select_match_ranges(
13204        &mut self,
13205        range: Range<usize>,
13206        reversed: bool,
13207        replace_newest: bool,
13208        auto_scroll: Option<Autoscroll>,
13209        window: &mut Window,
13210        cx: &mut Context<Editor>,
13211    ) {
13212        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13213        self.change_selections(auto_scroll, window, cx, |s| {
13214            if replace_newest {
13215                s.delete(s.newest_anchor().id);
13216            }
13217            if reversed {
13218                s.insert_range(range.end..range.start);
13219            } else {
13220                s.insert_range(range);
13221            }
13222        });
13223    }
13224
13225    pub fn select_next_match_internal(
13226        &mut self,
13227        display_map: &DisplaySnapshot,
13228        replace_newest: bool,
13229        autoscroll: Option<Autoscroll>,
13230        window: &mut Window,
13231        cx: &mut Context<Self>,
13232    ) -> Result<()> {
13233        let buffer = &display_map.buffer_snapshot;
13234        let mut selections = self.selections.all::<usize>(cx);
13235        if let Some(mut select_next_state) = self.select_next_state.take() {
13236            let query = &select_next_state.query;
13237            if !select_next_state.done {
13238                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13239                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13240                let mut next_selected_range = None;
13241
13242                let bytes_after_last_selection =
13243                    buffer.bytes_in_range(last_selection.end..buffer.len());
13244                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13245                let query_matches = query
13246                    .stream_find_iter(bytes_after_last_selection)
13247                    .map(|result| (last_selection.end, result))
13248                    .chain(
13249                        query
13250                            .stream_find_iter(bytes_before_first_selection)
13251                            .map(|result| (0, result)),
13252                    );
13253
13254                for (start_offset, query_match) in query_matches {
13255                    let query_match = query_match.unwrap(); // can only fail due to I/O
13256                    let offset_range =
13257                        start_offset + query_match.start()..start_offset + query_match.end();
13258                    let display_range = offset_range.start.to_display_point(display_map)
13259                        ..offset_range.end.to_display_point(display_map);
13260
13261                    if !select_next_state.wordwise
13262                        || (!movement::is_inside_word(display_map, display_range.start)
13263                            && !movement::is_inside_word(display_map, display_range.end))
13264                    {
13265                        // TODO: This is n^2, because we might check all the selections
13266                        if !selections
13267                            .iter()
13268                            .any(|selection| selection.range().overlaps(&offset_range))
13269                        {
13270                            next_selected_range = Some(offset_range);
13271                            break;
13272                        }
13273                    }
13274                }
13275
13276                if let Some(next_selected_range) = next_selected_range {
13277                    self.select_match_ranges(
13278                        next_selected_range,
13279                        last_selection.reversed,
13280                        replace_newest,
13281                        autoscroll,
13282                        window,
13283                        cx,
13284                    );
13285                } else {
13286                    select_next_state.done = true;
13287                }
13288            }
13289
13290            self.select_next_state = Some(select_next_state);
13291        } else {
13292            let mut only_carets = true;
13293            let mut same_text_selected = true;
13294            let mut selected_text = None;
13295
13296            let mut selections_iter = selections.iter().peekable();
13297            while let Some(selection) = selections_iter.next() {
13298                if selection.start != selection.end {
13299                    only_carets = false;
13300                }
13301
13302                if same_text_selected {
13303                    if selected_text.is_none() {
13304                        selected_text =
13305                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13306                    }
13307
13308                    if let Some(next_selection) = selections_iter.peek() {
13309                        if next_selection.range().len() == selection.range().len() {
13310                            let next_selected_text = buffer
13311                                .text_for_range(next_selection.range())
13312                                .collect::<String>();
13313                            if Some(next_selected_text) != selected_text {
13314                                same_text_selected = false;
13315                                selected_text = None;
13316                            }
13317                        } else {
13318                            same_text_selected = false;
13319                            selected_text = None;
13320                        }
13321                    }
13322                }
13323            }
13324
13325            if only_carets {
13326                for selection in &mut selections {
13327                    let word_range = movement::surrounding_word(
13328                        display_map,
13329                        selection.start.to_display_point(display_map),
13330                    );
13331                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13332                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13333                    selection.goal = SelectionGoal::None;
13334                    selection.reversed = false;
13335                    self.select_match_ranges(
13336                        selection.start..selection.end,
13337                        selection.reversed,
13338                        replace_newest,
13339                        autoscroll,
13340                        window,
13341                        cx,
13342                    );
13343                }
13344
13345                if selections.len() == 1 {
13346                    let selection = selections
13347                        .last()
13348                        .expect("ensured that there's only one selection");
13349                    let query = buffer
13350                        .text_for_range(selection.start..selection.end)
13351                        .collect::<String>();
13352                    let is_empty = query.is_empty();
13353                    let select_state = SelectNextState {
13354                        query: AhoCorasick::new(&[query])?,
13355                        wordwise: true,
13356                        done: is_empty,
13357                    };
13358                    self.select_next_state = Some(select_state);
13359                } else {
13360                    self.select_next_state = None;
13361                }
13362            } else if let Some(selected_text) = selected_text {
13363                self.select_next_state = Some(SelectNextState {
13364                    query: AhoCorasick::new(&[selected_text])?,
13365                    wordwise: false,
13366                    done: false,
13367                });
13368                self.select_next_match_internal(
13369                    display_map,
13370                    replace_newest,
13371                    autoscroll,
13372                    window,
13373                    cx,
13374                )?;
13375            }
13376        }
13377        Ok(())
13378    }
13379
13380    pub fn select_all_matches(
13381        &mut self,
13382        _action: &SelectAllMatches,
13383        window: &mut Window,
13384        cx: &mut Context<Self>,
13385    ) -> Result<()> {
13386        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13387
13388        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13389
13390        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13391        let Some(select_next_state) = self.select_next_state.as_mut() else {
13392            return Ok(());
13393        };
13394        if select_next_state.done {
13395            return Ok(());
13396        }
13397
13398        let mut new_selections = Vec::new();
13399
13400        let reversed = self.selections.oldest::<usize>(cx).reversed;
13401        let buffer = &display_map.buffer_snapshot;
13402        let query_matches = select_next_state
13403            .query
13404            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13405
13406        for query_match in query_matches.into_iter() {
13407            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13408            let offset_range = if reversed {
13409                query_match.end()..query_match.start()
13410            } else {
13411                query_match.start()..query_match.end()
13412            };
13413            let display_range = offset_range.start.to_display_point(&display_map)
13414                ..offset_range.end.to_display_point(&display_map);
13415
13416            if !select_next_state.wordwise
13417                || (!movement::is_inside_word(&display_map, display_range.start)
13418                    && !movement::is_inside_word(&display_map, display_range.end))
13419            {
13420                new_selections.push(offset_range.start..offset_range.end);
13421            }
13422        }
13423
13424        select_next_state.done = true;
13425        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13426        self.change_selections(None, window, cx, |selections| {
13427            selections.select_ranges(new_selections)
13428        });
13429
13430        Ok(())
13431    }
13432
13433    pub fn select_next(
13434        &mut self,
13435        action: &SelectNext,
13436        window: &mut Window,
13437        cx: &mut Context<Self>,
13438    ) -> Result<()> {
13439        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13440        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13441        self.select_next_match_internal(
13442            &display_map,
13443            action.replace_newest,
13444            Some(Autoscroll::newest()),
13445            window,
13446            cx,
13447        )?;
13448        Ok(())
13449    }
13450
13451    pub fn select_previous(
13452        &mut self,
13453        action: &SelectPrevious,
13454        window: &mut Window,
13455        cx: &mut Context<Self>,
13456    ) -> Result<()> {
13457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13458        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13459        let buffer = &display_map.buffer_snapshot;
13460        let mut selections = self.selections.all::<usize>(cx);
13461        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13462            let query = &select_prev_state.query;
13463            if !select_prev_state.done {
13464                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13465                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13466                let mut next_selected_range = None;
13467                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13468                let bytes_before_last_selection =
13469                    buffer.reversed_bytes_in_range(0..last_selection.start);
13470                let bytes_after_first_selection =
13471                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13472                let query_matches = query
13473                    .stream_find_iter(bytes_before_last_selection)
13474                    .map(|result| (last_selection.start, result))
13475                    .chain(
13476                        query
13477                            .stream_find_iter(bytes_after_first_selection)
13478                            .map(|result| (buffer.len(), result)),
13479                    );
13480                for (end_offset, query_match) in query_matches {
13481                    let query_match = query_match.unwrap(); // can only fail due to I/O
13482                    let offset_range =
13483                        end_offset - query_match.end()..end_offset - query_match.start();
13484                    let display_range = offset_range.start.to_display_point(&display_map)
13485                        ..offset_range.end.to_display_point(&display_map);
13486
13487                    if !select_prev_state.wordwise
13488                        || (!movement::is_inside_word(&display_map, display_range.start)
13489                            && !movement::is_inside_word(&display_map, display_range.end))
13490                    {
13491                        next_selected_range = Some(offset_range);
13492                        break;
13493                    }
13494                }
13495
13496                if let Some(next_selected_range) = next_selected_range {
13497                    self.select_match_ranges(
13498                        next_selected_range,
13499                        last_selection.reversed,
13500                        action.replace_newest,
13501                        Some(Autoscroll::newest()),
13502                        window,
13503                        cx,
13504                    );
13505                } else {
13506                    select_prev_state.done = true;
13507                }
13508            }
13509
13510            self.select_prev_state = Some(select_prev_state);
13511        } else {
13512            let mut only_carets = true;
13513            let mut same_text_selected = true;
13514            let mut selected_text = None;
13515
13516            let mut selections_iter = selections.iter().peekable();
13517            while let Some(selection) = selections_iter.next() {
13518                if selection.start != selection.end {
13519                    only_carets = false;
13520                }
13521
13522                if same_text_selected {
13523                    if selected_text.is_none() {
13524                        selected_text =
13525                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13526                    }
13527
13528                    if let Some(next_selection) = selections_iter.peek() {
13529                        if next_selection.range().len() == selection.range().len() {
13530                            let next_selected_text = buffer
13531                                .text_for_range(next_selection.range())
13532                                .collect::<String>();
13533                            if Some(next_selected_text) != selected_text {
13534                                same_text_selected = false;
13535                                selected_text = None;
13536                            }
13537                        } else {
13538                            same_text_selected = false;
13539                            selected_text = None;
13540                        }
13541                    }
13542                }
13543            }
13544
13545            if only_carets {
13546                for selection in &mut selections {
13547                    let word_range = movement::surrounding_word(
13548                        &display_map,
13549                        selection.start.to_display_point(&display_map),
13550                    );
13551                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13552                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13553                    selection.goal = SelectionGoal::None;
13554                    selection.reversed = false;
13555                    self.select_match_ranges(
13556                        selection.start..selection.end,
13557                        selection.reversed,
13558                        action.replace_newest,
13559                        Some(Autoscroll::newest()),
13560                        window,
13561                        cx,
13562                    );
13563                }
13564                if selections.len() == 1 {
13565                    let selection = selections
13566                        .last()
13567                        .expect("ensured that there's only one selection");
13568                    let query = buffer
13569                        .text_for_range(selection.start..selection.end)
13570                        .collect::<String>();
13571                    let is_empty = query.is_empty();
13572                    let select_state = SelectNextState {
13573                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13574                        wordwise: true,
13575                        done: is_empty,
13576                    };
13577                    self.select_prev_state = Some(select_state);
13578                } else {
13579                    self.select_prev_state = None;
13580                }
13581            } else if let Some(selected_text) = selected_text {
13582                self.select_prev_state = Some(SelectNextState {
13583                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13584                    wordwise: false,
13585                    done: false,
13586                });
13587                self.select_previous(action, window, cx)?;
13588            }
13589        }
13590        Ok(())
13591    }
13592
13593    pub fn find_next_match(
13594        &mut self,
13595        _: &FindNextMatch,
13596        window: &mut Window,
13597        cx: &mut Context<Self>,
13598    ) -> Result<()> {
13599        let selections = self.selections.disjoint_anchors();
13600        match selections.first() {
13601            Some(first) if selections.len() >= 2 => {
13602                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13603                    s.select_ranges([first.range()]);
13604                });
13605            }
13606            _ => self.select_next(
13607                &SelectNext {
13608                    replace_newest: true,
13609                },
13610                window,
13611                cx,
13612            )?,
13613        }
13614        Ok(())
13615    }
13616
13617    pub fn find_previous_match(
13618        &mut self,
13619        _: &FindPreviousMatch,
13620        window: &mut Window,
13621        cx: &mut Context<Self>,
13622    ) -> Result<()> {
13623        let selections = self.selections.disjoint_anchors();
13624        match selections.last() {
13625            Some(last) if selections.len() >= 2 => {
13626                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13627                    s.select_ranges([last.range()]);
13628                });
13629            }
13630            _ => self.select_previous(
13631                &SelectPrevious {
13632                    replace_newest: true,
13633                },
13634                window,
13635                cx,
13636            )?,
13637        }
13638        Ok(())
13639    }
13640
13641    pub fn toggle_comments(
13642        &mut self,
13643        action: &ToggleComments,
13644        window: &mut Window,
13645        cx: &mut Context<Self>,
13646    ) {
13647        if self.read_only(cx) {
13648            return;
13649        }
13650        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13651        let text_layout_details = &self.text_layout_details(window);
13652        self.transact(window, cx, |this, window, cx| {
13653            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13654            let mut edits = Vec::new();
13655            let mut selection_edit_ranges = Vec::new();
13656            let mut last_toggled_row = None;
13657            let snapshot = this.buffer.read(cx).read(cx);
13658            let empty_str: Arc<str> = Arc::default();
13659            let mut suffixes_inserted = Vec::new();
13660            let ignore_indent = action.ignore_indent;
13661
13662            fn comment_prefix_range(
13663                snapshot: &MultiBufferSnapshot,
13664                row: MultiBufferRow,
13665                comment_prefix: &str,
13666                comment_prefix_whitespace: &str,
13667                ignore_indent: bool,
13668            ) -> Range<Point> {
13669                let indent_size = if ignore_indent {
13670                    0
13671                } else {
13672                    snapshot.indent_size_for_line(row).len
13673                };
13674
13675                let start = Point::new(row.0, indent_size);
13676
13677                let mut line_bytes = snapshot
13678                    .bytes_in_range(start..snapshot.max_point())
13679                    .flatten()
13680                    .copied();
13681
13682                // If this line currently begins with the line comment prefix, then record
13683                // the range containing the prefix.
13684                if line_bytes
13685                    .by_ref()
13686                    .take(comment_prefix.len())
13687                    .eq(comment_prefix.bytes())
13688                {
13689                    // Include any whitespace that matches the comment prefix.
13690                    let matching_whitespace_len = line_bytes
13691                        .zip(comment_prefix_whitespace.bytes())
13692                        .take_while(|(a, b)| a == b)
13693                        .count() as u32;
13694                    let end = Point::new(
13695                        start.row,
13696                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13697                    );
13698                    start..end
13699                } else {
13700                    start..start
13701                }
13702            }
13703
13704            fn comment_suffix_range(
13705                snapshot: &MultiBufferSnapshot,
13706                row: MultiBufferRow,
13707                comment_suffix: &str,
13708                comment_suffix_has_leading_space: bool,
13709            ) -> Range<Point> {
13710                let end = Point::new(row.0, snapshot.line_len(row));
13711                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13712
13713                let mut line_end_bytes = snapshot
13714                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13715                    .flatten()
13716                    .copied();
13717
13718                let leading_space_len = if suffix_start_column > 0
13719                    && line_end_bytes.next() == Some(b' ')
13720                    && comment_suffix_has_leading_space
13721                {
13722                    1
13723                } else {
13724                    0
13725                };
13726
13727                // If this line currently begins with the line comment prefix, then record
13728                // the range containing the prefix.
13729                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13730                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13731                    start..end
13732                } else {
13733                    end..end
13734                }
13735            }
13736
13737            // TODO: Handle selections that cross excerpts
13738            for selection in &mut selections {
13739                let start_column = snapshot
13740                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13741                    .len;
13742                let language = if let Some(language) =
13743                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13744                {
13745                    language
13746                } else {
13747                    continue;
13748                };
13749
13750                selection_edit_ranges.clear();
13751
13752                // If multiple selections contain a given row, avoid processing that
13753                // row more than once.
13754                let mut start_row = MultiBufferRow(selection.start.row);
13755                if last_toggled_row == Some(start_row) {
13756                    start_row = start_row.next_row();
13757                }
13758                let end_row =
13759                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13760                        MultiBufferRow(selection.end.row - 1)
13761                    } else {
13762                        MultiBufferRow(selection.end.row)
13763                    };
13764                last_toggled_row = Some(end_row);
13765
13766                if start_row > end_row {
13767                    continue;
13768                }
13769
13770                // If the language has line comments, toggle those.
13771                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13772
13773                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13774                if ignore_indent {
13775                    full_comment_prefixes = full_comment_prefixes
13776                        .into_iter()
13777                        .map(|s| Arc::from(s.trim_end()))
13778                        .collect();
13779                }
13780
13781                if !full_comment_prefixes.is_empty() {
13782                    let first_prefix = full_comment_prefixes
13783                        .first()
13784                        .expect("prefixes is non-empty");
13785                    let prefix_trimmed_lengths = full_comment_prefixes
13786                        .iter()
13787                        .map(|p| p.trim_end_matches(' ').len())
13788                        .collect::<SmallVec<[usize; 4]>>();
13789
13790                    let mut all_selection_lines_are_comments = true;
13791
13792                    for row in start_row.0..=end_row.0 {
13793                        let row = MultiBufferRow(row);
13794                        if start_row < end_row && snapshot.is_line_blank(row) {
13795                            continue;
13796                        }
13797
13798                        let prefix_range = full_comment_prefixes
13799                            .iter()
13800                            .zip(prefix_trimmed_lengths.iter().copied())
13801                            .map(|(prefix, trimmed_prefix_len)| {
13802                                comment_prefix_range(
13803                                    snapshot.deref(),
13804                                    row,
13805                                    &prefix[..trimmed_prefix_len],
13806                                    &prefix[trimmed_prefix_len..],
13807                                    ignore_indent,
13808                                )
13809                            })
13810                            .max_by_key(|range| range.end.column - range.start.column)
13811                            .expect("prefixes is non-empty");
13812
13813                        if prefix_range.is_empty() {
13814                            all_selection_lines_are_comments = false;
13815                        }
13816
13817                        selection_edit_ranges.push(prefix_range);
13818                    }
13819
13820                    if all_selection_lines_are_comments {
13821                        edits.extend(
13822                            selection_edit_ranges
13823                                .iter()
13824                                .cloned()
13825                                .map(|range| (range, empty_str.clone())),
13826                        );
13827                    } else {
13828                        let min_column = selection_edit_ranges
13829                            .iter()
13830                            .map(|range| range.start.column)
13831                            .min()
13832                            .unwrap_or(0);
13833                        edits.extend(selection_edit_ranges.iter().map(|range| {
13834                            let position = Point::new(range.start.row, min_column);
13835                            (position..position, first_prefix.clone())
13836                        }));
13837                    }
13838                } else if let Some((full_comment_prefix, comment_suffix)) =
13839                    language.block_comment_delimiters()
13840                {
13841                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13842                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13843                    let prefix_range = comment_prefix_range(
13844                        snapshot.deref(),
13845                        start_row,
13846                        comment_prefix,
13847                        comment_prefix_whitespace,
13848                        ignore_indent,
13849                    );
13850                    let suffix_range = comment_suffix_range(
13851                        snapshot.deref(),
13852                        end_row,
13853                        comment_suffix.trim_start_matches(' '),
13854                        comment_suffix.starts_with(' '),
13855                    );
13856
13857                    if prefix_range.is_empty() || suffix_range.is_empty() {
13858                        edits.push((
13859                            prefix_range.start..prefix_range.start,
13860                            full_comment_prefix.clone(),
13861                        ));
13862                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13863                        suffixes_inserted.push((end_row, comment_suffix.len()));
13864                    } else {
13865                        edits.push((prefix_range, empty_str.clone()));
13866                        edits.push((suffix_range, empty_str.clone()));
13867                    }
13868                } else {
13869                    continue;
13870                }
13871            }
13872
13873            drop(snapshot);
13874            this.buffer.update(cx, |buffer, cx| {
13875                buffer.edit(edits, None, cx);
13876            });
13877
13878            // Adjust selections so that they end before any comment suffixes that
13879            // were inserted.
13880            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13881            let mut selections = this.selections.all::<Point>(cx);
13882            let snapshot = this.buffer.read(cx).read(cx);
13883            for selection in &mut selections {
13884                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13885                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13886                        Ordering::Less => {
13887                            suffixes_inserted.next();
13888                            continue;
13889                        }
13890                        Ordering::Greater => break,
13891                        Ordering::Equal => {
13892                            if selection.end.column == snapshot.line_len(row) {
13893                                if selection.is_empty() {
13894                                    selection.start.column -= suffix_len as u32;
13895                                }
13896                                selection.end.column -= suffix_len as u32;
13897                            }
13898                            break;
13899                        }
13900                    }
13901                }
13902            }
13903
13904            drop(snapshot);
13905            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13906                s.select(selections)
13907            });
13908
13909            let selections = this.selections.all::<Point>(cx);
13910            let selections_on_single_row = selections.windows(2).all(|selections| {
13911                selections[0].start.row == selections[1].start.row
13912                    && selections[0].end.row == selections[1].end.row
13913                    && selections[0].start.row == selections[0].end.row
13914            });
13915            let selections_selecting = selections
13916                .iter()
13917                .any(|selection| selection.start != selection.end);
13918            let advance_downwards = action.advance_downwards
13919                && selections_on_single_row
13920                && !selections_selecting
13921                && !matches!(this.mode, EditorMode::SingleLine { .. });
13922
13923            if advance_downwards {
13924                let snapshot = this.buffer.read(cx).snapshot(cx);
13925
13926                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13927                    s.move_cursors_with(|display_snapshot, display_point, _| {
13928                        let mut point = display_point.to_point(display_snapshot);
13929                        point.row += 1;
13930                        point = snapshot.clip_point(point, Bias::Left);
13931                        let display_point = point.to_display_point(display_snapshot);
13932                        let goal = SelectionGoal::HorizontalPosition(
13933                            display_snapshot
13934                                .x_for_display_point(display_point, text_layout_details)
13935                                .into(),
13936                        );
13937                        (display_point, goal)
13938                    })
13939                });
13940            }
13941        });
13942    }
13943
13944    pub fn select_enclosing_symbol(
13945        &mut self,
13946        _: &SelectEnclosingSymbol,
13947        window: &mut Window,
13948        cx: &mut Context<Self>,
13949    ) {
13950        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13951
13952        let buffer = self.buffer.read(cx).snapshot(cx);
13953        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13954
13955        fn update_selection(
13956            selection: &Selection<usize>,
13957            buffer_snap: &MultiBufferSnapshot,
13958        ) -> Option<Selection<usize>> {
13959            let cursor = selection.head();
13960            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13961            for symbol in symbols.iter().rev() {
13962                let start = symbol.range.start.to_offset(buffer_snap);
13963                let end = symbol.range.end.to_offset(buffer_snap);
13964                let new_range = start..end;
13965                if start < selection.start || end > selection.end {
13966                    return Some(Selection {
13967                        id: selection.id,
13968                        start: new_range.start,
13969                        end: new_range.end,
13970                        goal: SelectionGoal::None,
13971                        reversed: selection.reversed,
13972                    });
13973                }
13974            }
13975            None
13976        }
13977
13978        let mut selected_larger_symbol = false;
13979        let new_selections = old_selections
13980            .iter()
13981            .map(|selection| match update_selection(selection, &buffer) {
13982                Some(new_selection) => {
13983                    if new_selection.range() != selection.range() {
13984                        selected_larger_symbol = true;
13985                    }
13986                    new_selection
13987                }
13988                None => selection.clone(),
13989            })
13990            .collect::<Vec<_>>();
13991
13992        if selected_larger_symbol {
13993            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13994                s.select(new_selections);
13995            });
13996        }
13997    }
13998
13999    pub fn select_larger_syntax_node(
14000        &mut self,
14001        _: &SelectLargerSyntaxNode,
14002        window: &mut Window,
14003        cx: &mut Context<Self>,
14004    ) {
14005        let Some(visible_row_count) = self.visible_row_count() else {
14006            return;
14007        };
14008        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14009        if old_selections.is_empty() {
14010            return;
14011        }
14012
14013        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14014
14015        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14016        let buffer = self.buffer.read(cx).snapshot(cx);
14017
14018        let mut selected_larger_node = false;
14019        let mut new_selections = old_selections
14020            .iter()
14021            .map(|selection| {
14022                let old_range = selection.start..selection.end;
14023
14024                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14025                    // manually select word at selection
14026                    if ["string_content", "inline"].contains(&node.kind()) {
14027                        let word_range = {
14028                            let display_point = buffer
14029                                .offset_to_point(old_range.start)
14030                                .to_display_point(&display_map);
14031                            let Range { start, end } =
14032                                movement::surrounding_word(&display_map, display_point);
14033                            start.to_point(&display_map).to_offset(&buffer)
14034                                ..end.to_point(&display_map).to_offset(&buffer)
14035                        };
14036                        // ignore if word is already selected
14037                        if !word_range.is_empty() && old_range != word_range {
14038                            let last_word_range = {
14039                                let display_point = buffer
14040                                    .offset_to_point(old_range.end)
14041                                    .to_display_point(&display_map);
14042                                let Range { start, end } =
14043                                    movement::surrounding_word(&display_map, display_point);
14044                                start.to_point(&display_map).to_offset(&buffer)
14045                                    ..end.to_point(&display_map).to_offset(&buffer)
14046                            };
14047                            // only select word if start and end point belongs to same word
14048                            if word_range == last_word_range {
14049                                selected_larger_node = true;
14050                                return Selection {
14051                                    id: selection.id,
14052                                    start: word_range.start,
14053                                    end: word_range.end,
14054                                    goal: SelectionGoal::None,
14055                                    reversed: selection.reversed,
14056                                };
14057                            }
14058                        }
14059                    }
14060                }
14061
14062                let mut new_range = old_range.clone();
14063                while let Some((_node, containing_range)) =
14064                    buffer.syntax_ancestor(new_range.clone())
14065                {
14066                    new_range = match containing_range {
14067                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14068                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14069                    };
14070                    if !display_map.intersects_fold(new_range.start)
14071                        && !display_map.intersects_fold(new_range.end)
14072                    {
14073                        break;
14074                    }
14075                }
14076
14077                selected_larger_node |= new_range != old_range;
14078                Selection {
14079                    id: selection.id,
14080                    start: new_range.start,
14081                    end: new_range.end,
14082                    goal: SelectionGoal::None,
14083                    reversed: selection.reversed,
14084                }
14085            })
14086            .collect::<Vec<_>>();
14087
14088        if !selected_larger_node {
14089            return; // don't put this call in the history
14090        }
14091
14092        // scroll based on transformation done to the last selection created by the user
14093        let (last_old, last_new) = old_selections
14094            .last()
14095            .zip(new_selections.last().cloned())
14096            .expect("old_selections isn't empty");
14097
14098        // revert selection
14099        let is_selection_reversed = {
14100            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14101            new_selections.last_mut().expect("checked above").reversed =
14102                should_newest_selection_be_reversed;
14103            should_newest_selection_be_reversed
14104        };
14105
14106        if selected_larger_node {
14107            self.select_syntax_node_history.disable_clearing = true;
14108            self.change_selections(None, window, cx, |s| {
14109                s.select(new_selections.clone());
14110            });
14111            self.select_syntax_node_history.disable_clearing = false;
14112        }
14113
14114        let start_row = last_new.start.to_display_point(&display_map).row().0;
14115        let end_row = last_new.end.to_display_point(&display_map).row().0;
14116        let selection_height = end_row - start_row + 1;
14117        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14118
14119        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14120        let scroll_behavior = if fits_on_the_screen {
14121            self.request_autoscroll(Autoscroll::fit(), cx);
14122            SelectSyntaxNodeScrollBehavior::FitSelection
14123        } else if is_selection_reversed {
14124            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14125            SelectSyntaxNodeScrollBehavior::CursorTop
14126        } else {
14127            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14128            SelectSyntaxNodeScrollBehavior::CursorBottom
14129        };
14130
14131        self.select_syntax_node_history.push((
14132            old_selections,
14133            scroll_behavior,
14134            is_selection_reversed,
14135        ));
14136    }
14137
14138    pub fn select_smaller_syntax_node(
14139        &mut self,
14140        _: &SelectSmallerSyntaxNode,
14141        window: &mut Window,
14142        cx: &mut Context<Self>,
14143    ) {
14144        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14145
14146        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14147            self.select_syntax_node_history.pop()
14148        {
14149            if let Some(selection) = selections.last_mut() {
14150                selection.reversed = is_selection_reversed;
14151            }
14152
14153            self.select_syntax_node_history.disable_clearing = true;
14154            self.change_selections(None, window, cx, |s| {
14155                s.select(selections.to_vec());
14156            });
14157            self.select_syntax_node_history.disable_clearing = false;
14158
14159            match scroll_behavior {
14160                SelectSyntaxNodeScrollBehavior::CursorTop => {
14161                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14162                }
14163                SelectSyntaxNodeScrollBehavior::FitSelection => {
14164                    self.request_autoscroll(Autoscroll::fit(), cx);
14165                }
14166                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14167                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14168                }
14169            }
14170        }
14171    }
14172
14173    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14174        if !EditorSettings::get_global(cx).gutter.runnables {
14175            self.clear_tasks();
14176            return Task::ready(());
14177        }
14178        let project = self.project.as_ref().map(Entity::downgrade);
14179        let task_sources = self.lsp_task_sources(cx);
14180        let multi_buffer = self.buffer.downgrade();
14181        cx.spawn_in(window, async move |editor, cx| {
14182            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14183            let Some(project) = project.and_then(|p| p.upgrade()) else {
14184                return;
14185            };
14186            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14187                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14188            }) else {
14189                return;
14190            };
14191
14192            let hide_runnables = project
14193                .update(cx, |project, cx| {
14194                    // Do not display any test indicators in non-dev server remote projects.
14195                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14196                })
14197                .unwrap_or(true);
14198            if hide_runnables {
14199                return;
14200            }
14201            let new_rows =
14202                cx.background_spawn({
14203                    let snapshot = display_snapshot.clone();
14204                    async move {
14205                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14206                    }
14207                })
14208                    .await;
14209            let Ok(lsp_tasks) =
14210                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14211            else {
14212                return;
14213            };
14214            let lsp_tasks = lsp_tasks.await;
14215
14216            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14217                lsp_tasks
14218                    .into_iter()
14219                    .flat_map(|(kind, tasks)| {
14220                        tasks.into_iter().filter_map(move |(location, task)| {
14221                            Some((kind.clone(), location?, task))
14222                        })
14223                    })
14224                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14225                        let buffer = location.target.buffer;
14226                        let buffer_snapshot = buffer.read(cx).snapshot();
14227                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14228                            |(excerpt_id, snapshot, _)| {
14229                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14230                                    display_snapshot
14231                                        .buffer_snapshot
14232                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14233                                } else {
14234                                    None
14235                                }
14236                            },
14237                        );
14238                        if let Some(offset) = offset {
14239                            let task_buffer_range =
14240                                location.target.range.to_point(&buffer_snapshot);
14241                            let context_buffer_range =
14242                                task_buffer_range.to_offset(&buffer_snapshot);
14243                            let context_range = BufferOffset(context_buffer_range.start)
14244                                ..BufferOffset(context_buffer_range.end);
14245
14246                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14247                                .or_insert_with(|| RunnableTasks {
14248                                    templates: Vec::new(),
14249                                    offset,
14250                                    column: task_buffer_range.start.column,
14251                                    extra_variables: HashMap::default(),
14252                                    context_range,
14253                                })
14254                                .templates
14255                                .push((kind, task.original_task().clone()));
14256                        }
14257
14258                        acc
14259                    })
14260            }) else {
14261                return;
14262            };
14263
14264            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14265                buffer.language_settings(cx).tasks.prefer_lsp
14266            }) else {
14267                return;
14268            };
14269
14270            let rows = Self::runnable_rows(
14271                project,
14272                display_snapshot,
14273                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14274                new_rows,
14275                cx.clone(),
14276            )
14277            .await;
14278            editor
14279                .update(cx, |editor, _| {
14280                    editor.clear_tasks();
14281                    for (key, mut value) in rows {
14282                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14283                            value.templates.extend(lsp_tasks.templates);
14284                        }
14285
14286                        editor.insert_tasks(key, value);
14287                    }
14288                    for (key, value) in lsp_tasks_by_rows {
14289                        editor.insert_tasks(key, value);
14290                    }
14291                })
14292                .ok();
14293        })
14294    }
14295    fn fetch_runnable_ranges(
14296        snapshot: &DisplaySnapshot,
14297        range: Range<Anchor>,
14298    ) -> Vec<language::RunnableRange> {
14299        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14300    }
14301
14302    fn runnable_rows(
14303        project: Entity<Project>,
14304        snapshot: DisplaySnapshot,
14305        prefer_lsp: bool,
14306        runnable_ranges: Vec<RunnableRange>,
14307        cx: AsyncWindowContext,
14308    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14309        cx.spawn(async move |cx| {
14310            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14311            for mut runnable in runnable_ranges {
14312                let Some(tasks) = cx
14313                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14314                    .ok()
14315                else {
14316                    continue;
14317                };
14318                let mut tasks = tasks.await;
14319
14320                if prefer_lsp {
14321                    tasks.retain(|(task_kind, _)| {
14322                        !matches!(task_kind, TaskSourceKind::Language { .. })
14323                    });
14324                }
14325                if tasks.is_empty() {
14326                    continue;
14327                }
14328
14329                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14330                let Some(row) = snapshot
14331                    .buffer_snapshot
14332                    .buffer_line_for_row(MultiBufferRow(point.row))
14333                    .map(|(_, range)| range.start.row)
14334                else {
14335                    continue;
14336                };
14337
14338                let context_range =
14339                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14340                runnable_rows.push((
14341                    (runnable.buffer_id, row),
14342                    RunnableTasks {
14343                        templates: tasks,
14344                        offset: snapshot
14345                            .buffer_snapshot
14346                            .anchor_before(runnable.run_range.start),
14347                        context_range,
14348                        column: point.column,
14349                        extra_variables: runnable.extra_captures,
14350                    },
14351                ));
14352            }
14353            runnable_rows
14354        })
14355    }
14356
14357    fn templates_with_tags(
14358        project: &Entity<Project>,
14359        runnable: &mut Runnable,
14360        cx: &mut App,
14361    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14362        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14363            let (worktree_id, file) = project
14364                .buffer_for_id(runnable.buffer, cx)
14365                .and_then(|buffer| buffer.read(cx).file())
14366                .map(|file| (file.worktree_id(cx), file.clone()))
14367                .unzip();
14368
14369            (
14370                project.task_store().read(cx).task_inventory().cloned(),
14371                worktree_id,
14372                file,
14373            )
14374        });
14375
14376        let tags = mem::take(&mut runnable.tags);
14377        let language = runnable.language.clone();
14378        cx.spawn(async move |cx| {
14379            let mut templates_with_tags = Vec::new();
14380            if let Some(inventory) = inventory {
14381                for RunnableTag(tag) in tags {
14382                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14383                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14384                    }) else {
14385                        return templates_with_tags;
14386                    };
14387                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14388                        move |(_, template)| {
14389                            template.tags.iter().any(|source_tag| source_tag == &tag)
14390                        },
14391                    ));
14392                }
14393            }
14394            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14395
14396            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14397                // Strongest source wins; if we have worktree tag binding, prefer that to
14398                // global and language bindings;
14399                // if we have a global binding, prefer that to language binding.
14400                let first_mismatch = templates_with_tags
14401                    .iter()
14402                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14403                if let Some(index) = first_mismatch {
14404                    templates_with_tags.truncate(index);
14405                }
14406            }
14407
14408            templates_with_tags
14409        })
14410    }
14411
14412    pub fn move_to_enclosing_bracket(
14413        &mut self,
14414        _: &MoveToEnclosingBracket,
14415        window: &mut Window,
14416        cx: &mut Context<Self>,
14417    ) {
14418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14419        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14420            s.move_offsets_with(|snapshot, selection| {
14421                let Some(enclosing_bracket_ranges) =
14422                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14423                else {
14424                    return;
14425                };
14426
14427                let mut best_length = usize::MAX;
14428                let mut best_inside = false;
14429                let mut best_in_bracket_range = false;
14430                let mut best_destination = None;
14431                for (open, close) in enclosing_bracket_ranges {
14432                    let close = close.to_inclusive();
14433                    let length = close.end() - open.start;
14434                    let inside = selection.start >= open.end && selection.end <= *close.start();
14435                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14436                        || close.contains(&selection.head());
14437
14438                    // If best is next to a bracket and current isn't, skip
14439                    if !in_bracket_range && best_in_bracket_range {
14440                        continue;
14441                    }
14442
14443                    // Prefer smaller lengths unless best is inside and current isn't
14444                    if length > best_length && (best_inside || !inside) {
14445                        continue;
14446                    }
14447
14448                    best_length = length;
14449                    best_inside = inside;
14450                    best_in_bracket_range = in_bracket_range;
14451                    best_destination = Some(
14452                        if close.contains(&selection.start) && close.contains(&selection.end) {
14453                            if inside { open.end } else { open.start }
14454                        } else if inside {
14455                            *close.start()
14456                        } else {
14457                            *close.end()
14458                        },
14459                    );
14460                }
14461
14462                if let Some(destination) = best_destination {
14463                    selection.collapse_to(destination, SelectionGoal::None);
14464                }
14465            })
14466        });
14467    }
14468
14469    pub fn undo_selection(
14470        &mut self,
14471        _: &UndoSelection,
14472        window: &mut Window,
14473        cx: &mut Context<Self>,
14474    ) {
14475        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14476        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14477            self.selection_history.mode = SelectionHistoryMode::Undoing;
14478            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14479                this.end_selection(window, cx);
14480                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14481                    s.select_anchors(entry.selections.to_vec())
14482                });
14483            });
14484            self.selection_history.mode = SelectionHistoryMode::Normal;
14485
14486            self.select_next_state = entry.select_next_state;
14487            self.select_prev_state = entry.select_prev_state;
14488            self.add_selections_state = entry.add_selections_state;
14489        }
14490    }
14491
14492    pub fn redo_selection(
14493        &mut self,
14494        _: &RedoSelection,
14495        window: &mut Window,
14496        cx: &mut Context<Self>,
14497    ) {
14498        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14499        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14500            self.selection_history.mode = SelectionHistoryMode::Redoing;
14501            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14502                this.end_selection(window, cx);
14503                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14504                    s.select_anchors(entry.selections.to_vec())
14505                });
14506            });
14507            self.selection_history.mode = SelectionHistoryMode::Normal;
14508
14509            self.select_next_state = entry.select_next_state;
14510            self.select_prev_state = entry.select_prev_state;
14511            self.add_selections_state = entry.add_selections_state;
14512        }
14513    }
14514
14515    pub fn expand_excerpts(
14516        &mut self,
14517        action: &ExpandExcerpts,
14518        _: &mut Window,
14519        cx: &mut Context<Self>,
14520    ) {
14521        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14522    }
14523
14524    pub fn expand_excerpts_down(
14525        &mut self,
14526        action: &ExpandExcerptsDown,
14527        _: &mut Window,
14528        cx: &mut Context<Self>,
14529    ) {
14530        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14531    }
14532
14533    pub fn expand_excerpts_up(
14534        &mut self,
14535        action: &ExpandExcerptsUp,
14536        _: &mut Window,
14537        cx: &mut Context<Self>,
14538    ) {
14539        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14540    }
14541
14542    pub fn expand_excerpts_for_direction(
14543        &mut self,
14544        lines: u32,
14545        direction: ExpandExcerptDirection,
14546
14547        cx: &mut Context<Self>,
14548    ) {
14549        let selections = self.selections.disjoint_anchors();
14550
14551        let lines = if lines == 0 {
14552            EditorSettings::get_global(cx).expand_excerpt_lines
14553        } else {
14554            lines
14555        };
14556
14557        self.buffer.update(cx, |buffer, cx| {
14558            let snapshot = buffer.snapshot(cx);
14559            let mut excerpt_ids = selections
14560                .iter()
14561                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14562                .collect::<Vec<_>>();
14563            excerpt_ids.sort();
14564            excerpt_ids.dedup();
14565            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14566        })
14567    }
14568
14569    pub fn expand_excerpt(
14570        &mut self,
14571        excerpt: ExcerptId,
14572        direction: ExpandExcerptDirection,
14573        window: &mut Window,
14574        cx: &mut Context<Self>,
14575    ) {
14576        let current_scroll_position = self.scroll_position(cx);
14577        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14578        let mut should_scroll_up = false;
14579
14580        if direction == ExpandExcerptDirection::Down {
14581            let multi_buffer = self.buffer.read(cx);
14582            let snapshot = multi_buffer.snapshot(cx);
14583            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14584                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14585                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14586                        let buffer_snapshot = buffer.read(cx).snapshot();
14587                        let excerpt_end_row =
14588                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14589                        let last_row = buffer_snapshot.max_point().row;
14590                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14591                        should_scroll_up = lines_below >= lines_to_expand;
14592                    }
14593                }
14594            }
14595        }
14596
14597        self.buffer.update(cx, |buffer, cx| {
14598            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14599        });
14600
14601        if should_scroll_up {
14602            let new_scroll_position =
14603                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14604            self.set_scroll_position(new_scroll_position, window, cx);
14605        }
14606    }
14607
14608    pub fn go_to_singleton_buffer_point(
14609        &mut self,
14610        point: Point,
14611        window: &mut Window,
14612        cx: &mut Context<Self>,
14613    ) {
14614        self.go_to_singleton_buffer_range(point..point, window, cx);
14615    }
14616
14617    pub fn go_to_singleton_buffer_range(
14618        &mut self,
14619        range: Range<Point>,
14620        window: &mut Window,
14621        cx: &mut Context<Self>,
14622    ) {
14623        let multibuffer = self.buffer().read(cx);
14624        let Some(buffer) = multibuffer.as_singleton() else {
14625            return;
14626        };
14627        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14628            return;
14629        };
14630        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14631            return;
14632        };
14633        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14634            s.select_anchor_ranges([start..end])
14635        });
14636    }
14637
14638    pub fn go_to_diagnostic(
14639        &mut self,
14640        _: &GoToDiagnostic,
14641        window: &mut Window,
14642        cx: &mut Context<Self>,
14643    ) {
14644        if !self.diagnostics_enabled() {
14645            return;
14646        }
14647        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14648        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14649    }
14650
14651    pub fn go_to_prev_diagnostic(
14652        &mut self,
14653        _: &GoToPreviousDiagnostic,
14654        window: &mut Window,
14655        cx: &mut Context<Self>,
14656    ) {
14657        if !self.diagnostics_enabled() {
14658            return;
14659        }
14660        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14661        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14662    }
14663
14664    pub fn go_to_diagnostic_impl(
14665        &mut self,
14666        direction: Direction,
14667        window: &mut Window,
14668        cx: &mut Context<Self>,
14669    ) {
14670        let buffer = self.buffer.read(cx).snapshot(cx);
14671        let selection = self.selections.newest::<usize>(cx);
14672
14673        let mut active_group_id = None;
14674        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14675            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14676                active_group_id = Some(active_group.group_id);
14677            }
14678        }
14679
14680        fn filtered(
14681            snapshot: EditorSnapshot,
14682            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14683        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14684            diagnostics
14685                .filter(|entry| entry.range.start != entry.range.end)
14686                .filter(|entry| !entry.diagnostic.is_unnecessary)
14687                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14688        }
14689
14690        let snapshot = self.snapshot(window, cx);
14691        let before = filtered(
14692            snapshot.clone(),
14693            buffer
14694                .diagnostics_in_range(0..selection.start)
14695                .filter(|entry| entry.range.start <= selection.start),
14696        );
14697        let after = filtered(
14698            snapshot,
14699            buffer
14700                .diagnostics_in_range(selection.start..buffer.len())
14701                .filter(|entry| entry.range.start >= selection.start),
14702        );
14703
14704        let mut found: Option<DiagnosticEntry<usize>> = None;
14705        if direction == Direction::Prev {
14706            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14707            {
14708                for diagnostic in prev_diagnostics.into_iter().rev() {
14709                    if diagnostic.range.start != selection.start
14710                        || active_group_id
14711                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14712                    {
14713                        found = Some(diagnostic);
14714                        break 'outer;
14715                    }
14716                }
14717            }
14718        } else {
14719            for diagnostic in after.chain(before) {
14720                if diagnostic.range.start != selection.start
14721                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14722                {
14723                    found = Some(diagnostic);
14724                    break;
14725                }
14726            }
14727        }
14728        let Some(next_diagnostic) = found else {
14729            return;
14730        };
14731
14732        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14733            return;
14734        };
14735        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14736            s.select_ranges(vec![
14737                next_diagnostic.range.start..next_diagnostic.range.start,
14738            ])
14739        });
14740        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14741        self.refresh_inline_completion(false, true, window, cx);
14742    }
14743
14744    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14745        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14746        let snapshot = self.snapshot(window, cx);
14747        let selection = self.selections.newest::<Point>(cx);
14748        self.go_to_hunk_before_or_after_position(
14749            &snapshot,
14750            selection.head(),
14751            Direction::Next,
14752            window,
14753            cx,
14754        );
14755    }
14756
14757    pub fn go_to_hunk_before_or_after_position(
14758        &mut self,
14759        snapshot: &EditorSnapshot,
14760        position: Point,
14761        direction: Direction,
14762        window: &mut Window,
14763        cx: &mut Context<Editor>,
14764    ) {
14765        let row = if direction == Direction::Next {
14766            self.hunk_after_position(snapshot, position)
14767                .map(|hunk| hunk.row_range.start)
14768        } else {
14769            self.hunk_before_position(snapshot, position)
14770        };
14771
14772        if let Some(row) = row {
14773            let destination = Point::new(row.0, 0);
14774            let autoscroll = Autoscroll::center();
14775
14776            self.unfold_ranges(&[destination..destination], false, false, cx);
14777            self.change_selections(Some(autoscroll), window, cx, |s| {
14778                s.select_ranges([destination..destination]);
14779            });
14780        }
14781    }
14782
14783    fn hunk_after_position(
14784        &mut self,
14785        snapshot: &EditorSnapshot,
14786        position: Point,
14787    ) -> Option<MultiBufferDiffHunk> {
14788        snapshot
14789            .buffer_snapshot
14790            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14791            .find(|hunk| hunk.row_range.start.0 > position.row)
14792            .or_else(|| {
14793                snapshot
14794                    .buffer_snapshot
14795                    .diff_hunks_in_range(Point::zero()..position)
14796                    .find(|hunk| hunk.row_range.end.0 < position.row)
14797            })
14798    }
14799
14800    fn go_to_prev_hunk(
14801        &mut self,
14802        _: &GoToPreviousHunk,
14803        window: &mut Window,
14804        cx: &mut Context<Self>,
14805    ) {
14806        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14807        let snapshot = self.snapshot(window, cx);
14808        let selection = self.selections.newest::<Point>(cx);
14809        self.go_to_hunk_before_or_after_position(
14810            &snapshot,
14811            selection.head(),
14812            Direction::Prev,
14813            window,
14814            cx,
14815        );
14816    }
14817
14818    fn hunk_before_position(
14819        &mut self,
14820        snapshot: &EditorSnapshot,
14821        position: Point,
14822    ) -> Option<MultiBufferRow> {
14823        snapshot
14824            .buffer_snapshot
14825            .diff_hunk_before(position)
14826            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14827    }
14828
14829    fn go_to_next_change(
14830        &mut self,
14831        _: &GoToNextChange,
14832        window: &mut Window,
14833        cx: &mut Context<Self>,
14834    ) {
14835        if let Some(selections) = self
14836            .change_list
14837            .next_change(1, Direction::Next)
14838            .map(|s| s.to_vec())
14839        {
14840            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14841                let map = s.display_map();
14842                s.select_display_ranges(selections.iter().map(|a| {
14843                    let point = a.to_display_point(&map);
14844                    point..point
14845                }))
14846            })
14847        }
14848    }
14849
14850    fn go_to_previous_change(
14851        &mut self,
14852        _: &GoToPreviousChange,
14853        window: &mut Window,
14854        cx: &mut Context<Self>,
14855    ) {
14856        if let Some(selections) = self
14857            .change_list
14858            .next_change(1, Direction::Prev)
14859            .map(|s| s.to_vec())
14860        {
14861            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14862                let map = s.display_map();
14863                s.select_display_ranges(selections.iter().map(|a| {
14864                    let point = a.to_display_point(&map);
14865                    point..point
14866                }))
14867            })
14868        }
14869    }
14870
14871    fn go_to_line<T: 'static>(
14872        &mut self,
14873        position: Anchor,
14874        highlight_color: Option<Hsla>,
14875        window: &mut Window,
14876        cx: &mut Context<Self>,
14877    ) {
14878        let snapshot = self.snapshot(window, cx).display_snapshot;
14879        let position = position.to_point(&snapshot.buffer_snapshot);
14880        let start = snapshot
14881            .buffer_snapshot
14882            .clip_point(Point::new(position.row, 0), Bias::Left);
14883        let end = start + Point::new(1, 0);
14884        let start = snapshot.buffer_snapshot.anchor_before(start);
14885        let end = snapshot.buffer_snapshot.anchor_before(end);
14886
14887        self.highlight_rows::<T>(
14888            start..end,
14889            highlight_color
14890                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14891            Default::default(),
14892            cx,
14893        );
14894
14895        if self.buffer.read(cx).is_singleton() {
14896            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14897        }
14898    }
14899
14900    pub fn go_to_definition(
14901        &mut self,
14902        _: &GoToDefinition,
14903        window: &mut Window,
14904        cx: &mut Context<Self>,
14905    ) -> Task<Result<Navigated>> {
14906        let definition =
14907            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14908        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14909        cx.spawn_in(window, async move |editor, cx| {
14910            if definition.await? == Navigated::Yes {
14911                return Ok(Navigated::Yes);
14912            }
14913            match fallback_strategy {
14914                GoToDefinitionFallback::None => Ok(Navigated::No),
14915                GoToDefinitionFallback::FindAllReferences => {
14916                    match editor.update_in(cx, |editor, window, cx| {
14917                        editor.find_all_references(&FindAllReferences, window, cx)
14918                    })? {
14919                        Some(references) => references.await,
14920                        None => Ok(Navigated::No),
14921                    }
14922                }
14923            }
14924        })
14925    }
14926
14927    pub fn go_to_declaration(
14928        &mut self,
14929        _: &GoToDeclaration,
14930        window: &mut Window,
14931        cx: &mut Context<Self>,
14932    ) -> Task<Result<Navigated>> {
14933        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14934    }
14935
14936    pub fn go_to_declaration_split(
14937        &mut self,
14938        _: &GoToDeclaration,
14939        window: &mut Window,
14940        cx: &mut Context<Self>,
14941    ) -> Task<Result<Navigated>> {
14942        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14943    }
14944
14945    pub fn go_to_implementation(
14946        &mut self,
14947        _: &GoToImplementation,
14948        window: &mut Window,
14949        cx: &mut Context<Self>,
14950    ) -> Task<Result<Navigated>> {
14951        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14952    }
14953
14954    pub fn go_to_implementation_split(
14955        &mut self,
14956        _: &GoToImplementationSplit,
14957        window: &mut Window,
14958        cx: &mut Context<Self>,
14959    ) -> Task<Result<Navigated>> {
14960        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14961    }
14962
14963    pub fn go_to_type_definition(
14964        &mut self,
14965        _: &GoToTypeDefinition,
14966        window: &mut Window,
14967        cx: &mut Context<Self>,
14968    ) -> Task<Result<Navigated>> {
14969        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14970    }
14971
14972    pub fn go_to_definition_split(
14973        &mut self,
14974        _: &GoToDefinitionSplit,
14975        window: &mut Window,
14976        cx: &mut Context<Self>,
14977    ) -> Task<Result<Navigated>> {
14978        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14979    }
14980
14981    pub fn go_to_type_definition_split(
14982        &mut self,
14983        _: &GoToTypeDefinitionSplit,
14984        window: &mut Window,
14985        cx: &mut Context<Self>,
14986    ) -> Task<Result<Navigated>> {
14987        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14988    }
14989
14990    fn go_to_definition_of_kind(
14991        &mut self,
14992        kind: GotoDefinitionKind,
14993        split: bool,
14994        window: &mut Window,
14995        cx: &mut Context<Self>,
14996    ) -> Task<Result<Navigated>> {
14997        let Some(provider) = self.semantics_provider.clone() else {
14998            return Task::ready(Ok(Navigated::No));
14999        };
15000        let head = self.selections.newest::<usize>(cx).head();
15001        let buffer = self.buffer.read(cx);
15002        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15003            text_anchor
15004        } else {
15005            return Task::ready(Ok(Navigated::No));
15006        };
15007
15008        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15009            return Task::ready(Ok(Navigated::No));
15010        };
15011
15012        cx.spawn_in(window, async move |editor, cx| {
15013            let definitions = definitions.await?;
15014            let navigated = editor
15015                .update_in(cx, |editor, window, cx| {
15016                    editor.navigate_to_hover_links(
15017                        Some(kind),
15018                        definitions
15019                            .into_iter()
15020                            .filter(|location| {
15021                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15022                            })
15023                            .map(HoverLink::Text)
15024                            .collect::<Vec<_>>(),
15025                        split,
15026                        window,
15027                        cx,
15028                    )
15029                })?
15030                .await?;
15031            anyhow::Ok(navigated)
15032        })
15033    }
15034
15035    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15036        let selection = self.selections.newest_anchor();
15037        let head = selection.head();
15038        let tail = selection.tail();
15039
15040        let Some((buffer, start_position)) =
15041            self.buffer.read(cx).text_anchor_for_position(head, cx)
15042        else {
15043            return;
15044        };
15045
15046        let end_position = if head != tail {
15047            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15048                return;
15049            };
15050            Some(pos)
15051        } else {
15052            None
15053        };
15054
15055        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15056            let url = if let Some(end_pos) = end_position {
15057                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15058            } else {
15059                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15060            };
15061
15062            if let Some(url) = url {
15063                editor.update(cx, |_, cx| {
15064                    cx.open_url(&url);
15065                })
15066            } else {
15067                Ok(())
15068            }
15069        });
15070
15071        url_finder.detach();
15072    }
15073
15074    pub fn open_selected_filename(
15075        &mut self,
15076        _: &OpenSelectedFilename,
15077        window: &mut Window,
15078        cx: &mut Context<Self>,
15079    ) {
15080        let Some(workspace) = self.workspace() else {
15081            return;
15082        };
15083
15084        let position = self.selections.newest_anchor().head();
15085
15086        let Some((buffer, buffer_position)) =
15087            self.buffer.read(cx).text_anchor_for_position(position, cx)
15088        else {
15089            return;
15090        };
15091
15092        let project = self.project.clone();
15093
15094        cx.spawn_in(window, async move |_, cx| {
15095            let result = find_file(&buffer, project, buffer_position, cx).await;
15096
15097            if let Some((_, path)) = result {
15098                workspace
15099                    .update_in(cx, |workspace, window, cx| {
15100                        workspace.open_resolved_path(path, window, cx)
15101                    })?
15102                    .await?;
15103            }
15104            anyhow::Ok(())
15105        })
15106        .detach();
15107    }
15108
15109    pub(crate) fn navigate_to_hover_links(
15110        &mut self,
15111        kind: Option<GotoDefinitionKind>,
15112        mut definitions: Vec<HoverLink>,
15113        split: bool,
15114        window: &mut Window,
15115        cx: &mut Context<Editor>,
15116    ) -> Task<Result<Navigated>> {
15117        // If there is one definition, just open it directly
15118        if definitions.len() == 1 {
15119            let definition = definitions.pop().unwrap();
15120
15121            enum TargetTaskResult {
15122                Location(Option<Location>),
15123                AlreadyNavigated,
15124            }
15125
15126            let target_task = match definition {
15127                HoverLink::Text(link) => {
15128                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15129                }
15130                HoverLink::InlayHint(lsp_location, server_id) => {
15131                    let computation =
15132                        self.compute_target_location(lsp_location, server_id, window, cx);
15133                    cx.background_spawn(async move {
15134                        let location = computation.await?;
15135                        Ok(TargetTaskResult::Location(location))
15136                    })
15137                }
15138                HoverLink::Url(url) => {
15139                    cx.open_url(&url);
15140                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15141                }
15142                HoverLink::File(path) => {
15143                    if let Some(workspace) = self.workspace() {
15144                        cx.spawn_in(window, async move |_, cx| {
15145                            workspace
15146                                .update_in(cx, |workspace, window, cx| {
15147                                    workspace.open_resolved_path(path, window, cx)
15148                                })?
15149                                .await
15150                                .map(|_| TargetTaskResult::AlreadyNavigated)
15151                        })
15152                    } else {
15153                        Task::ready(Ok(TargetTaskResult::Location(None)))
15154                    }
15155                }
15156            };
15157            cx.spawn_in(window, async move |editor, cx| {
15158                let target = match target_task.await.context("target resolution task")? {
15159                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15160                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15161                    TargetTaskResult::Location(Some(target)) => target,
15162                };
15163
15164                editor.update_in(cx, |editor, window, cx| {
15165                    let Some(workspace) = editor.workspace() else {
15166                        return Navigated::No;
15167                    };
15168                    let pane = workspace.read(cx).active_pane().clone();
15169
15170                    let range = target.range.to_point(target.buffer.read(cx));
15171                    let range = editor.range_for_match(&range);
15172                    let range = collapse_multiline_range(range);
15173
15174                    if !split
15175                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15176                    {
15177                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15178                    } else {
15179                        window.defer(cx, move |window, cx| {
15180                            let target_editor: Entity<Self> =
15181                                workspace.update(cx, |workspace, cx| {
15182                                    let pane = if split {
15183                                        workspace.adjacent_pane(window, cx)
15184                                    } else {
15185                                        workspace.active_pane().clone()
15186                                    };
15187
15188                                    workspace.open_project_item(
15189                                        pane,
15190                                        target.buffer.clone(),
15191                                        true,
15192                                        true,
15193                                        window,
15194                                        cx,
15195                                    )
15196                                });
15197                            target_editor.update(cx, |target_editor, cx| {
15198                                // When selecting a definition in a different buffer, disable the nav history
15199                                // to avoid creating a history entry at the previous cursor location.
15200                                pane.update(cx, |pane, _| pane.disable_history());
15201                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15202                                pane.update(cx, |pane, _| pane.enable_history());
15203                            });
15204                        });
15205                    }
15206                    Navigated::Yes
15207                })
15208            })
15209        } else if !definitions.is_empty() {
15210            cx.spawn_in(window, async move |editor, cx| {
15211                let (title, location_tasks, workspace) = editor
15212                    .update_in(cx, |editor, window, cx| {
15213                        let tab_kind = match kind {
15214                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15215                            _ => "Definitions",
15216                        };
15217                        let title = definitions
15218                            .iter()
15219                            .find_map(|definition| match definition {
15220                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15221                                    let buffer = origin.buffer.read(cx);
15222                                    format!(
15223                                        "{} for {}",
15224                                        tab_kind,
15225                                        buffer
15226                                            .text_for_range(origin.range.clone())
15227                                            .collect::<String>()
15228                                    )
15229                                }),
15230                                HoverLink::InlayHint(_, _) => None,
15231                                HoverLink::Url(_) => None,
15232                                HoverLink::File(_) => None,
15233                            })
15234                            .unwrap_or(tab_kind.to_string());
15235                        let location_tasks = definitions
15236                            .into_iter()
15237                            .map(|definition| match definition {
15238                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15239                                HoverLink::InlayHint(lsp_location, server_id) => editor
15240                                    .compute_target_location(lsp_location, server_id, window, cx),
15241                                HoverLink::Url(_) => Task::ready(Ok(None)),
15242                                HoverLink::File(_) => Task::ready(Ok(None)),
15243                            })
15244                            .collect::<Vec<_>>();
15245                        (title, location_tasks, editor.workspace().clone())
15246                    })
15247                    .context("location tasks preparation")?;
15248
15249                let locations: Vec<Location> = future::join_all(location_tasks)
15250                    .await
15251                    .into_iter()
15252                    .filter_map(|location| location.transpose())
15253                    .collect::<Result<_>>()
15254                    .context("location tasks")?;
15255
15256                if locations.is_empty() {
15257                    return Ok(Navigated::No);
15258                }
15259
15260                let Some(workspace) = workspace else {
15261                    return Ok(Navigated::No);
15262                };
15263
15264                let opened = workspace
15265                    .update_in(cx, |workspace, window, cx| {
15266                        Self::open_locations_in_multibuffer(
15267                            workspace,
15268                            locations,
15269                            title,
15270                            split,
15271                            MultibufferSelectionMode::First,
15272                            window,
15273                            cx,
15274                        )
15275                    })
15276                    .ok();
15277
15278                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15279            })
15280        } else {
15281            Task::ready(Ok(Navigated::No))
15282        }
15283    }
15284
15285    fn compute_target_location(
15286        &self,
15287        lsp_location: lsp::Location,
15288        server_id: LanguageServerId,
15289        window: &mut Window,
15290        cx: &mut Context<Self>,
15291    ) -> Task<anyhow::Result<Option<Location>>> {
15292        let Some(project) = self.project.clone() else {
15293            return Task::ready(Ok(None));
15294        };
15295
15296        cx.spawn_in(window, async move |editor, cx| {
15297            let location_task = editor.update(cx, |_, cx| {
15298                project.update(cx, |project, cx| {
15299                    let language_server_name = project
15300                        .language_server_statuses(cx)
15301                        .find(|(id, _)| server_id == *id)
15302                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15303                    language_server_name.map(|language_server_name| {
15304                        project.open_local_buffer_via_lsp(
15305                            lsp_location.uri.clone(),
15306                            server_id,
15307                            language_server_name,
15308                            cx,
15309                        )
15310                    })
15311                })
15312            })?;
15313            let location = match location_task {
15314                Some(task) => Some({
15315                    let target_buffer_handle = task.await.context("open local buffer")?;
15316                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15317                        let target_start = target_buffer
15318                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15319                        let target_end = target_buffer
15320                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15321                        target_buffer.anchor_after(target_start)
15322                            ..target_buffer.anchor_before(target_end)
15323                    })?;
15324                    Location {
15325                        buffer: target_buffer_handle,
15326                        range,
15327                    }
15328                }),
15329                None => None,
15330            };
15331            Ok(location)
15332        })
15333    }
15334
15335    pub fn find_all_references(
15336        &mut self,
15337        _: &FindAllReferences,
15338        window: &mut Window,
15339        cx: &mut Context<Self>,
15340    ) -> Option<Task<Result<Navigated>>> {
15341        let selection = self.selections.newest::<usize>(cx);
15342        let multi_buffer = self.buffer.read(cx);
15343        let head = selection.head();
15344
15345        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15346        let head_anchor = multi_buffer_snapshot.anchor_at(
15347            head,
15348            if head < selection.tail() {
15349                Bias::Right
15350            } else {
15351                Bias::Left
15352            },
15353        );
15354
15355        match self
15356            .find_all_references_task_sources
15357            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15358        {
15359            Ok(_) => {
15360                log::info!(
15361                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15362                );
15363                return None;
15364            }
15365            Err(i) => {
15366                self.find_all_references_task_sources.insert(i, head_anchor);
15367            }
15368        }
15369
15370        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15371        let workspace = self.workspace()?;
15372        let project = workspace.read(cx).project().clone();
15373        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15374        Some(cx.spawn_in(window, async move |editor, cx| {
15375            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15376                if let Ok(i) = editor
15377                    .find_all_references_task_sources
15378                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15379                {
15380                    editor.find_all_references_task_sources.remove(i);
15381                }
15382            });
15383
15384            let locations = references.await?;
15385            if locations.is_empty() {
15386                return anyhow::Ok(Navigated::No);
15387            }
15388
15389            workspace.update_in(cx, |workspace, window, cx| {
15390                let title = locations
15391                    .first()
15392                    .as_ref()
15393                    .map(|location| {
15394                        let buffer = location.buffer.read(cx);
15395                        format!(
15396                            "References to `{}`",
15397                            buffer
15398                                .text_for_range(location.range.clone())
15399                                .collect::<String>()
15400                        )
15401                    })
15402                    .unwrap();
15403                Self::open_locations_in_multibuffer(
15404                    workspace,
15405                    locations,
15406                    title,
15407                    false,
15408                    MultibufferSelectionMode::First,
15409                    window,
15410                    cx,
15411                );
15412                Navigated::Yes
15413            })
15414        }))
15415    }
15416
15417    /// Opens a multibuffer with the given project locations in it
15418    pub fn open_locations_in_multibuffer(
15419        workspace: &mut Workspace,
15420        mut locations: Vec<Location>,
15421        title: String,
15422        split: bool,
15423        multibuffer_selection_mode: MultibufferSelectionMode,
15424        window: &mut Window,
15425        cx: &mut Context<Workspace>,
15426    ) {
15427        if locations.is_empty() {
15428            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15429            return;
15430        }
15431
15432        // If there are multiple definitions, open them in a multibuffer
15433        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15434        let mut locations = locations.into_iter().peekable();
15435        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15436        let capability = workspace.project().read(cx).capability();
15437
15438        let excerpt_buffer = cx.new(|cx| {
15439            let mut multibuffer = MultiBuffer::new(capability);
15440            while let Some(location) = locations.next() {
15441                let buffer = location.buffer.read(cx);
15442                let mut ranges_for_buffer = Vec::new();
15443                let range = location.range.to_point(buffer);
15444                ranges_for_buffer.push(range.clone());
15445
15446                while let Some(next_location) = locations.peek() {
15447                    if next_location.buffer == location.buffer {
15448                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15449                        locations.next();
15450                    } else {
15451                        break;
15452                    }
15453                }
15454
15455                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15456                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15457                    PathKey::for_buffer(&location.buffer, cx),
15458                    location.buffer.clone(),
15459                    ranges_for_buffer,
15460                    DEFAULT_MULTIBUFFER_CONTEXT,
15461                    cx,
15462                );
15463                ranges.extend(new_ranges)
15464            }
15465
15466            multibuffer.with_title(title)
15467        });
15468
15469        let editor = cx.new(|cx| {
15470            Editor::for_multibuffer(
15471                excerpt_buffer,
15472                Some(workspace.project().clone()),
15473                window,
15474                cx,
15475            )
15476        });
15477        editor.update(cx, |editor, cx| {
15478            match multibuffer_selection_mode {
15479                MultibufferSelectionMode::First => {
15480                    if let Some(first_range) = ranges.first() {
15481                        editor.change_selections(None, window, cx, |selections| {
15482                            selections.clear_disjoint();
15483                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15484                        });
15485                    }
15486                    editor.highlight_background::<Self>(
15487                        &ranges,
15488                        |theme| theme.colors().editor_highlighted_line_background,
15489                        cx,
15490                    );
15491                }
15492                MultibufferSelectionMode::All => {
15493                    editor.change_selections(None, window, cx, |selections| {
15494                        selections.clear_disjoint();
15495                        selections.select_anchor_ranges(ranges);
15496                    });
15497                }
15498            }
15499            editor.register_buffers_with_language_servers(cx);
15500        });
15501
15502        let item = Box::new(editor);
15503        let item_id = item.item_id();
15504
15505        if split {
15506            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15507        } else {
15508            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15509                let (preview_item_id, preview_item_idx) =
15510                    workspace.active_pane().read_with(cx, |pane, _| {
15511                        (pane.preview_item_id(), pane.preview_item_idx())
15512                    });
15513
15514                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15515
15516                if let Some(preview_item_id) = preview_item_id {
15517                    workspace.active_pane().update(cx, |pane, cx| {
15518                        pane.remove_item(preview_item_id, false, false, window, cx);
15519                    });
15520                }
15521            } else {
15522                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15523            }
15524        }
15525        workspace.active_pane().update(cx, |pane, cx| {
15526            pane.set_preview_item_id(Some(item_id), cx);
15527        });
15528    }
15529
15530    pub fn rename(
15531        &mut self,
15532        _: &Rename,
15533        window: &mut Window,
15534        cx: &mut Context<Self>,
15535    ) -> Option<Task<Result<()>>> {
15536        use language::ToOffset as _;
15537
15538        let provider = self.semantics_provider.clone()?;
15539        let selection = self.selections.newest_anchor().clone();
15540        let (cursor_buffer, cursor_buffer_position) = self
15541            .buffer
15542            .read(cx)
15543            .text_anchor_for_position(selection.head(), cx)?;
15544        let (tail_buffer, cursor_buffer_position_end) = self
15545            .buffer
15546            .read(cx)
15547            .text_anchor_for_position(selection.tail(), cx)?;
15548        if tail_buffer != cursor_buffer {
15549            return None;
15550        }
15551
15552        let snapshot = cursor_buffer.read(cx).snapshot();
15553        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15554        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15555        let prepare_rename = provider
15556            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15557            .unwrap_or_else(|| Task::ready(Ok(None)));
15558        drop(snapshot);
15559
15560        Some(cx.spawn_in(window, async move |this, cx| {
15561            let rename_range = if let Some(range) = prepare_rename.await? {
15562                Some(range)
15563            } else {
15564                this.update(cx, |this, cx| {
15565                    let buffer = this.buffer.read(cx).snapshot(cx);
15566                    let mut buffer_highlights = this
15567                        .document_highlights_for_position(selection.head(), &buffer)
15568                        .filter(|highlight| {
15569                            highlight.start.excerpt_id == selection.head().excerpt_id
15570                                && highlight.end.excerpt_id == selection.head().excerpt_id
15571                        });
15572                    buffer_highlights
15573                        .next()
15574                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15575                })?
15576            };
15577            if let Some(rename_range) = rename_range {
15578                this.update_in(cx, |this, window, cx| {
15579                    let snapshot = cursor_buffer.read(cx).snapshot();
15580                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15581                    let cursor_offset_in_rename_range =
15582                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15583                    let cursor_offset_in_rename_range_end =
15584                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15585
15586                    this.take_rename(false, window, cx);
15587                    let buffer = this.buffer.read(cx).read(cx);
15588                    let cursor_offset = selection.head().to_offset(&buffer);
15589                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15590                    let rename_end = rename_start + rename_buffer_range.len();
15591                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15592                    let mut old_highlight_id = None;
15593                    let old_name: Arc<str> = buffer
15594                        .chunks(rename_start..rename_end, true)
15595                        .map(|chunk| {
15596                            if old_highlight_id.is_none() {
15597                                old_highlight_id = chunk.syntax_highlight_id;
15598                            }
15599                            chunk.text
15600                        })
15601                        .collect::<String>()
15602                        .into();
15603
15604                    drop(buffer);
15605
15606                    // Position the selection in the rename editor so that it matches the current selection.
15607                    this.show_local_selections = false;
15608                    let rename_editor = cx.new(|cx| {
15609                        let mut editor = Editor::single_line(window, cx);
15610                        editor.buffer.update(cx, |buffer, cx| {
15611                            buffer.edit([(0..0, old_name.clone())], None, cx)
15612                        });
15613                        let rename_selection_range = match cursor_offset_in_rename_range
15614                            .cmp(&cursor_offset_in_rename_range_end)
15615                        {
15616                            Ordering::Equal => {
15617                                editor.select_all(&SelectAll, window, cx);
15618                                return editor;
15619                            }
15620                            Ordering::Less => {
15621                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15622                            }
15623                            Ordering::Greater => {
15624                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15625                            }
15626                        };
15627                        if rename_selection_range.end > old_name.len() {
15628                            editor.select_all(&SelectAll, window, cx);
15629                        } else {
15630                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15631                                s.select_ranges([rename_selection_range]);
15632                            });
15633                        }
15634                        editor
15635                    });
15636                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15637                        if e == &EditorEvent::Focused {
15638                            cx.emit(EditorEvent::FocusedIn)
15639                        }
15640                    })
15641                    .detach();
15642
15643                    let write_highlights =
15644                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15645                    let read_highlights =
15646                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15647                    let ranges = write_highlights
15648                        .iter()
15649                        .flat_map(|(_, ranges)| ranges.iter())
15650                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15651                        .cloned()
15652                        .collect();
15653
15654                    this.highlight_text::<Rename>(
15655                        ranges,
15656                        HighlightStyle {
15657                            fade_out: Some(0.6),
15658                            ..Default::default()
15659                        },
15660                        cx,
15661                    );
15662                    let rename_focus_handle = rename_editor.focus_handle(cx);
15663                    window.focus(&rename_focus_handle);
15664                    let block_id = this.insert_blocks(
15665                        [BlockProperties {
15666                            style: BlockStyle::Flex,
15667                            placement: BlockPlacement::Below(range.start),
15668                            height: Some(1),
15669                            render: Arc::new({
15670                                let rename_editor = rename_editor.clone();
15671                                move |cx: &mut BlockContext| {
15672                                    let mut text_style = cx.editor_style.text.clone();
15673                                    if let Some(highlight_style) = old_highlight_id
15674                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15675                                    {
15676                                        text_style = text_style.highlight(highlight_style);
15677                                    }
15678                                    div()
15679                                        .block_mouse_except_scroll()
15680                                        .pl(cx.anchor_x)
15681                                        .child(EditorElement::new(
15682                                            &rename_editor,
15683                                            EditorStyle {
15684                                                background: cx.theme().system().transparent,
15685                                                local_player: cx.editor_style.local_player,
15686                                                text: text_style,
15687                                                scrollbar_width: cx.editor_style.scrollbar_width,
15688                                                syntax: cx.editor_style.syntax.clone(),
15689                                                status: cx.editor_style.status.clone(),
15690                                                inlay_hints_style: HighlightStyle {
15691                                                    font_weight: Some(FontWeight::BOLD),
15692                                                    ..make_inlay_hints_style(cx.app)
15693                                                },
15694                                                inline_completion_styles: make_suggestion_styles(
15695                                                    cx.app,
15696                                                ),
15697                                                ..EditorStyle::default()
15698                                            },
15699                                        ))
15700                                        .into_any_element()
15701                                }
15702                            }),
15703                            priority: 0,
15704                            render_in_minimap: true,
15705                        }],
15706                        Some(Autoscroll::fit()),
15707                        cx,
15708                    )[0];
15709                    this.pending_rename = Some(RenameState {
15710                        range,
15711                        old_name,
15712                        editor: rename_editor,
15713                        block_id,
15714                    });
15715                })?;
15716            }
15717
15718            Ok(())
15719        }))
15720    }
15721
15722    pub fn confirm_rename(
15723        &mut self,
15724        _: &ConfirmRename,
15725        window: &mut Window,
15726        cx: &mut Context<Self>,
15727    ) -> Option<Task<Result<()>>> {
15728        let rename = self.take_rename(false, window, cx)?;
15729        let workspace = self.workspace()?.downgrade();
15730        let (buffer, start) = self
15731            .buffer
15732            .read(cx)
15733            .text_anchor_for_position(rename.range.start, cx)?;
15734        let (end_buffer, _) = self
15735            .buffer
15736            .read(cx)
15737            .text_anchor_for_position(rename.range.end, cx)?;
15738        if buffer != end_buffer {
15739            return None;
15740        }
15741
15742        let old_name = rename.old_name;
15743        let new_name = rename.editor.read(cx).text(cx);
15744
15745        let rename = self.semantics_provider.as_ref()?.perform_rename(
15746            &buffer,
15747            start,
15748            new_name.clone(),
15749            cx,
15750        )?;
15751
15752        Some(cx.spawn_in(window, async move |editor, cx| {
15753            let project_transaction = rename.await?;
15754            Self::open_project_transaction(
15755                &editor,
15756                workspace,
15757                project_transaction,
15758                format!("Rename: {}{}", old_name, new_name),
15759                cx,
15760            )
15761            .await?;
15762
15763            editor.update(cx, |editor, cx| {
15764                editor.refresh_document_highlights(cx);
15765            })?;
15766            Ok(())
15767        }))
15768    }
15769
15770    fn take_rename(
15771        &mut self,
15772        moving_cursor: bool,
15773        window: &mut Window,
15774        cx: &mut Context<Self>,
15775    ) -> Option<RenameState> {
15776        let rename = self.pending_rename.take()?;
15777        if rename.editor.focus_handle(cx).is_focused(window) {
15778            window.focus(&self.focus_handle);
15779        }
15780
15781        self.remove_blocks(
15782            [rename.block_id].into_iter().collect(),
15783            Some(Autoscroll::fit()),
15784            cx,
15785        );
15786        self.clear_highlights::<Rename>(cx);
15787        self.show_local_selections = true;
15788
15789        if moving_cursor {
15790            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15791                editor.selections.newest::<usize>(cx).head()
15792            });
15793
15794            // Update the selection to match the position of the selection inside
15795            // the rename editor.
15796            let snapshot = self.buffer.read(cx).read(cx);
15797            let rename_range = rename.range.to_offset(&snapshot);
15798            let cursor_in_editor = snapshot
15799                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15800                .min(rename_range.end);
15801            drop(snapshot);
15802
15803            self.change_selections(None, window, cx, |s| {
15804                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15805            });
15806        } else {
15807            self.refresh_document_highlights(cx);
15808        }
15809
15810        Some(rename)
15811    }
15812
15813    pub fn pending_rename(&self) -> Option<&RenameState> {
15814        self.pending_rename.as_ref()
15815    }
15816
15817    fn format(
15818        &mut self,
15819        _: &Format,
15820        window: &mut Window,
15821        cx: &mut Context<Self>,
15822    ) -> Option<Task<Result<()>>> {
15823        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15824
15825        let project = match &self.project {
15826            Some(project) => project.clone(),
15827            None => return None,
15828        };
15829
15830        Some(self.perform_format(
15831            project,
15832            FormatTrigger::Manual,
15833            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15834            window,
15835            cx,
15836        ))
15837    }
15838
15839    fn format_selections(
15840        &mut self,
15841        _: &FormatSelections,
15842        window: &mut Window,
15843        cx: &mut Context<Self>,
15844    ) -> Option<Task<Result<()>>> {
15845        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15846
15847        let project = match &self.project {
15848            Some(project) => project.clone(),
15849            None => return None,
15850        };
15851
15852        let ranges = self
15853            .selections
15854            .all_adjusted(cx)
15855            .into_iter()
15856            .map(|selection| selection.range())
15857            .collect_vec();
15858
15859        Some(self.perform_format(
15860            project,
15861            FormatTrigger::Manual,
15862            FormatTarget::Ranges(ranges),
15863            window,
15864            cx,
15865        ))
15866    }
15867
15868    fn perform_format(
15869        &mut self,
15870        project: Entity<Project>,
15871        trigger: FormatTrigger,
15872        target: FormatTarget,
15873        window: &mut Window,
15874        cx: &mut Context<Self>,
15875    ) -> Task<Result<()>> {
15876        let buffer = self.buffer.clone();
15877        let (buffers, target) = match target {
15878            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
15879            FormatTarget::Ranges(selection_ranges) => {
15880                let multi_buffer = buffer.read(cx);
15881                let snapshot = multi_buffer.read(cx);
15882                let mut buffers = HashSet::default();
15883                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15884                    BTreeMap::new();
15885                for selection_range in selection_ranges {
15886                    for (buffer, buffer_range, _) in
15887                        snapshot.range_to_buffer_ranges(selection_range)
15888                    {
15889                        let buffer_id = buffer.remote_id();
15890                        let start = buffer.anchor_before(buffer_range.start);
15891                        let end = buffer.anchor_after(buffer_range.end);
15892                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15893                        buffer_id_to_ranges
15894                            .entry(buffer_id)
15895                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15896                            .or_insert_with(|| vec![start..end]);
15897                    }
15898                }
15899                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15900            }
15901        };
15902
15903        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15904        let selections_prev = transaction_id_prev
15905            .and_then(|transaction_id_prev| {
15906                // default to selections as they were after the last edit, if we have them,
15907                // instead of how they are now.
15908                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15909                // will take you back to where you made the last edit, instead of staying where you scrolled
15910                self.selection_history
15911                    .transaction(transaction_id_prev)
15912                    .map(|t| t.0.clone())
15913            })
15914            .unwrap_or_else(|| {
15915                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15916                self.selections.disjoint_anchors()
15917            });
15918
15919        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15920        let format = project.update(cx, |project, cx| {
15921            project.format(buffers, target, true, trigger, cx)
15922        });
15923
15924        cx.spawn_in(window, async move |editor, cx| {
15925            let transaction = futures::select_biased! {
15926                transaction = format.log_err().fuse() => transaction,
15927                () = timeout => {
15928                    log::warn!("timed out waiting for formatting");
15929                    None
15930                }
15931            };
15932
15933            buffer
15934                .update(cx, |buffer, cx| {
15935                    if let Some(transaction) = transaction {
15936                        if !buffer.is_singleton() {
15937                            buffer.push_transaction(&transaction.0, cx);
15938                        }
15939                    }
15940                    cx.notify();
15941                })
15942                .ok();
15943
15944            if let Some(transaction_id_now) =
15945                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15946            {
15947                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15948                if has_new_transaction {
15949                    _ = editor.update(cx, |editor, _| {
15950                        editor
15951                            .selection_history
15952                            .insert_transaction(transaction_id_now, selections_prev);
15953                    });
15954                }
15955            }
15956
15957            Ok(())
15958        })
15959    }
15960
15961    fn organize_imports(
15962        &mut self,
15963        _: &OrganizeImports,
15964        window: &mut Window,
15965        cx: &mut Context<Self>,
15966    ) -> Option<Task<Result<()>>> {
15967        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15968        let project = match &self.project {
15969            Some(project) => project.clone(),
15970            None => return None,
15971        };
15972        Some(self.perform_code_action_kind(
15973            project,
15974            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15975            window,
15976            cx,
15977        ))
15978    }
15979
15980    fn perform_code_action_kind(
15981        &mut self,
15982        project: Entity<Project>,
15983        kind: CodeActionKind,
15984        window: &mut Window,
15985        cx: &mut Context<Self>,
15986    ) -> Task<Result<()>> {
15987        let buffer = self.buffer.clone();
15988        let buffers = buffer.read(cx).all_buffers();
15989        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15990        let apply_action = project.update(cx, |project, cx| {
15991            project.apply_code_action_kind(buffers, kind, true, cx)
15992        });
15993        cx.spawn_in(window, async move |_, cx| {
15994            let transaction = futures::select_biased! {
15995                () = timeout => {
15996                    log::warn!("timed out waiting for executing code action");
15997                    None
15998                }
15999                transaction = apply_action.log_err().fuse() => transaction,
16000            };
16001            buffer
16002                .update(cx, |buffer, cx| {
16003                    // check if we need this
16004                    if let Some(transaction) = transaction {
16005                        if !buffer.is_singleton() {
16006                            buffer.push_transaction(&transaction.0, cx);
16007                        }
16008                    }
16009                    cx.notify();
16010                })
16011                .ok();
16012            Ok(())
16013        })
16014    }
16015
16016    fn restart_language_server(
16017        &mut self,
16018        _: &RestartLanguageServer,
16019        _: &mut Window,
16020        cx: &mut Context<Self>,
16021    ) {
16022        if let Some(project) = self.project.clone() {
16023            self.buffer.update(cx, |multi_buffer, cx| {
16024                project.update(cx, |project, cx| {
16025                    project.restart_language_servers_for_buffers(
16026                        multi_buffer.all_buffers().into_iter().collect(),
16027                        cx,
16028                    );
16029                });
16030            })
16031        }
16032    }
16033
16034    fn stop_language_server(
16035        &mut self,
16036        _: &StopLanguageServer,
16037        _: &mut Window,
16038        cx: &mut Context<Self>,
16039    ) {
16040        if let Some(project) = self.project.clone() {
16041            self.buffer.update(cx, |multi_buffer, cx| {
16042                project.update(cx, |project, cx| {
16043                    project.stop_language_servers_for_buffers(
16044                        multi_buffer.all_buffers().into_iter().collect(),
16045                        cx,
16046                    );
16047                    cx.emit(project::Event::RefreshInlayHints);
16048                });
16049            });
16050        }
16051    }
16052
16053    fn cancel_language_server_work(
16054        workspace: &mut Workspace,
16055        _: &actions::CancelLanguageServerWork,
16056        _: &mut Window,
16057        cx: &mut Context<Workspace>,
16058    ) {
16059        let project = workspace.project();
16060        let buffers = workspace
16061            .active_item(cx)
16062            .and_then(|item| item.act_as::<Editor>(cx))
16063            .map_or(HashSet::default(), |editor| {
16064                editor.read(cx).buffer.read(cx).all_buffers()
16065            });
16066        project.update(cx, |project, cx| {
16067            project.cancel_language_server_work_for_buffers(buffers, cx);
16068        });
16069    }
16070
16071    fn show_character_palette(
16072        &mut self,
16073        _: &ShowCharacterPalette,
16074        window: &mut Window,
16075        _: &mut Context<Self>,
16076    ) {
16077        window.show_character_palette();
16078    }
16079
16080    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16081        if !self.diagnostics_enabled() {
16082            return;
16083        }
16084
16085        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16086            let buffer = self.buffer.read(cx).snapshot(cx);
16087            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16088            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16089            let is_valid = buffer
16090                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16091                .any(|entry| {
16092                    entry.diagnostic.is_primary
16093                        && !entry.range.is_empty()
16094                        && entry.range.start == primary_range_start
16095                        && entry.diagnostic.message == active_diagnostics.active_message
16096                });
16097
16098            if !is_valid {
16099                self.dismiss_diagnostics(cx);
16100            }
16101        }
16102    }
16103
16104    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16105        match &self.active_diagnostics {
16106            ActiveDiagnostic::Group(group) => Some(group),
16107            _ => None,
16108        }
16109    }
16110
16111    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16112        if !self.diagnostics_enabled() {
16113            return;
16114        }
16115        self.dismiss_diagnostics(cx);
16116        self.active_diagnostics = ActiveDiagnostic::All;
16117    }
16118
16119    fn activate_diagnostics(
16120        &mut self,
16121        buffer_id: BufferId,
16122        diagnostic: DiagnosticEntry<usize>,
16123        window: &mut Window,
16124        cx: &mut Context<Self>,
16125    ) {
16126        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16127            return;
16128        }
16129        self.dismiss_diagnostics(cx);
16130        let snapshot = self.snapshot(window, cx);
16131        let buffer = self.buffer.read(cx).snapshot(cx);
16132        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16133            return;
16134        };
16135
16136        let diagnostic_group = buffer
16137            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16138            .collect::<Vec<_>>();
16139
16140        let blocks =
16141            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16142
16143        let blocks = self.display_map.update(cx, |display_map, cx| {
16144            display_map.insert_blocks(blocks, cx).into_iter().collect()
16145        });
16146        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16147            active_range: buffer.anchor_before(diagnostic.range.start)
16148                ..buffer.anchor_after(diagnostic.range.end),
16149            active_message: diagnostic.diagnostic.message.clone(),
16150            group_id: diagnostic.diagnostic.group_id,
16151            blocks,
16152        });
16153        cx.notify();
16154    }
16155
16156    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16157        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16158            return;
16159        };
16160
16161        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16162        if let ActiveDiagnostic::Group(group) = prev {
16163            self.display_map.update(cx, |display_map, cx| {
16164                display_map.remove_blocks(group.blocks, cx);
16165            });
16166            cx.notify();
16167        }
16168    }
16169
16170    /// Disable inline diagnostics rendering for this editor.
16171    pub fn disable_inline_diagnostics(&mut self) {
16172        self.inline_diagnostics_enabled = false;
16173        self.inline_diagnostics_update = Task::ready(());
16174        self.inline_diagnostics.clear();
16175    }
16176
16177    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16178        self.diagnostics_enabled = false;
16179        self.dismiss_diagnostics(cx);
16180        self.inline_diagnostics_update = Task::ready(());
16181        self.inline_diagnostics.clear();
16182    }
16183
16184    pub fn diagnostics_enabled(&self) -> bool {
16185        self.diagnostics_enabled && self.mode.is_full()
16186    }
16187
16188    pub fn inline_diagnostics_enabled(&self) -> bool {
16189        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16190    }
16191
16192    pub fn show_inline_diagnostics(&self) -> bool {
16193        self.show_inline_diagnostics
16194    }
16195
16196    pub fn toggle_inline_diagnostics(
16197        &mut self,
16198        _: &ToggleInlineDiagnostics,
16199        window: &mut Window,
16200        cx: &mut Context<Editor>,
16201    ) {
16202        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16203        self.refresh_inline_diagnostics(false, window, cx);
16204    }
16205
16206    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16207        self.diagnostics_max_severity = severity;
16208        self.display_map.update(cx, |display_map, _| {
16209            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16210        });
16211    }
16212
16213    pub fn toggle_diagnostics(
16214        &mut self,
16215        _: &ToggleDiagnostics,
16216        window: &mut Window,
16217        cx: &mut Context<Editor>,
16218    ) {
16219        if !self.diagnostics_enabled() {
16220            return;
16221        }
16222
16223        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16224            EditorSettings::get_global(cx)
16225                .diagnostics_max_severity
16226                .filter(|severity| severity != &DiagnosticSeverity::Off)
16227                .unwrap_or(DiagnosticSeverity::Hint)
16228        } else {
16229            DiagnosticSeverity::Off
16230        };
16231        self.set_max_diagnostics_severity(new_severity, cx);
16232        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16233            self.active_diagnostics = ActiveDiagnostic::None;
16234            self.inline_diagnostics_update = Task::ready(());
16235            self.inline_diagnostics.clear();
16236        } else {
16237            self.refresh_inline_diagnostics(false, window, cx);
16238        }
16239
16240        cx.notify();
16241    }
16242
16243    pub fn toggle_minimap(
16244        &mut self,
16245        _: &ToggleMinimap,
16246        window: &mut Window,
16247        cx: &mut Context<Editor>,
16248    ) {
16249        if self.supports_minimap(cx) {
16250            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16251        }
16252    }
16253
16254    fn refresh_inline_diagnostics(
16255        &mut self,
16256        debounce: bool,
16257        window: &mut Window,
16258        cx: &mut Context<Self>,
16259    ) {
16260        let max_severity = ProjectSettings::get_global(cx)
16261            .diagnostics
16262            .inline
16263            .max_severity
16264            .unwrap_or(self.diagnostics_max_severity);
16265
16266        if !self.inline_diagnostics_enabled()
16267            || !self.show_inline_diagnostics
16268            || max_severity == DiagnosticSeverity::Off
16269        {
16270            self.inline_diagnostics_update = Task::ready(());
16271            self.inline_diagnostics.clear();
16272            return;
16273        }
16274
16275        let debounce_ms = ProjectSettings::get_global(cx)
16276            .diagnostics
16277            .inline
16278            .update_debounce_ms;
16279        let debounce = if debounce && debounce_ms > 0 {
16280            Some(Duration::from_millis(debounce_ms))
16281        } else {
16282            None
16283        };
16284        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16285            if let Some(debounce) = debounce {
16286                cx.background_executor().timer(debounce).await;
16287            }
16288            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16289                editor
16290                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16291                    .ok()
16292            }) else {
16293                return;
16294            };
16295
16296            let new_inline_diagnostics = cx
16297                .background_spawn(async move {
16298                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16299                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16300                        let message = diagnostic_entry
16301                            .diagnostic
16302                            .message
16303                            .split_once('\n')
16304                            .map(|(line, _)| line)
16305                            .map(SharedString::new)
16306                            .unwrap_or_else(|| {
16307                                SharedString::from(diagnostic_entry.diagnostic.message)
16308                            });
16309                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16310                        let (Ok(i) | Err(i)) = inline_diagnostics
16311                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16312                        inline_diagnostics.insert(
16313                            i,
16314                            (
16315                                start_anchor,
16316                                InlineDiagnostic {
16317                                    message,
16318                                    group_id: diagnostic_entry.diagnostic.group_id,
16319                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16320                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16321                                    severity: diagnostic_entry.diagnostic.severity,
16322                                },
16323                            ),
16324                        );
16325                    }
16326                    inline_diagnostics
16327                })
16328                .await;
16329
16330            editor
16331                .update(cx, |editor, cx| {
16332                    editor.inline_diagnostics = new_inline_diagnostics;
16333                    cx.notify();
16334                })
16335                .ok();
16336        });
16337    }
16338
16339    fn pull_diagnostics(
16340        &mut self,
16341        buffer_id: Option<BufferId>,
16342        window: &Window,
16343        cx: &mut Context<Self>,
16344    ) -> Option<()> {
16345        if !self.mode().is_full() {
16346            return None;
16347        }
16348        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16349            .diagnostics
16350            .lsp_pull_diagnostics;
16351        if !pull_diagnostics_settings.enabled {
16352            return None;
16353        }
16354        let project = self.project.as_ref()?.downgrade();
16355        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16356        let mut buffers = self.buffer.read(cx).all_buffers();
16357        if let Some(buffer_id) = buffer_id {
16358            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16359        }
16360
16361        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16362            cx.background_executor().timer(debounce).await;
16363
16364            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16365                buffers
16366                    .into_iter()
16367                    .filter_map(|buffer| {
16368                        project
16369                            .update(cx, |project, cx| {
16370                                project.lsp_store().update(cx, |lsp_store, cx| {
16371                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16372                                })
16373                            })
16374                            .ok()
16375                    })
16376                    .collect::<FuturesUnordered<_>>()
16377            }) else {
16378                return;
16379            };
16380
16381            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16382                match pull_task {
16383                    Ok(()) => {
16384                        if editor
16385                            .update_in(cx, |editor, window, cx| {
16386                                editor.update_diagnostics_state(window, cx);
16387                            })
16388                            .is_err()
16389                        {
16390                            return;
16391                        }
16392                    }
16393                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16394                }
16395            }
16396        });
16397
16398        Some(())
16399    }
16400
16401    pub fn set_selections_from_remote(
16402        &mut self,
16403        selections: Vec<Selection<Anchor>>,
16404        pending_selection: Option<Selection<Anchor>>,
16405        window: &mut Window,
16406        cx: &mut Context<Self>,
16407    ) {
16408        let old_cursor_position = self.selections.newest_anchor().head();
16409        self.selections.change_with(cx, |s| {
16410            s.select_anchors(selections);
16411            if let Some(pending_selection) = pending_selection {
16412                s.set_pending(pending_selection, SelectMode::Character);
16413            } else {
16414                s.clear_pending();
16415            }
16416        });
16417        self.selections_did_change(
16418            false,
16419            &old_cursor_position,
16420            SelectionEffects::default(),
16421            window,
16422            cx,
16423        );
16424    }
16425
16426    pub fn transact(
16427        &mut self,
16428        window: &mut Window,
16429        cx: &mut Context<Self>,
16430        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16431    ) -> Option<TransactionId> {
16432        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16433            this.start_transaction_at(Instant::now(), window, cx);
16434            update(this, window, cx);
16435            this.end_transaction_at(Instant::now(), cx)
16436        })
16437    }
16438
16439    pub fn start_transaction_at(
16440        &mut self,
16441        now: Instant,
16442        window: &mut Window,
16443        cx: &mut Context<Self>,
16444    ) {
16445        self.end_selection(window, cx);
16446        if let Some(tx_id) = self
16447            .buffer
16448            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16449        {
16450            self.selection_history
16451                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16452            cx.emit(EditorEvent::TransactionBegun {
16453                transaction_id: tx_id,
16454            })
16455        }
16456    }
16457
16458    pub fn end_transaction_at(
16459        &mut self,
16460        now: Instant,
16461        cx: &mut Context<Self>,
16462    ) -> Option<TransactionId> {
16463        if let Some(transaction_id) = self
16464            .buffer
16465            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16466        {
16467            if let Some((_, end_selections)) =
16468                self.selection_history.transaction_mut(transaction_id)
16469            {
16470                *end_selections = Some(self.selections.disjoint_anchors());
16471            } else {
16472                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16473            }
16474
16475            cx.emit(EditorEvent::Edited { transaction_id });
16476            Some(transaction_id)
16477        } else {
16478            None
16479        }
16480    }
16481
16482    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16483        if self.selection_mark_mode {
16484            self.change_selections(None, window, cx, |s| {
16485                s.move_with(|_, sel| {
16486                    sel.collapse_to(sel.head(), SelectionGoal::None);
16487                });
16488            })
16489        }
16490        self.selection_mark_mode = true;
16491        cx.notify();
16492    }
16493
16494    pub fn swap_selection_ends(
16495        &mut self,
16496        _: &actions::SwapSelectionEnds,
16497        window: &mut Window,
16498        cx: &mut Context<Self>,
16499    ) {
16500        self.change_selections(None, window, cx, |s| {
16501            s.move_with(|_, sel| {
16502                if sel.start != sel.end {
16503                    sel.reversed = !sel.reversed
16504                }
16505            });
16506        });
16507        self.request_autoscroll(Autoscroll::newest(), cx);
16508        cx.notify();
16509    }
16510
16511    pub fn toggle_fold(
16512        &mut self,
16513        _: &actions::ToggleFold,
16514        window: &mut Window,
16515        cx: &mut Context<Self>,
16516    ) {
16517        if self.is_singleton(cx) {
16518            let selection = self.selections.newest::<Point>(cx);
16519
16520            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16521            let range = if selection.is_empty() {
16522                let point = selection.head().to_display_point(&display_map);
16523                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16524                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16525                    .to_point(&display_map);
16526                start..end
16527            } else {
16528                selection.range()
16529            };
16530            if display_map.folds_in_range(range).next().is_some() {
16531                self.unfold_lines(&Default::default(), window, cx)
16532            } else {
16533                self.fold(&Default::default(), window, cx)
16534            }
16535        } else {
16536            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16537            let buffer_ids: HashSet<_> = self
16538                .selections
16539                .disjoint_anchor_ranges()
16540                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16541                .collect();
16542
16543            let should_unfold = buffer_ids
16544                .iter()
16545                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16546
16547            for buffer_id in buffer_ids {
16548                if should_unfold {
16549                    self.unfold_buffer(buffer_id, cx);
16550                } else {
16551                    self.fold_buffer(buffer_id, cx);
16552                }
16553            }
16554        }
16555    }
16556
16557    pub fn toggle_fold_recursive(
16558        &mut self,
16559        _: &actions::ToggleFoldRecursive,
16560        window: &mut Window,
16561        cx: &mut Context<Self>,
16562    ) {
16563        let selection = self.selections.newest::<Point>(cx);
16564
16565        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16566        let range = if selection.is_empty() {
16567            let point = selection.head().to_display_point(&display_map);
16568            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16569            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16570                .to_point(&display_map);
16571            start..end
16572        } else {
16573            selection.range()
16574        };
16575        if display_map.folds_in_range(range).next().is_some() {
16576            self.unfold_recursive(&Default::default(), window, cx)
16577        } else {
16578            self.fold_recursive(&Default::default(), window, cx)
16579        }
16580    }
16581
16582    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16583        if self.is_singleton(cx) {
16584            let mut to_fold = Vec::new();
16585            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16586            let selections = self.selections.all_adjusted(cx);
16587
16588            for selection in selections {
16589                let range = selection.range().sorted();
16590                let buffer_start_row = range.start.row;
16591
16592                if range.start.row != range.end.row {
16593                    let mut found = false;
16594                    let mut row = range.start.row;
16595                    while row <= range.end.row {
16596                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16597                        {
16598                            found = true;
16599                            row = crease.range().end.row + 1;
16600                            to_fold.push(crease);
16601                        } else {
16602                            row += 1
16603                        }
16604                    }
16605                    if found {
16606                        continue;
16607                    }
16608                }
16609
16610                for row in (0..=range.start.row).rev() {
16611                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16612                        if crease.range().end.row >= buffer_start_row {
16613                            to_fold.push(crease);
16614                            if row <= range.start.row {
16615                                break;
16616                            }
16617                        }
16618                    }
16619                }
16620            }
16621
16622            self.fold_creases(to_fold, true, window, cx);
16623        } else {
16624            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16625            let buffer_ids = self
16626                .selections
16627                .disjoint_anchor_ranges()
16628                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16629                .collect::<HashSet<_>>();
16630            for buffer_id in buffer_ids {
16631                self.fold_buffer(buffer_id, cx);
16632            }
16633        }
16634    }
16635
16636    fn fold_at_level(
16637        &mut self,
16638        fold_at: &FoldAtLevel,
16639        window: &mut Window,
16640        cx: &mut Context<Self>,
16641    ) {
16642        if !self.buffer.read(cx).is_singleton() {
16643            return;
16644        }
16645
16646        let fold_at_level = fold_at.0;
16647        let snapshot = self.buffer.read(cx).snapshot(cx);
16648        let mut to_fold = Vec::new();
16649        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16650
16651        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16652            while start_row < end_row {
16653                match self
16654                    .snapshot(window, cx)
16655                    .crease_for_buffer_row(MultiBufferRow(start_row))
16656                {
16657                    Some(crease) => {
16658                        let nested_start_row = crease.range().start.row + 1;
16659                        let nested_end_row = crease.range().end.row;
16660
16661                        if current_level < fold_at_level {
16662                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16663                        } else if current_level == fold_at_level {
16664                            to_fold.push(crease);
16665                        }
16666
16667                        start_row = nested_end_row + 1;
16668                    }
16669                    None => start_row += 1,
16670                }
16671            }
16672        }
16673
16674        self.fold_creases(to_fold, true, window, cx);
16675    }
16676
16677    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16678        if self.buffer.read(cx).is_singleton() {
16679            let mut fold_ranges = Vec::new();
16680            let snapshot = self.buffer.read(cx).snapshot(cx);
16681
16682            for row in 0..snapshot.max_row().0 {
16683                if let Some(foldable_range) = self
16684                    .snapshot(window, cx)
16685                    .crease_for_buffer_row(MultiBufferRow(row))
16686                {
16687                    fold_ranges.push(foldable_range);
16688                }
16689            }
16690
16691            self.fold_creases(fold_ranges, true, window, cx);
16692        } else {
16693            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16694                editor
16695                    .update_in(cx, |editor, _, cx| {
16696                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16697                            editor.fold_buffer(buffer_id, cx);
16698                        }
16699                    })
16700                    .ok();
16701            });
16702        }
16703    }
16704
16705    pub fn fold_function_bodies(
16706        &mut self,
16707        _: &actions::FoldFunctionBodies,
16708        window: &mut Window,
16709        cx: &mut Context<Self>,
16710    ) {
16711        let snapshot = self.buffer.read(cx).snapshot(cx);
16712
16713        let ranges = snapshot
16714            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16715            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16716            .collect::<Vec<_>>();
16717
16718        let creases = ranges
16719            .into_iter()
16720            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16721            .collect();
16722
16723        self.fold_creases(creases, true, window, cx);
16724    }
16725
16726    pub fn fold_recursive(
16727        &mut self,
16728        _: &actions::FoldRecursive,
16729        window: &mut Window,
16730        cx: &mut Context<Self>,
16731    ) {
16732        let mut to_fold = Vec::new();
16733        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16734        let selections = self.selections.all_adjusted(cx);
16735
16736        for selection in selections {
16737            let range = selection.range().sorted();
16738            let buffer_start_row = range.start.row;
16739
16740            if range.start.row != range.end.row {
16741                let mut found = false;
16742                for row in range.start.row..=range.end.row {
16743                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16744                        found = true;
16745                        to_fold.push(crease);
16746                    }
16747                }
16748                if found {
16749                    continue;
16750                }
16751            }
16752
16753            for row in (0..=range.start.row).rev() {
16754                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16755                    if crease.range().end.row >= buffer_start_row {
16756                        to_fold.push(crease);
16757                    } else {
16758                        break;
16759                    }
16760                }
16761            }
16762        }
16763
16764        self.fold_creases(to_fold, true, window, cx);
16765    }
16766
16767    pub fn fold_at(
16768        &mut self,
16769        buffer_row: MultiBufferRow,
16770        window: &mut Window,
16771        cx: &mut Context<Self>,
16772    ) {
16773        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16774
16775        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16776            let autoscroll = self
16777                .selections
16778                .all::<Point>(cx)
16779                .iter()
16780                .any(|selection| crease.range().overlaps(&selection.range()));
16781
16782            self.fold_creases(vec![crease], autoscroll, window, cx);
16783        }
16784    }
16785
16786    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16787        if self.is_singleton(cx) {
16788            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16789            let buffer = &display_map.buffer_snapshot;
16790            let selections = self.selections.all::<Point>(cx);
16791            let ranges = selections
16792                .iter()
16793                .map(|s| {
16794                    let range = s.display_range(&display_map).sorted();
16795                    let mut start = range.start.to_point(&display_map);
16796                    let mut end = range.end.to_point(&display_map);
16797                    start.column = 0;
16798                    end.column = buffer.line_len(MultiBufferRow(end.row));
16799                    start..end
16800                })
16801                .collect::<Vec<_>>();
16802
16803            self.unfold_ranges(&ranges, true, true, cx);
16804        } else {
16805            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16806            let buffer_ids = self
16807                .selections
16808                .disjoint_anchor_ranges()
16809                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16810                .collect::<HashSet<_>>();
16811            for buffer_id in buffer_ids {
16812                self.unfold_buffer(buffer_id, cx);
16813            }
16814        }
16815    }
16816
16817    pub fn unfold_recursive(
16818        &mut self,
16819        _: &UnfoldRecursive,
16820        _window: &mut Window,
16821        cx: &mut Context<Self>,
16822    ) {
16823        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16824        let selections = self.selections.all::<Point>(cx);
16825        let ranges = selections
16826            .iter()
16827            .map(|s| {
16828                let mut range = s.display_range(&display_map).sorted();
16829                *range.start.column_mut() = 0;
16830                *range.end.column_mut() = display_map.line_len(range.end.row());
16831                let start = range.start.to_point(&display_map);
16832                let end = range.end.to_point(&display_map);
16833                start..end
16834            })
16835            .collect::<Vec<_>>();
16836
16837        self.unfold_ranges(&ranges, true, true, cx);
16838    }
16839
16840    pub fn unfold_at(
16841        &mut self,
16842        buffer_row: MultiBufferRow,
16843        _window: &mut Window,
16844        cx: &mut Context<Self>,
16845    ) {
16846        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16847
16848        let intersection_range = Point::new(buffer_row.0, 0)
16849            ..Point::new(
16850                buffer_row.0,
16851                display_map.buffer_snapshot.line_len(buffer_row),
16852            );
16853
16854        let autoscroll = self
16855            .selections
16856            .all::<Point>(cx)
16857            .iter()
16858            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16859
16860        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16861    }
16862
16863    pub fn unfold_all(
16864        &mut self,
16865        _: &actions::UnfoldAll,
16866        _window: &mut Window,
16867        cx: &mut Context<Self>,
16868    ) {
16869        if self.buffer.read(cx).is_singleton() {
16870            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16871            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16872        } else {
16873            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16874                editor
16875                    .update(cx, |editor, cx| {
16876                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16877                            editor.unfold_buffer(buffer_id, cx);
16878                        }
16879                    })
16880                    .ok();
16881            });
16882        }
16883    }
16884
16885    pub fn fold_selected_ranges(
16886        &mut self,
16887        _: &FoldSelectedRanges,
16888        window: &mut Window,
16889        cx: &mut Context<Self>,
16890    ) {
16891        let selections = self.selections.all_adjusted(cx);
16892        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16893        let ranges = selections
16894            .into_iter()
16895            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16896            .collect::<Vec<_>>();
16897        self.fold_creases(ranges, true, window, cx);
16898    }
16899
16900    pub fn fold_ranges<T: ToOffset + Clone>(
16901        &mut self,
16902        ranges: Vec<Range<T>>,
16903        auto_scroll: bool,
16904        window: &mut Window,
16905        cx: &mut Context<Self>,
16906    ) {
16907        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16908        let ranges = ranges
16909            .into_iter()
16910            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16911            .collect::<Vec<_>>();
16912        self.fold_creases(ranges, auto_scroll, window, cx);
16913    }
16914
16915    pub fn fold_creases<T: ToOffset + Clone>(
16916        &mut self,
16917        creases: Vec<Crease<T>>,
16918        auto_scroll: bool,
16919        _window: &mut Window,
16920        cx: &mut Context<Self>,
16921    ) {
16922        if creases.is_empty() {
16923            return;
16924        }
16925
16926        let mut buffers_affected = HashSet::default();
16927        let multi_buffer = self.buffer().read(cx);
16928        for crease in &creases {
16929            if let Some((_, buffer, _)) =
16930                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16931            {
16932                buffers_affected.insert(buffer.read(cx).remote_id());
16933            };
16934        }
16935
16936        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16937
16938        if auto_scroll {
16939            self.request_autoscroll(Autoscroll::fit(), cx);
16940        }
16941
16942        cx.notify();
16943
16944        self.scrollbar_marker_state.dirty = true;
16945        self.folds_did_change(cx);
16946    }
16947
16948    /// Removes any folds whose ranges intersect any of the given ranges.
16949    pub fn unfold_ranges<T: ToOffset + Clone>(
16950        &mut self,
16951        ranges: &[Range<T>],
16952        inclusive: bool,
16953        auto_scroll: bool,
16954        cx: &mut Context<Self>,
16955    ) {
16956        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16957            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16958        });
16959        self.folds_did_change(cx);
16960    }
16961
16962    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16963        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16964            return;
16965        }
16966        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16967        self.display_map.update(cx, |display_map, cx| {
16968            display_map.fold_buffers([buffer_id], cx)
16969        });
16970        cx.emit(EditorEvent::BufferFoldToggled {
16971            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16972            folded: true,
16973        });
16974        cx.notify();
16975    }
16976
16977    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16978        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16979            return;
16980        }
16981        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16982        self.display_map.update(cx, |display_map, cx| {
16983            display_map.unfold_buffers([buffer_id], cx);
16984        });
16985        cx.emit(EditorEvent::BufferFoldToggled {
16986            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16987            folded: false,
16988        });
16989        cx.notify();
16990    }
16991
16992    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16993        self.display_map.read(cx).is_buffer_folded(buffer)
16994    }
16995
16996    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16997        self.display_map.read(cx).folded_buffers()
16998    }
16999
17000    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17001        self.display_map.update(cx, |display_map, cx| {
17002            display_map.disable_header_for_buffer(buffer_id, cx);
17003        });
17004        cx.notify();
17005    }
17006
17007    /// Removes any folds with the given ranges.
17008    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17009        &mut self,
17010        ranges: &[Range<T>],
17011        type_id: TypeId,
17012        auto_scroll: bool,
17013        cx: &mut Context<Self>,
17014    ) {
17015        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17016            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17017        });
17018        self.folds_did_change(cx);
17019    }
17020
17021    fn remove_folds_with<T: ToOffset + Clone>(
17022        &mut self,
17023        ranges: &[Range<T>],
17024        auto_scroll: bool,
17025        cx: &mut Context<Self>,
17026        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17027    ) {
17028        if ranges.is_empty() {
17029            return;
17030        }
17031
17032        let mut buffers_affected = HashSet::default();
17033        let multi_buffer = self.buffer().read(cx);
17034        for range in ranges {
17035            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17036                buffers_affected.insert(buffer.read(cx).remote_id());
17037            };
17038        }
17039
17040        self.display_map.update(cx, update);
17041
17042        if auto_scroll {
17043            self.request_autoscroll(Autoscroll::fit(), cx);
17044        }
17045
17046        cx.notify();
17047        self.scrollbar_marker_state.dirty = true;
17048        self.active_indent_guides_state.dirty = true;
17049    }
17050
17051    pub fn update_fold_widths(
17052        &mut self,
17053        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
17054        cx: &mut Context<Self>,
17055    ) -> bool {
17056        self.display_map
17057            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17058    }
17059
17060    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17061        self.display_map.read(cx).fold_placeholder.clone()
17062    }
17063
17064    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17065        self.buffer.update(cx, |buffer, cx| {
17066            buffer.set_all_diff_hunks_expanded(cx);
17067        });
17068    }
17069
17070    pub fn expand_all_diff_hunks(
17071        &mut self,
17072        _: &ExpandAllDiffHunks,
17073        _window: &mut Window,
17074        cx: &mut Context<Self>,
17075    ) {
17076        self.buffer.update(cx, |buffer, cx| {
17077            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17078        });
17079    }
17080
17081    pub fn toggle_selected_diff_hunks(
17082        &mut self,
17083        _: &ToggleSelectedDiffHunks,
17084        _window: &mut Window,
17085        cx: &mut Context<Self>,
17086    ) {
17087        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17088        self.toggle_diff_hunks_in_ranges(ranges, cx);
17089    }
17090
17091    pub fn diff_hunks_in_ranges<'a>(
17092        &'a self,
17093        ranges: &'a [Range<Anchor>],
17094        buffer: &'a MultiBufferSnapshot,
17095    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17096        ranges.iter().flat_map(move |range| {
17097            let end_excerpt_id = range.end.excerpt_id;
17098            let range = range.to_point(buffer);
17099            let mut peek_end = range.end;
17100            if range.end.row < buffer.max_row().0 {
17101                peek_end = Point::new(range.end.row + 1, 0);
17102            }
17103            buffer
17104                .diff_hunks_in_range(range.start..peek_end)
17105                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17106        })
17107    }
17108
17109    pub fn has_stageable_diff_hunks_in_ranges(
17110        &self,
17111        ranges: &[Range<Anchor>],
17112        snapshot: &MultiBufferSnapshot,
17113    ) -> bool {
17114        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17115        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17116    }
17117
17118    pub fn toggle_staged_selected_diff_hunks(
17119        &mut self,
17120        _: &::git::ToggleStaged,
17121        _: &mut Window,
17122        cx: &mut Context<Self>,
17123    ) {
17124        let snapshot = self.buffer.read(cx).snapshot(cx);
17125        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17126        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17127        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17128    }
17129
17130    pub fn set_render_diff_hunk_controls(
17131        &mut self,
17132        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17133        cx: &mut Context<Self>,
17134    ) {
17135        self.render_diff_hunk_controls = render_diff_hunk_controls;
17136        cx.notify();
17137    }
17138
17139    pub fn stage_and_next(
17140        &mut self,
17141        _: &::git::StageAndNext,
17142        window: &mut Window,
17143        cx: &mut Context<Self>,
17144    ) {
17145        self.do_stage_or_unstage_and_next(true, window, cx);
17146    }
17147
17148    pub fn unstage_and_next(
17149        &mut self,
17150        _: &::git::UnstageAndNext,
17151        window: &mut Window,
17152        cx: &mut Context<Self>,
17153    ) {
17154        self.do_stage_or_unstage_and_next(false, window, cx);
17155    }
17156
17157    pub fn stage_or_unstage_diff_hunks(
17158        &mut self,
17159        stage: bool,
17160        ranges: Vec<Range<Anchor>>,
17161        cx: &mut Context<Self>,
17162    ) {
17163        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17164        cx.spawn(async move |this, cx| {
17165            task.await?;
17166            this.update(cx, |this, cx| {
17167                let snapshot = this.buffer.read(cx).snapshot(cx);
17168                let chunk_by = this
17169                    .diff_hunks_in_ranges(&ranges, &snapshot)
17170                    .chunk_by(|hunk| hunk.buffer_id);
17171                for (buffer_id, hunks) in &chunk_by {
17172                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17173                }
17174            })
17175        })
17176        .detach_and_log_err(cx);
17177    }
17178
17179    fn save_buffers_for_ranges_if_needed(
17180        &mut self,
17181        ranges: &[Range<Anchor>],
17182        cx: &mut Context<Editor>,
17183    ) -> Task<Result<()>> {
17184        let multibuffer = self.buffer.read(cx);
17185        let snapshot = multibuffer.read(cx);
17186        let buffer_ids: HashSet<_> = ranges
17187            .iter()
17188            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17189            .collect();
17190        drop(snapshot);
17191
17192        let mut buffers = HashSet::default();
17193        for buffer_id in buffer_ids {
17194            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17195                let buffer = buffer_entity.read(cx);
17196                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17197                {
17198                    buffers.insert(buffer_entity);
17199                }
17200            }
17201        }
17202
17203        if let Some(project) = &self.project {
17204            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17205        } else {
17206            Task::ready(Ok(()))
17207        }
17208    }
17209
17210    fn do_stage_or_unstage_and_next(
17211        &mut self,
17212        stage: bool,
17213        window: &mut Window,
17214        cx: &mut Context<Self>,
17215    ) {
17216        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17217
17218        if ranges.iter().any(|range| range.start != range.end) {
17219            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17220            return;
17221        }
17222
17223        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17224        let snapshot = self.snapshot(window, cx);
17225        let position = self.selections.newest::<Point>(cx).head();
17226        let mut row = snapshot
17227            .buffer_snapshot
17228            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17229            .find(|hunk| hunk.row_range.start.0 > position.row)
17230            .map(|hunk| hunk.row_range.start);
17231
17232        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17233        // Outside of the project diff editor, wrap around to the beginning.
17234        if !all_diff_hunks_expanded {
17235            row = row.or_else(|| {
17236                snapshot
17237                    .buffer_snapshot
17238                    .diff_hunks_in_range(Point::zero()..position)
17239                    .find(|hunk| hunk.row_range.end.0 < position.row)
17240                    .map(|hunk| hunk.row_range.start)
17241            });
17242        }
17243
17244        if let Some(row) = row {
17245            let destination = Point::new(row.0, 0);
17246            let autoscroll = Autoscroll::center();
17247
17248            self.unfold_ranges(&[destination..destination], false, false, cx);
17249            self.change_selections(Some(autoscroll), window, cx, |s| {
17250                s.select_ranges([destination..destination]);
17251            });
17252        }
17253    }
17254
17255    fn do_stage_or_unstage(
17256        &self,
17257        stage: bool,
17258        buffer_id: BufferId,
17259        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17260        cx: &mut App,
17261    ) -> Option<()> {
17262        let project = self.project.as_ref()?;
17263        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17264        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17265        let buffer_snapshot = buffer.read(cx).snapshot();
17266        let file_exists = buffer_snapshot
17267            .file()
17268            .is_some_and(|file| file.disk_state().exists());
17269        diff.update(cx, |diff, cx| {
17270            diff.stage_or_unstage_hunks(
17271                stage,
17272                &hunks
17273                    .map(|hunk| buffer_diff::DiffHunk {
17274                        buffer_range: hunk.buffer_range,
17275                        diff_base_byte_range: hunk.diff_base_byte_range,
17276                        secondary_status: hunk.secondary_status,
17277                        range: Point::zero()..Point::zero(), // unused
17278                    })
17279                    .collect::<Vec<_>>(),
17280                &buffer_snapshot,
17281                file_exists,
17282                cx,
17283            )
17284        });
17285        None
17286    }
17287
17288    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17289        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17290        self.buffer
17291            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17292    }
17293
17294    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17295        self.buffer.update(cx, |buffer, cx| {
17296            let ranges = vec![Anchor::min()..Anchor::max()];
17297            if !buffer.all_diff_hunks_expanded()
17298                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17299            {
17300                buffer.collapse_diff_hunks(ranges, cx);
17301                true
17302            } else {
17303                false
17304            }
17305        })
17306    }
17307
17308    fn toggle_diff_hunks_in_ranges(
17309        &mut self,
17310        ranges: Vec<Range<Anchor>>,
17311        cx: &mut Context<Editor>,
17312    ) {
17313        self.buffer.update(cx, |buffer, cx| {
17314            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17315            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17316        })
17317    }
17318
17319    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17320        self.buffer.update(cx, |buffer, cx| {
17321            let snapshot = buffer.snapshot(cx);
17322            let excerpt_id = range.end.excerpt_id;
17323            let point_range = range.to_point(&snapshot);
17324            let expand = !buffer.single_hunk_is_expanded(range, cx);
17325            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17326        })
17327    }
17328
17329    pub(crate) fn apply_all_diff_hunks(
17330        &mut self,
17331        _: &ApplyAllDiffHunks,
17332        window: &mut Window,
17333        cx: &mut Context<Self>,
17334    ) {
17335        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17336
17337        let buffers = self.buffer.read(cx).all_buffers();
17338        for branch_buffer in buffers {
17339            branch_buffer.update(cx, |branch_buffer, cx| {
17340                branch_buffer.merge_into_base(Vec::new(), cx);
17341            });
17342        }
17343
17344        if let Some(project) = self.project.clone() {
17345            self.save(
17346                SaveOptions {
17347                    format: true,
17348                    autosave: false,
17349                },
17350                project,
17351                window,
17352                cx,
17353            )
17354            .detach_and_log_err(cx);
17355        }
17356    }
17357
17358    pub(crate) fn apply_selected_diff_hunks(
17359        &mut self,
17360        _: &ApplyDiffHunk,
17361        window: &mut Window,
17362        cx: &mut Context<Self>,
17363    ) {
17364        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17365        let snapshot = self.snapshot(window, cx);
17366        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17367        let mut ranges_by_buffer = HashMap::default();
17368        self.transact(window, cx, |editor, _window, cx| {
17369            for hunk in hunks {
17370                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17371                    ranges_by_buffer
17372                        .entry(buffer.clone())
17373                        .or_insert_with(Vec::new)
17374                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17375                }
17376            }
17377
17378            for (buffer, ranges) in ranges_by_buffer {
17379                buffer.update(cx, |buffer, cx| {
17380                    buffer.merge_into_base(ranges, cx);
17381                });
17382            }
17383        });
17384
17385        if let Some(project) = self.project.clone() {
17386            self.save(
17387                SaveOptions {
17388                    format: true,
17389                    autosave: false,
17390                },
17391                project,
17392                window,
17393                cx,
17394            )
17395            .detach_and_log_err(cx);
17396        }
17397    }
17398
17399    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17400        if hovered != self.gutter_hovered {
17401            self.gutter_hovered = hovered;
17402            cx.notify();
17403        }
17404    }
17405
17406    pub fn insert_blocks(
17407        &mut self,
17408        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17409        autoscroll: Option<Autoscroll>,
17410        cx: &mut Context<Self>,
17411    ) -> Vec<CustomBlockId> {
17412        let blocks = self
17413            .display_map
17414            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17415        if let Some(autoscroll) = autoscroll {
17416            self.request_autoscroll(autoscroll, cx);
17417        }
17418        cx.notify();
17419        blocks
17420    }
17421
17422    pub fn resize_blocks(
17423        &mut self,
17424        heights: HashMap<CustomBlockId, u32>,
17425        autoscroll: Option<Autoscroll>,
17426        cx: &mut Context<Self>,
17427    ) {
17428        self.display_map
17429            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17430        if let Some(autoscroll) = autoscroll {
17431            self.request_autoscroll(autoscroll, cx);
17432        }
17433        cx.notify();
17434    }
17435
17436    pub fn replace_blocks(
17437        &mut self,
17438        renderers: HashMap<CustomBlockId, RenderBlock>,
17439        autoscroll: Option<Autoscroll>,
17440        cx: &mut Context<Self>,
17441    ) {
17442        self.display_map
17443            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17444        if let Some(autoscroll) = autoscroll {
17445            self.request_autoscroll(autoscroll, cx);
17446        }
17447        cx.notify();
17448    }
17449
17450    pub fn remove_blocks(
17451        &mut self,
17452        block_ids: HashSet<CustomBlockId>,
17453        autoscroll: Option<Autoscroll>,
17454        cx: &mut Context<Self>,
17455    ) {
17456        self.display_map.update(cx, |display_map, cx| {
17457            display_map.remove_blocks(block_ids, cx)
17458        });
17459        if let Some(autoscroll) = autoscroll {
17460            self.request_autoscroll(autoscroll, cx);
17461        }
17462        cx.notify();
17463    }
17464
17465    pub fn row_for_block(
17466        &self,
17467        block_id: CustomBlockId,
17468        cx: &mut Context<Self>,
17469    ) -> Option<DisplayRow> {
17470        self.display_map
17471            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17472    }
17473
17474    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17475        self.focused_block = Some(focused_block);
17476    }
17477
17478    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17479        self.focused_block.take()
17480    }
17481
17482    pub fn insert_creases(
17483        &mut self,
17484        creases: impl IntoIterator<Item = Crease<Anchor>>,
17485        cx: &mut Context<Self>,
17486    ) -> Vec<CreaseId> {
17487        self.display_map
17488            .update(cx, |map, cx| map.insert_creases(creases, cx))
17489    }
17490
17491    pub fn remove_creases(
17492        &mut self,
17493        ids: impl IntoIterator<Item = CreaseId>,
17494        cx: &mut Context<Self>,
17495    ) -> Vec<(CreaseId, Range<Anchor>)> {
17496        self.display_map
17497            .update(cx, |map, cx| map.remove_creases(ids, cx))
17498    }
17499
17500    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17501        self.display_map
17502            .update(cx, |map, cx| map.snapshot(cx))
17503            .longest_row()
17504    }
17505
17506    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17507        self.display_map
17508            .update(cx, |map, cx| map.snapshot(cx))
17509            .max_point()
17510    }
17511
17512    pub fn text(&self, cx: &App) -> String {
17513        self.buffer.read(cx).read(cx).text()
17514    }
17515
17516    pub fn is_empty(&self, cx: &App) -> bool {
17517        self.buffer.read(cx).read(cx).is_empty()
17518    }
17519
17520    pub fn text_option(&self, cx: &App) -> Option<String> {
17521        let text = self.text(cx);
17522        let text = text.trim();
17523
17524        if text.is_empty() {
17525            return None;
17526        }
17527
17528        Some(text.to_string())
17529    }
17530
17531    pub fn set_text(
17532        &mut self,
17533        text: impl Into<Arc<str>>,
17534        window: &mut Window,
17535        cx: &mut Context<Self>,
17536    ) {
17537        self.transact(window, cx, |this, _, cx| {
17538            this.buffer
17539                .read(cx)
17540                .as_singleton()
17541                .expect("you can only call set_text on editors for singleton buffers")
17542                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17543        });
17544    }
17545
17546    pub fn display_text(&self, cx: &mut App) -> String {
17547        self.display_map
17548            .update(cx, |map, cx| map.snapshot(cx))
17549            .text()
17550    }
17551
17552    fn create_minimap(
17553        &self,
17554        minimap_settings: MinimapSettings,
17555        window: &mut Window,
17556        cx: &mut Context<Self>,
17557    ) -> Option<Entity<Self>> {
17558        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17559            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17560    }
17561
17562    fn initialize_new_minimap(
17563        &self,
17564        minimap_settings: MinimapSettings,
17565        window: &mut Window,
17566        cx: &mut Context<Self>,
17567    ) -> Entity<Self> {
17568        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17569
17570        let mut minimap = Editor::new_internal(
17571            EditorMode::Minimap {
17572                parent: cx.weak_entity(),
17573            },
17574            self.buffer.clone(),
17575            self.project.clone(),
17576            Some(self.display_map.clone()),
17577            window,
17578            cx,
17579        );
17580        minimap.scroll_manager.clone_state(&self.scroll_manager);
17581        minimap.set_text_style_refinement(TextStyleRefinement {
17582            font_size: Some(MINIMAP_FONT_SIZE),
17583            font_weight: Some(MINIMAP_FONT_WEIGHT),
17584            ..Default::default()
17585        });
17586        minimap.update_minimap_configuration(minimap_settings, cx);
17587        cx.new(|_| minimap)
17588    }
17589
17590    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17591        let current_line_highlight = minimap_settings
17592            .current_line_highlight
17593            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17594        self.set_current_line_highlight(Some(current_line_highlight));
17595    }
17596
17597    pub fn minimap(&self) -> Option<&Entity<Self>> {
17598        self.minimap
17599            .as_ref()
17600            .filter(|_| self.minimap_visibility.visible())
17601    }
17602
17603    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17604        let mut wrap_guides = smallvec![];
17605
17606        if self.show_wrap_guides == Some(false) {
17607            return wrap_guides;
17608        }
17609
17610        let settings = self.buffer.read(cx).language_settings(cx);
17611        if settings.show_wrap_guides {
17612            match self.soft_wrap_mode(cx) {
17613                SoftWrap::Column(soft_wrap) => {
17614                    wrap_guides.push((soft_wrap as usize, true));
17615                }
17616                SoftWrap::Bounded(soft_wrap) => {
17617                    wrap_guides.push((soft_wrap as usize, true));
17618                }
17619                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17620            }
17621            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17622        }
17623
17624        wrap_guides
17625    }
17626
17627    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17628        let settings = self.buffer.read(cx).language_settings(cx);
17629        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17630        match mode {
17631            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17632                SoftWrap::None
17633            }
17634            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17635            language_settings::SoftWrap::PreferredLineLength => {
17636                SoftWrap::Column(settings.preferred_line_length)
17637            }
17638            language_settings::SoftWrap::Bounded => {
17639                SoftWrap::Bounded(settings.preferred_line_length)
17640            }
17641        }
17642    }
17643
17644    pub fn set_soft_wrap_mode(
17645        &mut self,
17646        mode: language_settings::SoftWrap,
17647
17648        cx: &mut Context<Self>,
17649    ) {
17650        self.soft_wrap_mode_override = Some(mode);
17651        cx.notify();
17652    }
17653
17654    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17655        self.hard_wrap = hard_wrap;
17656        cx.notify();
17657    }
17658
17659    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17660        self.text_style_refinement = Some(style);
17661    }
17662
17663    /// called by the Element so we know what style we were most recently rendered with.
17664    pub(crate) fn set_style(
17665        &mut self,
17666        style: EditorStyle,
17667        window: &mut Window,
17668        cx: &mut Context<Self>,
17669    ) {
17670        // We intentionally do not inform the display map about the minimap style
17671        // so that wrapping is not recalculated and stays consistent for the editor
17672        // and its linked minimap.
17673        if !self.mode.is_minimap() {
17674            let rem_size = window.rem_size();
17675            self.display_map.update(cx, |map, cx| {
17676                map.set_font(
17677                    style.text.font(),
17678                    style.text.font_size.to_pixels(rem_size),
17679                    cx,
17680                )
17681            });
17682        }
17683        self.style = Some(style);
17684    }
17685
17686    pub fn style(&self) -> Option<&EditorStyle> {
17687        self.style.as_ref()
17688    }
17689
17690    // Called by the element. This method is not designed to be called outside of the editor
17691    // element's layout code because it does not notify when rewrapping is computed synchronously.
17692    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17693        self.display_map
17694            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17695    }
17696
17697    pub fn set_soft_wrap(&mut self) {
17698        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17699    }
17700
17701    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17702        if self.soft_wrap_mode_override.is_some() {
17703            self.soft_wrap_mode_override.take();
17704        } else {
17705            let soft_wrap = match self.soft_wrap_mode(cx) {
17706                SoftWrap::GitDiff => return,
17707                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17708                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17709                    language_settings::SoftWrap::None
17710                }
17711            };
17712            self.soft_wrap_mode_override = Some(soft_wrap);
17713        }
17714        cx.notify();
17715    }
17716
17717    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17718        let Some(workspace) = self.workspace() else {
17719            return;
17720        };
17721        let fs = workspace.read(cx).app_state().fs.clone();
17722        let current_show = TabBarSettings::get_global(cx).show;
17723        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17724            setting.show = Some(!current_show);
17725        });
17726    }
17727
17728    pub fn toggle_indent_guides(
17729        &mut self,
17730        _: &ToggleIndentGuides,
17731        _: &mut Window,
17732        cx: &mut Context<Self>,
17733    ) {
17734        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17735            self.buffer
17736                .read(cx)
17737                .language_settings(cx)
17738                .indent_guides
17739                .enabled
17740        });
17741        self.show_indent_guides = Some(!currently_enabled);
17742        cx.notify();
17743    }
17744
17745    fn should_show_indent_guides(&self) -> Option<bool> {
17746        self.show_indent_guides
17747    }
17748
17749    pub fn toggle_line_numbers(
17750        &mut self,
17751        _: &ToggleLineNumbers,
17752        _: &mut Window,
17753        cx: &mut Context<Self>,
17754    ) {
17755        let mut editor_settings = EditorSettings::get_global(cx).clone();
17756        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17757        EditorSettings::override_global(editor_settings, cx);
17758    }
17759
17760    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17761        if let Some(show_line_numbers) = self.show_line_numbers {
17762            return show_line_numbers;
17763        }
17764        EditorSettings::get_global(cx).gutter.line_numbers
17765    }
17766
17767    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17768        self.use_relative_line_numbers
17769            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17770    }
17771
17772    pub fn toggle_relative_line_numbers(
17773        &mut self,
17774        _: &ToggleRelativeLineNumbers,
17775        _: &mut Window,
17776        cx: &mut Context<Self>,
17777    ) {
17778        let is_relative = self.should_use_relative_line_numbers(cx);
17779        self.set_relative_line_number(Some(!is_relative), cx)
17780    }
17781
17782    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17783        self.use_relative_line_numbers = is_relative;
17784        cx.notify();
17785    }
17786
17787    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17788        self.show_gutter = show_gutter;
17789        cx.notify();
17790    }
17791
17792    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17793        self.show_scrollbars = ScrollbarAxes {
17794            horizontal: show,
17795            vertical: show,
17796        };
17797        cx.notify();
17798    }
17799
17800    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17801        self.show_scrollbars.vertical = show;
17802        cx.notify();
17803    }
17804
17805    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17806        self.show_scrollbars.horizontal = show;
17807        cx.notify();
17808    }
17809
17810    pub fn set_minimap_visibility(
17811        &mut self,
17812        minimap_visibility: MinimapVisibility,
17813        window: &mut Window,
17814        cx: &mut Context<Self>,
17815    ) {
17816        if self.minimap_visibility != minimap_visibility {
17817            if minimap_visibility.visible() && self.minimap.is_none() {
17818                let minimap_settings = EditorSettings::get_global(cx).minimap;
17819                self.minimap =
17820                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17821            }
17822            self.minimap_visibility = minimap_visibility;
17823            cx.notify();
17824        }
17825    }
17826
17827    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17828        self.set_show_scrollbars(false, cx);
17829        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17830    }
17831
17832    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17833        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17834    }
17835
17836    /// Normally the text in full mode and auto height editors is padded on the
17837    /// left side by roughly half a character width for improved hit testing.
17838    ///
17839    /// Use this method to disable this for cases where this is not wanted (e.g.
17840    /// if you want to align the editor text with some other text above or below)
17841    /// or if you want to add this padding to single-line editors.
17842    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17843        self.offset_content = offset_content;
17844        cx.notify();
17845    }
17846
17847    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17848        self.show_line_numbers = Some(show_line_numbers);
17849        cx.notify();
17850    }
17851
17852    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17853        self.disable_expand_excerpt_buttons = true;
17854        cx.notify();
17855    }
17856
17857    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17858        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17859        cx.notify();
17860    }
17861
17862    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17863        self.show_code_actions = Some(show_code_actions);
17864        cx.notify();
17865    }
17866
17867    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17868        self.show_runnables = Some(show_runnables);
17869        cx.notify();
17870    }
17871
17872    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17873        self.show_breakpoints = Some(show_breakpoints);
17874        cx.notify();
17875    }
17876
17877    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17878        if self.display_map.read(cx).masked != masked {
17879            self.display_map.update(cx, |map, _| map.masked = masked);
17880        }
17881        cx.notify()
17882    }
17883
17884    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17885        self.show_wrap_guides = Some(show_wrap_guides);
17886        cx.notify();
17887    }
17888
17889    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17890        self.show_indent_guides = Some(show_indent_guides);
17891        cx.notify();
17892    }
17893
17894    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17895        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17896            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17897                if let Some(dir) = file.abs_path(cx).parent() {
17898                    return Some(dir.to_owned());
17899                }
17900            }
17901
17902            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17903                return Some(project_path.path.to_path_buf());
17904            }
17905        }
17906
17907        None
17908    }
17909
17910    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17911        self.active_excerpt(cx)?
17912            .1
17913            .read(cx)
17914            .file()
17915            .and_then(|f| f.as_local())
17916    }
17917
17918    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17919        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17920            let buffer = buffer.read(cx);
17921            if let Some(project_path) = buffer.project_path(cx) {
17922                let project = self.project.as_ref()?.read(cx);
17923                project.absolute_path(&project_path, cx)
17924            } else {
17925                buffer
17926                    .file()
17927                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17928            }
17929        })
17930    }
17931
17932    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17933        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17934            let project_path = buffer.read(cx).project_path(cx)?;
17935            let project = self.project.as_ref()?.read(cx);
17936            let entry = project.entry_for_path(&project_path, cx)?;
17937            let path = entry.path.to_path_buf();
17938            Some(path)
17939        })
17940    }
17941
17942    pub fn reveal_in_finder(
17943        &mut self,
17944        _: &RevealInFileManager,
17945        _window: &mut Window,
17946        cx: &mut Context<Self>,
17947    ) {
17948        if let Some(target) = self.target_file(cx) {
17949            cx.reveal_path(&target.abs_path(cx));
17950        }
17951    }
17952
17953    pub fn copy_path(
17954        &mut self,
17955        _: &zed_actions::workspace::CopyPath,
17956        _window: &mut Window,
17957        cx: &mut Context<Self>,
17958    ) {
17959        if let Some(path) = self.target_file_abs_path(cx) {
17960            if let Some(path) = path.to_str() {
17961                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17962            }
17963        }
17964    }
17965
17966    pub fn copy_relative_path(
17967        &mut self,
17968        _: &zed_actions::workspace::CopyRelativePath,
17969        _window: &mut Window,
17970        cx: &mut Context<Self>,
17971    ) {
17972        if let Some(path) = self.target_file_path(cx) {
17973            if let Some(path) = path.to_str() {
17974                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17975            }
17976        }
17977    }
17978
17979    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17980        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17981            buffer.read(cx).project_path(cx)
17982        } else {
17983            None
17984        }
17985    }
17986
17987    // Returns true if the editor handled a go-to-line request
17988    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17989        maybe!({
17990            let breakpoint_store = self.breakpoint_store.as_ref()?;
17991
17992            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17993            else {
17994                self.clear_row_highlights::<ActiveDebugLine>();
17995                return None;
17996            };
17997
17998            let position = active_stack_frame.position;
17999            let buffer_id = position.buffer_id?;
18000            let snapshot = self
18001                .project
18002                .as_ref()?
18003                .read(cx)
18004                .buffer_for_id(buffer_id, cx)?
18005                .read(cx)
18006                .snapshot();
18007
18008            let mut handled = false;
18009            for (id, ExcerptRange { context, .. }) in
18010                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18011            {
18012                if context.start.cmp(&position, &snapshot).is_ge()
18013                    || context.end.cmp(&position, &snapshot).is_lt()
18014                {
18015                    continue;
18016                }
18017                let snapshot = self.buffer.read(cx).snapshot(cx);
18018                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18019
18020                handled = true;
18021                self.clear_row_highlights::<ActiveDebugLine>();
18022
18023                self.go_to_line::<ActiveDebugLine>(
18024                    multibuffer_anchor,
18025                    Some(cx.theme().colors().editor_debugger_active_line_background),
18026                    window,
18027                    cx,
18028                );
18029
18030                cx.notify();
18031            }
18032
18033            handled.then_some(())
18034        })
18035        .is_some()
18036    }
18037
18038    pub fn copy_file_name_without_extension(
18039        &mut self,
18040        _: &CopyFileNameWithoutExtension,
18041        _: &mut Window,
18042        cx: &mut Context<Self>,
18043    ) {
18044        if let Some(file) = self.target_file(cx) {
18045            if let Some(file_stem) = file.path().file_stem() {
18046                if let Some(name) = file_stem.to_str() {
18047                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18048                }
18049            }
18050        }
18051    }
18052
18053    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18054        if let Some(file) = self.target_file(cx) {
18055            if let Some(file_name) = file.path().file_name() {
18056                if let Some(name) = file_name.to_str() {
18057                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18058                }
18059            }
18060        }
18061    }
18062
18063    pub fn toggle_git_blame(
18064        &mut self,
18065        _: &::git::Blame,
18066        window: &mut Window,
18067        cx: &mut Context<Self>,
18068    ) {
18069        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18070
18071        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18072            self.start_git_blame(true, window, cx);
18073        }
18074
18075        cx.notify();
18076    }
18077
18078    pub fn toggle_git_blame_inline(
18079        &mut self,
18080        _: &ToggleGitBlameInline,
18081        window: &mut Window,
18082        cx: &mut Context<Self>,
18083    ) {
18084        self.toggle_git_blame_inline_internal(true, window, cx);
18085        cx.notify();
18086    }
18087
18088    pub fn open_git_blame_commit(
18089        &mut self,
18090        _: &OpenGitBlameCommit,
18091        window: &mut Window,
18092        cx: &mut Context<Self>,
18093    ) {
18094        self.open_git_blame_commit_internal(window, cx);
18095    }
18096
18097    fn open_git_blame_commit_internal(
18098        &mut self,
18099        window: &mut Window,
18100        cx: &mut Context<Self>,
18101    ) -> Option<()> {
18102        let blame = self.blame.as_ref()?;
18103        let snapshot = self.snapshot(window, cx);
18104        let cursor = self.selections.newest::<Point>(cx).head();
18105        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18106        let blame_entry = blame
18107            .update(cx, |blame, cx| {
18108                blame
18109                    .blame_for_rows(
18110                        &[RowInfo {
18111                            buffer_id: Some(buffer.remote_id()),
18112                            buffer_row: Some(point.row),
18113                            ..Default::default()
18114                        }],
18115                        cx,
18116                    )
18117                    .next()
18118            })
18119            .flatten()?;
18120        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18121        let repo = blame.read(cx).repository(cx)?;
18122        let workspace = self.workspace()?.downgrade();
18123        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18124        None
18125    }
18126
18127    pub fn git_blame_inline_enabled(&self) -> bool {
18128        self.git_blame_inline_enabled
18129    }
18130
18131    pub fn toggle_selection_menu(
18132        &mut self,
18133        _: &ToggleSelectionMenu,
18134        _: &mut Window,
18135        cx: &mut Context<Self>,
18136    ) {
18137        self.show_selection_menu = self
18138            .show_selection_menu
18139            .map(|show_selections_menu| !show_selections_menu)
18140            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18141
18142        cx.notify();
18143    }
18144
18145    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18146        self.show_selection_menu
18147            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18148    }
18149
18150    fn start_git_blame(
18151        &mut self,
18152        user_triggered: bool,
18153        window: &mut Window,
18154        cx: &mut Context<Self>,
18155    ) {
18156        if let Some(project) = self.project.as_ref() {
18157            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18158                return;
18159            };
18160
18161            if buffer.read(cx).file().is_none() {
18162                return;
18163            }
18164
18165            let focused = self.focus_handle(cx).contains_focused(window, cx);
18166
18167            let project = project.clone();
18168            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18169            self.blame_subscription =
18170                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18171            self.blame = Some(blame);
18172        }
18173    }
18174
18175    fn toggle_git_blame_inline_internal(
18176        &mut self,
18177        user_triggered: bool,
18178        window: &mut Window,
18179        cx: &mut Context<Self>,
18180    ) {
18181        if self.git_blame_inline_enabled {
18182            self.git_blame_inline_enabled = false;
18183            self.show_git_blame_inline = false;
18184            self.show_git_blame_inline_delay_task.take();
18185        } else {
18186            self.git_blame_inline_enabled = true;
18187            self.start_git_blame_inline(user_triggered, window, cx);
18188        }
18189
18190        cx.notify();
18191    }
18192
18193    fn start_git_blame_inline(
18194        &mut self,
18195        user_triggered: bool,
18196        window: &mut Window,
18197        cx: &mut Context<Self>,
18198    ) {
18199        self.start_git_blame(user_triggered, window, cx);
18200
18201        if ProjectSettings::get_global(cx)
18202            .git
18203            .inline_blame_delay()
18204            .is_some()
18205        {
18206            self.start_inline_blame_timer(window, cx);
18207        } else {
18208            self.show_git_blame_inline = true
18209        }
18210    }
18211
18212    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18213        self.blame.as_ref()
18214    }
18215
18216    pub fn show_git_blame_gutter(&self) -> bool {
18217        self.show_git_blame_gutter
18218    }
18219
18220    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18221        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18222    }
18223
18224    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18225        self.show_git_blame_inline
18226            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18227            && !self.newest_selection_head_on_empty_line(cx)
18228            && self.has_blame_entries(cx)
18229    }
18230
18231    fn has_blame_entries(&self, cx: &App) -> bool {
18232        self.blame()
18233            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18234    }
18235
18236    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18237        let cursor_anchor = self.selections.newest_anchor().head();
18238
18239        let snapshot = self.buffer.read(cx).snapshot(cx);
18240        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18241
18242        snapshot.line_len(buffer_row) == 0
18243    }
18244
18245    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18246        let buffer_and_selection = maybe!({
18247            let selection = self.selections.newest::<Point>(cx);
18248            let selection_range = selection.range();
18249
18250            let multi_buffer = self.buffer().read(cx);
18251            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18252            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18253
18254            let (buffer, range, _) = if selection.reversed {
18255                buffer_ranges.first()
18256            } else {
18257                buffer_ranges.last()
18258            }?;
18259
18260            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18261                ..text::ToPoint::to_point(&range.end, &buffer).row;
18262            Some((
18263                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18264                selection,
18265            ))
18266        });
18267
18268        let Some((buffer, selection)) = buffer_and_selection else {
18269            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18270        };
18271
18272        let Some(project) = self.project.as_ref() else {
18273            return Task::ready(Err(anyhow!("editor does not have project")));
18274        };
18275
18276        project.update(cx, |project, cx| {
18277            project.get_permalink_to_line(&buffer, selection, cx)
18278        })
18279    }
18280
18281    pub fn copy_permalink_to_line(
18282        &mut self,
18283        _: &CopyPermalinkToLine,
18284        window: &mut Window,
18285        cx: &mut Context<Self>,
18286    ) {
18287        let permalink_task = self.get_permalink_to_line(cx);
18288        let workspace = self.workspace();
18289
18290        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18291            Ok(permalink) => {
18292                cx.update(|_, cx| {
18293                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18294                })
18295                .ok();
18296            }
18297            Err(err) => {
18298                let message = format!("Failed to copy permalink: {err}");
18299
18300                anyhow::Result::<()>::Err(err).log_err();
18301
18302                if let Some(workspace) = workspace {
18303                    workspace
18304                        .update_in(cx, |workspace, _, cx| {
18305                            struct CopyPermalinkToLine;
18306
18307                            workspace.show_toast(
18308                                Toast::new(
18309                                    NotificationId::unique::<CopyPermalinkToLine>(),
18310                                    message,
18311                                ),
18312                                cx,
18313                            )
18314                        })
18315                        .ok();
18316                }
18317            }
18318        })
18319        .detach();
18320    }
18321
18322    pub fn copy_file_location(
18323        &mut self,
18324        _: &CopyFileLocation,
18325        _: &mut Window,
18326        cx: &mut Context<Self>,
18327    ) {
18328        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18329        if let Some(file) = self.target_file(cx) {
18330            if let Some(path) = file.path().to_str() {
18331                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18332            }
18333        }
18334    }
18335
18336    pub fn open_permalink_to_line(
18337        &mut self,
18338        _: &OpenPermalinkToLine,
18339        window: &mut Window,
18340        cx: &mut Context<Self>,
18341    ) {
18342        let permalink_task = self.get_permalink_to_line(cx);
18343        let workspace = self.workspace();
18344
18345        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18346            Ok(permalink) => {
18347                cx.update(|_, cx| {
18348                    cx.open_url(permalink.as_ref());
18349                })
18350                .ok();
18351            }
18352            Err(err) => {
18353                let message = format!("Failed to open permalink: {err}");
18354
18355                anyhow::Result::<()>::Err(err).log_err();
18356
18357                if let Some(workspace) = workspace {
18358                    workspace
18359                        .update(cx, |workspace, cx| {
18360                            struct OpenPermalinkToLine;
18361
18362                            workspace.show_toast(
18363                                Toast::new(
18364                                    NotificationId::unique::<OpenPermalinkToLine>(),
18365                                    message,
18366                                ),
18367                                cx,
18368                            )
18369                        })
18370                        .ok();
18371                }
18372            }
18373        })
18374        .detach();
18375    }
18376
18377    pub fn insert_uuid_v4(
18378        &mut self,
18379        _: &InsertUuidV4,
18380        window: &mut Window,
18381        cx: &mut Context<Self>,
18382    ) {
18383        self.insert_uuid(UuidVersion::V4, window, cx);
18384    }
18385
18386    pub fn insert_uuid_v7(
18387        &mut self,
18388        _: &InsertUuidV7,
18389        window: &mut Window,
18390        cx: &mut Context<Self>,
18391    ) {
18392        self.insert_uuid(UuidVersion::V7, window, cx);
18393    }
18394
18395    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18396        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18397        self.transact(window, cx, |this, window, cx| {
18398            let edits = this
18399                .selections
18400                .all::<Point>(cx)
18401                .into_iter()
18402                .map(|selection| {
18403                    let uuid = match version {
18404                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18405                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18406                    };
18407
18408                    (selection.range(), uuid.to_string())
18409                });
18410            this.edit(edits, cx);
18411            this.refresh_inline_completion(true, false, window, cx);
18412        });
18413    }
18414
18415    pub fn open_selections_in_multibuffer(
18416        &mut self,
18417        _: &OpenSelectionsInMultibuffer,
18418        window: &mut Window,
18419        cx: &mut Context<Self>,
18420    ) {
18421        let multibuffer = self.buffer.read(cx);
18422
18423        let Some(buffer) = multibuffer.as_singleton() else {
18424            return;
18425        };
18426
18427        let Some(workspace) = self.workspace() else {
18428            return;
18429        };
18430
18431        let title = multibuffer.title(cx).to_string();
18432
18433        let locations = self
18434            .selections
18435            .all_anchors(cx)
18436            .into_iter()
18437            .map(|selection| Location {
18438                buffer: buffer.clone(),
18439                range: selection.start.text_anchor..selection.end.text_anchor,
18440            })
18441            .collect::<Vec<_>>();
18442
18443        cx.spawn_in(window, async move |_, cx| {
18444            workspace.update_in(cx, |workspace, window, cx| {
18445                Self::open_locations_in_multibuffer(
18446                    workspace,
18447                    locations,
18448                    format!("Selections for '{title}'"),
18449                    false,
18450                    MultibufferSelectionMode::All,
18451                    window,
18452                    cx,
18453                );
18454            })
18455        })
18456        .detach();
18457    }
18458
18459    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18460    /// last highlight added will be used.
18461    ///
18462    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18463    pub fn highlight_rows<T: 'static>(
18464        &mut self,
18465        range: Range<Anchor>,
18466        color: Hsla,
18467        options: RowHighlightOptions,
18468        cx: &mut Context<Self>,
18469    ) {
18470        let snapshot = self.buffer().read(cx).snapshot(cx);
18471        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18472        let ix = row_highlights.binary_search_by(|highlight| {
18473            Ordering::Equal
18474                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18475                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18476        });
18477
18478        if let Err(mut ix) = ix {
18479            let index = post_inc(&mut self.highlight_order);
18480
18481            // If this range intersects with the preceding highlight, then merge it with
18482            // the preceding highlight. Otherwise insert a new highlight.
18483            let mut merged = false;
18484            if ix > 0 {
18485                let prev_highlight = &mut row_highlights[ix - 1];
18486                if prev_highlight
18487                    .range
18488                    .end
18489                    .cmp(&range.start, &snapshot)
18490                    .is_ge()
18491                {
18492                    ix -= 1;
18493                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18494                        prev_highlight.range.end = range.end;
18495                    }
18496                    merged = true;
18497                    prev_highlight.index = index;
18498                    prev_highlight.color = color;
18499                    prev_highlight.options = options;
18500                }
18501            }
18502
18503            if !merged {
18504                row_highlights.insert(
18505                    ix,
18506                    RowHighlight {
18507                        range: range.clone(),
18508                        index,
18509                        color,
18510                        options,
18511                        type_id: TypeId::of::<T>(),
18512                    },
18513                );
18514            }
18515
18516            // If any of the following highlights intersect with this one, merge them.
18517            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18518                let highlight = &row_highlights[ix];
18519                if next_highlight
18520                    .range
18521                    .start
18522                    .cmp(&highlight.range.end, &snapshot)
18523                    .is_le()
18524                {
18525                    if next_highlight
18526                        .range
18527                        .end
18528                        .cmp(&highlight.range.end, &snapshot)
18529                        .is_gt()
18530                    {
18531                        row_highlights[ix].range.end = next_highlight.range.end;
18532                    }
18533                    row_highlights.remove(ix + 1);
18534                } else {
18535                    break;
18536                }
18537            }
18538        }
18539    }
18540
18541    /// Remove any highlighted row ranges of the given type that intersect the
18542    /// given ranges.
18543    pub fn remove_highlighted_rows<T: 'static>(
18544        &mut self,
18545        ranges_to_remove: Vec<Range<Anchor>>,
18546        cx: &mut Context<Self>,
18547    ) {
18548        let snapshot = self.buffer().read(cx).snapshot(cx);
18549        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18550        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18551        row_highlights.retain(|highlight| {
18552            while let Some(range_to_remove) = ranges_to_remove.peek() {
18553                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18554                    Ordering::Less | Ordering::Equal => {
18555                        ranges_to_remove.next();
18556                    }
18557                    Ordering::Greater => {
18558                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18559                            Ordering::Less | Ordering::Equal => {
18560                                return false;
18561                            }
18562                            Ordering::Greater => break,
18563                        }
18564                    }
18565                }
18566            }
18567
18568            true
18569        })
18570    }
18571
18572    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18573    pub fn clear_row_highlights<T: 'static>(&mut self) {
18574        self.highlighted_rows.remove(&TypeId::of::<T>());
18575    }
18576
18577    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18578    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18579        self.highlighted_rows
18580            .get(&TypeId::of::<T>())
18581            .map_or(&[] as &[_], |vec| vec.as_slice())
18582            .iter()
18583            .map(|highlight| (highlight.range.clone(), highlight.color))
18584    }
18585
18586    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18587    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18588    /// Allows to ignore certain kinds of highlights.
18589    pub fn highlighted_display_rows(
18590        &self,
18591        window: &mut Window,
18592        cx: &mut App,
18593    ) -> BTreeMap<DisplayRow, LineHighlight> {
18594        let snapshot = self.snapshot(window, cx);
18595        let mut used_highlight_orders = HashMap::default();
18596        self.highlighted_rows
18597            .iter()
18598            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18599            .fold(
18600                BTreeMap::<DisplayRow, LineHighlight>::new(),
18601                |mut unique_rows, highlight| {
18602                    let start = highlight.range.start.to_display_point(&snapshot);
18603                    let end = highlight.range.end.to_display_point(&snapshot);
18604                    let start_row = start.row().0;
18605                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18606                        && end.column() == 0
18607                    {
18608                        end.row().0.saturating_sub(1)
18609                    } else {
18610                        end.row().0
18611                    };
18612                    for row in start_row..=end_row {
18613                        let used_index =
18614                            used_highlight_orders.entry(row).or_insert(highlight.index);
18615                        if highlight.index >= *used_index {
18616                            *used_index = highlight.index;
18617                            unique_rows.insert(
18618                                DisplayRow(row),
18619                                LineHighlight {
18620                                    include_gutter: highlight.options.include_gutter,
18621                                    border: None,
18622                                    background: highlight.color.into(),
18623                                    type_id: Some(highlight.type_id),
18624                                },
18625                            );
18626                        }
18627                    }
18628                    unique_rows
18629                },
18630            )
18631    }
18632
18633    pub fn highlighted_display_row_for_autoscroll(
18634        &self,
18635        snapshot: &DisplaySnapshot,
18636    ) -> Option<DisplayRow> {
18637        self.highlighted_rows
18638            .values()
18639            .flat_map(|highlighted_rows| highlighted_rows.iter())
18640            .filter_map(|highlight| {
18641                if highlight.options.autoscroll {
18642                    Some(highlight.range.start.to_display_point(snapshot).row())
18643                } else {
18644                    None
18645                }
18646            })
18647            .min()
18648    }
18649
18650    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18651        self.highlight_background::<SearchWithinRange>(
18652            ranges,
18653            |colors| colors.colors().editor_document_highlight_read_background,
18654            cx,
18655        )
18656    }
18657
18658    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18659        self.breadcrumb_header = Some(new_header);
18660    }
18661
18662    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18663        self.clear_background_highlights::<SearchWithinRange>(cx);
18664    }
18665
18666    pub fn highlight_background<T: 'static>(
18667        &mut self,
18668        ranges: &[Range<Anchor>],
18669        color_fetcher: fn(&Theme) -> Hsla,
18670        cx: &mut Context<Self>,
18671    ) {
18672        self.background_highlights.insert(
18673            HighlightKey::Type(TypeId::of::<T>()),
18674            (color_fetcher, Arc::from(ranges)),
18675        );
18676        self.scrollbar_marker_state.dirty = true;
18677        cx.notify();
18678    }
18679
18680    pub fn highlight_background_key<T: 'static>(
18681        &mut self,
18682        key: usize,
18683        ranges: &[Range<Anchor>],
18684        color_fetcher: fn(&Theme) -> Hsla,
18685        cx: &mut Context<Self>,
18686    ) {
18687        self.background_highlights.insert(
18688            HighlightKey::TypePlus(TypeId::of::<T>(), key),
18689            (color_fetcher, Arc::from(ranges)),
18690        );
18691        self.scrollbar_marker_state.dirty = true;
18692        cx.notify();
18693    }
18694
18695    pub fn clear_background_highlights<T: 'static>(
18696        &mut self,
18697        cx: &mut Context<Self>,
18698    ) -> Option<BackgroundHighlight> {
18699        let text_highlights = self
18700            .background_highlights
18701            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
18702        if !text_highlights.1.is_empty() {
18703            self.scrollbar_marker_state.dirty = true;
18704            cx.notify();
18705        }
18706        Some(text_highlights)
18707    }
18708
18709    pub fn highlight_gutter<T: 'static>(
18710        &mut self,
18711        ranges: impl Into<Vec<Range<Anchor>>>,
18712        color_fetcher: fn(&App) -> Hsla,
18713        cx: &mut Context<Self>,
18714    ) {
18715        self.gutter_highlights
18716            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18717        cx.notify();
18718    }
18719
18720    pub fn clear_gutter_highlights<T: 'static>(
18721        &mut self,
18722        cx: &mut Context<Self>,
18723    ) -> Option<GutterHighlight> {
18724        cx.notify();
18725        self.gutter_highlights.remove(&TypeId::of::<T>())
18726    }
18727
18728    pub fn insert_gutter_highlight<T: 'static>(
18729        &mut self,
18730        range: Range<Anchor>,
18731        color_fetcher: fn(&App) -> Hsla,
18732        cx: &mut Context<Self>,
18733    ) {
18734        let snapshot = self.buffer().read(cx).snapshot(cx);
18735        let mut highlights = self
18736            .gutter_highlights
18737            .remove(&TypeId::of::<T>())
18738            .map(|(_, highlights)| highlights)
18739            .unwrap_or_default();
18740        let ix = highlights.binary_search_by(|highlight| {
18741            Ordering::Equal
18742                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18743                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18744        });
18745        if let Err(ix) = ix {
18746            highlights.insert(ix, range);
18747        }
18748        self.gutter_highlights
18749            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18750    }
18751
18752    pub fn remove_gutter_highlights<T: 'static>(
18753        &mut self,
18754        ranges_to_remove: Vec<Range<Anchor>>,
18755        cx: &mut Context<Self>,
18756    ) {
18757        let snapshot = self.buffer().read(cx).snapshot(cx);
18758        let Some((color_fetcher, mut gutter_highlights)) =
18759            self.gutter_highlights.remove(&TypeId::of::<T>())
18760        else {
18761            return;
18762        };
18763        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18764        gutter_highlights.retain(|highlight| {
18765            while let Some(range_to_remove) = ranges_to_remove.peek() {
18766                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18767                    Ordering::Less | Ordering::Equal => {
18768                        ranges_to_remove.next();
18769                    }
18770                    Ordering::Greater => {
18771                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18772                            Ordering::Less | Ordering::Equal => {
18773                                return false;
18774                            }
18775                            Ordering::Greater => break,
18776                        }
18777                    }
18778                }
18779            }
18780
18781            true
18782        });
18783        self.gutter_highlights
18784            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18785    }
18786
18787    #[cfg(feature = "test-support")]
18788    pub fn all_text_highlights(
18789        &self,
18790        window: &mut Window,
18791        cx: &mut Context<Self>,
18792    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
18793        let snapshot = self.snapshot(window, cx);
18794        self.display_map.update(cx, |display_map, _| {
18795            display_map
18796                .all_text_highlights()
18797                .map(|highlight| {
18798                    let (style, ranges) = highlight.as_ref();
18799                    (
18800                        *style,
18801                        ranges
18802                            .iter()
18803                            .map(|range| range.clone().to_display_points(&snapshot))
18804                            .collect(),
18805                    )
18806                })
18807                .collect()
18808        })
18809    }
18810
18811    #[cfg(feature = "test-support")]
18812    pub fn all_text_background_highlights(
18813        &self,
18814        window: &mut Window,
18815        cx: &mut Context<Self>,
18816    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18817        let snapshot = self.snapshot(window, cx);
18818        let buffer = &snapshot.buffer_snapshot;
18819        let start = buffer.anchor_before(0);
18820        let end = buffer.anchor_after(buffer.len());
18821        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
18822    }
18823
18824    #[cfg(feature = "test-support")]
18825    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18826        let snapshot = self.buffer().read(cx).snapshot(cx);
18827
18828        let highlights = self
18829            .background_highlights
18830            .get(&HighlightKey::Type(TypeId::of::<
18831                items::BufferSearchHighlights,
18832            >()));
18833
18834        if let Some((_color, ranges)) = highlights {
18835            ranges
18836                .iter()
18837                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18838                .collect_vec()
18839        } else {
18840            vec![]
18841        }
18842    }
18843
18844    fn document_highlights_for_position<'a>(
18845        &'a self,
18846        position: Anchor,
18847        buffer: &'a MultiBufferSnapshot,
18848    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18849        let read_highlights = self
18850            .background_highlights
18851            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
18852            .map(|h| &h.1);
18853        let write_highlights = self
18854            .background_highlights
18855            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
18856            .map(|h| &h.1);
18857        let left_position = position.bias_left(buffer);
18858        let right_position = position.bias_right(buffer);
18859        read_highlights
18860            .into_iter()
18861            .chain(write_highlights)
18862            .flat_map(move |ranges| {
18863                let start_ix = match ranges.binary_search_by(|probe| {
18864                    let cmp = probe.end.cmp(&left_position, buffer);
18865                    if cmp.is_ge() {
18866                        Ordering::Greater
18867                    } else {
18868                        Ordering::Less
18869                    }
18870                }) {
18871                    Ok(i) | Err(i) => i,
18872                };
18873
18874                ranges[start_ix..]
18875                    .iter()
18876                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18877            })
18878    }
18879
18880    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18881        self.background_highlights
18882            .get(&HighlightKey::Type(TypeId::of::<T>()))
18883            .map_or(false, |(_, highlights)| !highlights.is_empty())
18884    }
18885
18886    pub fn background_highlights_in_range(
18887        &self,
18888        search_range: Range<Anchor>,
18889        display_snapshot: &DisplaySnapshot,
18890        theme: &Theme,
18891    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18892        let mut results = Vec::new();
18893        for (color_fetcher, ranges) in self.background_highlights.values() {
18894            let color = color_fetcher(theme);
18895            let start_ix = match ranges.binary_search_by(|probe| {
18896                let cmp = probe
18897                    .end
18898                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18899                if cmp.is_gt() {
18900                    Ordering::Greater
18901                } else {
18902                    Ordering::Less
18903                }
18904            }) {
18905                Ok(i) | Err(i) => i,
18906            };
18907            for range in &ranges[start_ix..] {
18908                if range
18909                    .start
18910                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18911                    .is_ge()
18912                {
18913                    break;
18914                }
18915
18916                let start = range.start.to_display_point(display_snapshot);
18917                let end = range.end.to_display_point(display_snapshot);
18918                results.push((start..end, color))
18919            }
18920        }
18921        results
18922    }
18923
18924    pub fn background_highlight_row_ranges<T: 'static>(
18925        &self,
18926        search_range: Range<Anchor>,
18927        display_snapshot: &DisplaySnapshot,
18928        count: usize,
18929    ) -> Vec<RangeInclusive<DisplayPoint>> {
18930        let mut results = Vec::new();
18931        let Some((_, ranges)) = self
18932            .background_highlights
18933            .get(&HighlightKey::Type(TypeId::of::<T>()))
18934        else {
18935            return vec![];
18936        };
18937
18938        let start_ix = match ranges.binary_search_by(|probe| {
18939            let cmp = probe
18940                .end
18941                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18942            if cmp.is_gt() {
18943                Ordering::Greater
18944            } else {
18945                Ordering::Less
18946            }
18947        }) {
18948            Ok(i) | Err(i) => i,
18949        };
18950        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18951            if let (Some(start_display), Some(end_display)) = (start, end) {
18952                results.push(
18953                    start_display.to_display_point(display_snapshot)
18954                        ..=end_display.to_display_point(display_snapshot),
18955                );
18956            }
18957        };
18958        let mut start_row: Option<Point> = None;
18959        let mut end_row: Option<Point> = None;
18960        if ranges.len() > count {
18961            return Vec::new();
18962        }
18963        for range in &ranges[start_ix..] {
18964            if range
18965                .start
18966                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18967                .is_ge()
18968            {
18969                break;
18970            }
18971            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18972            if let Some(current_row) = &end_row {
18973                if end.row == current_row.row {
18974                    continue;
18975                }
18976            }
18977            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18978            if start_row.is_none() {
18979                assert_eq!(end_row, None);
18980                start_row = Some(start);
18981                end_row = Some(end);
18982                continue;
18983            }
18984            if let Some(current_end) = end_row.as_mut() {
18985                if start.row > current_end.row + 1 {
18986                    push_region(start_row, end_row);
18987                    start_row = Some(start);
18988                    end_row = Some(end);
18989                } else {
18990                    // Merge two hunks.
18991                    *current_end = end;
18992                }
18993            } else {
18994                unreachable!();
18995            }
18996        }
18997        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18998        push_region(start_row, end_row);
18999        results
19000    }
19001
19002    pub fn gutter_highlights_in_range(
19003        &self,
19004        search_range: Range<Anchor>,
19005        display_snapshot: &DisplaySnapshot,
19006        cx: &App,
19007    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19008        let mut results = Vec::new();
19009        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19010            let color = color_fetcher(cx);
19011            let start_ix = match ranges.binary_search_by(|probe| {
19012                let cmp = probe
19013                    .end
19014                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19015                if cmp.is_gt() {
19016                    Ordering::Greater
19017                } else {
19018                    Ordering::Less
19019                }
19020            }) {
19021                Ok(i) | Err(i) => i,
19022            };
19023            for range in &ranges[start_ix..] {
19024                if range
19025                    .start
19026                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19027                    .is_ge()
19028                {
19029                    break;
19030                }
19031
19032                let start = range.start.to_display_point(display_snapshot);
19033                let end = range.end.to_display_point(display_snapshot);
19034                results.push((start..end, color))
19035            }
19036        }
19037        results
19038    }
19039
19040    /// Get the text ranges corresponding to the redaction query
19041    pub fn redacted_ranges(
19042        &self,
19043        search_range: Range<Anchor>,
19044        display_snapshot: &DisplaySnapshot,
19045        cx: &App,
19046    ) -> Vec<Range<DisplayPoint>> {
19047        display_snapshot
19048            .buffer_snapshot
19049            .redacted_ranges(search_range, |file| {
19050                if let Some(file) = file {
19051                    file.is_private()
19052                        && EditorSettings::get(
19053                            Some(SettingsLocation {
19054                                worktree_id: file.worktree_id(cx),
19055                                path: file.path().as_ref(),
19056                            }),
19057                            cx,
19058                        )
19059                        .redact_private_values
19060                } else {
19061                    false
19062                }
19063            })
19064            .map(|range| {
19065                range.start.to_display_point(display_snapshot)
19066                    ..range.end.to_display_point(display_snapshot)
19067            })
19068            .collect()
19069    }
19070
19071    pub fn highlight_text_key<T: 'static>(
19072        &mut self,
19073        key: usize,
19074        ranges: Vec<Range<Anchor>>,
19075        style: HighlightStyle,
19076        cx: &mut Context<Self>,
19077    ) {
19078        self.display_map.update(cx, |map, _| {
19079            map.highlight_text(
19080                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19081                ranges,
19082                style,
19083            );
19084        });
19085        cx.notify();
19086    }
19087
19088    pub fn highlight_text<T: 'static>(
19089        &mut self,
19090        ranges: Vec<Range<Anchor>>,
19091        style: HighlightStyle,
19092        cx: &mut Context<Self>,
19093    ) {
19094        self.display_map.update(cx, |map, _| {
19095            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19096        });
19097        cx.notify();
19098    }
19099
19100    pub(crate) fn highlight_inlays<T: 'static>(
19101        &mut self,
19102        highlights: Vec<InlayHighlight>,
19103        style: HighlightStyle,
19104        cx: &mut Context<Self>,
19105    ) {
19106        self.display_map.update(cx, |map, _| {
19107            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19108        });
19109        cx.notify();
19110    }
19111
19112    pub fn text_highlights<'a, T: 'static>(
19113        &'a self,
19114        cx: &'a App,
19115    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19116        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19117    }
19118
19119    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19120        let cleared = self
19121            .display_map
19122            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19123        if cleared {
19124            cx.notify();
19125        }
19126    }
19127
19128    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19129        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19130            && self.focus_handle.is_focused(window)
19131    }
19132
19133    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19134        self.show_cursor_when_unfocused = is_enabled;
19135        cx.notify();
19136    }
19137
19138    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19139        cx.notify();
19140    }
19141
19142    fn on_debug_session_event(
19143        &mut self,
19144        _session: Entity<Session>,
19145        event: &SessionEvent,
19146        cx: &mut Context<Self>,
19147    ) {
19148        match event {
19149            SessionEvent::InvalidateInlineValue => {
19150                self.refresh_inline_values(cx);
19151            }
19152            _ => {}
19153        }
19154    }
19155
19156    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19157        let Some(project) = self.project.clone() else {
19158            return;
19159        };
19160
19161        if !self.inline_value_cache.enabled {
19162            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19163            self.splice_inlays(&inlays, Vec::new(), cx);
19164            return;
19165        }
19166
19167        let current_execution_position = self
19168            .highlighted_rows
19169            .get(&TypeId::of::<ActiveDebugLine>())
19170            .and_then(|lines| lines.last().map(|line| line.range.end));
19171
19172        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19173            let inline_values = editor
19174                .update(cx, |editor, cx| {
19175                    let Some(current_execution_position) = current_execution_position else {
19176                        return Some(Task::ready(Ok(Vec::new())));
19177                    };
19178
19179                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19180                        let snapshot = buffer.snapshot(cx);
19181
19182                        let excerpt = snapshot.excerpt_containing(
19183                            current_execution_position..current_execution_position,
19184                        )?;
19185
19186                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19187                    })?;
19188
19189                    let range =
19190                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19191
19192                    project.inline_values(buffer, range, cx)
19193                })
19194                .ok()
19195                .flatten()?
19196                .await
19197                .context("refreshing debugger inlays")
19198                .log_err()?;
19199
19200            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19201
19202            for (buffer_id, inline_value) in inline_values
19203                .into_iter()
19204                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19205            {
19206                buffer_inline_values
19207                    .entry(buffer_id)
19208                    .or_default()
19209                    .push(inline_value);
19210            }
19211
19212            editor
19213                .update(cx, |editor, cx| {
19214                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19215                    let mut new_inlays = Vec::default();
19216
19217                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19218                        let buffer_id = buffer_snapshot.remote_id();
19219                        buffer_inline_values
19220                            .get(&buffer_id)
19221                            .into_iter()
19222                            .flatten()
19223                            .for_each(|hint| {
19224                                let inlay = Inlay::debugger(
19225                                    post_inc(&mut editor.next_inlay_id),
19226                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19227                                    hint.text(),
19228                                );
19229
19230                                new_inlays.push(inlay);
19231                            });
19232                    }
19233
19234                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19235                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19236
19237                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19238                })
19239                .ok()?;
19240            Some(())
19241        });
19242    }
19243
19244    fn on_buffer_event(
19245        &mut self,
19246        multibuffer: &Entity<MultiBuffer>,
19247        event: &multi_buffer::Event,
19248        window: &mut Window,
19249        cx: &mut Context<Self>,
19250    ) {
19251        match event {
19252            multi_buffer::Event::Edited {
19253                singleton_buffer_edited,
19254                edited_buffer,
19255            } => {
19256                self.scrollbar_marker_state.dirty = true;
19257                self.active_indent_guides_state.dirty = true;
19258                self.refresh_active_diagnostics(cx);
19259                self.refresh_code_actions(window, cx);
19260                self.refresh_selected_text_highlights(true, window, cx);
19261                refresh_matching_bracket_highlights(self, window, cx);
19262                if self.has_active_inline_completion() {
19263                    self.update_visible_inline_completion(window, cx);
19264                }
19265                if let Some(project) = self.project.as_ref() {
19266                    if let Some(edited_buffer) = edited_buffer {
19267                        project.update(cx, |project, cx| {
19268                            self.registered_buffers
19269                                .entry(edited_buffer.read(cx).remote_id())
19270                                .or_insert_with(|| {
19271                                    project
19272                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19273                                });
19274                        });
19275                    }
19276                }
19277                cx.emit(EditorEvent::BufferEdited);
19278                cx.emit(SearchEvent::MatchesInvalidated);
19279
19280                if let Some(buffer) = edited_buffer {
19281                    self.update_lsp_data(None, Some(buffer.read(cx).remote_id()), window, cx);
19282                }
19283
19284                if *singleton_buffer_edited {
19285                    if let Some(buffer) = edited_buffer {
19286                        if buffer.read(cx).file().is_none() {
19287                            cx.emit(EditorEvent::TitleChanged);
19288                        }
19289                    }
19290                    if let Some(project) = &self.project {
19291                        #[allow(clippy::mutable_key_type)]
19292                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19293                            multibuffer
19294                                .all_buffers()
19295                                .into_iter()
19296                                .filter_map(|buffer| {
19297                                    buffer.update(cx, |buffer, cx| {
19298                                        let language = buffer.language()?;
19299                                        let should_discard = project.update(cx, |project, cx| {
19300                                            project.is_local()
19301                                                && !project.has_language_servers_for(buffer, cx)
19302                                        });
19303                                        should_discard.not().then_some(language.clone())
19304                                    })
19305                                })
19306                                .collect::<HashSet<_>>()
19307                        });
19308                        if !languages_affected.is_empty() {
19309                            self.refresh_inlay_hints(
19310                                InlayHintRefreshReason::BufferEdited(languages_affected),
19311                                cx,
19312                            );
19313                        }
19314                    }
19315                }
19316
19317                let Some(project) = &self.project else { return };
19318                let (telemetry, is_via_ssh) = {
19319                    let project = project.read(cx);
19320                    let telemetry = project.client().telemetry().clone();
19321                    let is_via_ssh = project.is_via_ssh();
19322                    (telemetry, is_via_ssh)
19323                };
19324                refresh_linked_ranges(self, window, cx);
19325                telemetry.log_edit_event("editor", is_via_ssh);
19326            }
19327            multi_buffer::Event::ExcerptsAdded {
19328                buffer,
19329                predecessor,
19330                excerpts,
19331            } => {
19332                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19333                let buffer_id = buffer.read(cx).remote_id();
19334                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19335                    if let Some(project) = &self.project {
19336                        update_uncommitted_diff_for_buffer(
19337                            cx.entity(),
19338                            project,
19339                            [buffer.clone()],
19340                            self.buffer.clone(),
19341                            cx,
19342                        )
19343                        .detach();
19344                    }
19345                }
19346                self.update_lsp_data(None, Some(buffer_id), window, cx);
19347                cx.emit(EditorEvent::ExcerptsAdded {
19348                    buffer: buffer.clone(),
19349                    predecessor: *predecessor,
19350                    excerpts: excerpts.clone(),
19351                });
19352                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19353            }
19354            multi_buffer::Event::ExcerptsRemoved {
19355                ids,
19356                removed_buffer_ids,
19357            } => {
19358                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19359                let buffer = self.buffer.read(cx);
19360                self.registered_buffers
19361                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19362                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19363                cx.emit(EditorEvent::ExcerptsRemoved {
19364                    ids: ids.clone(),
19365                    removed_buffer_ids: removed_buffer_ids.clone(),
19366                });
19367            }
19368            multi_buffer::Event::ExcerptsEdited {
19369                excerpt_ids,
19370                buffer_ids,
19371            } => {
19372                self.display_map.update(cx, |map, cx| {
19373                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19374                });
19375                cx.emit(EditorEvent::ExcerptsEdited {
19376                    ids: excerpt_ids.clone(),
19377                });
19378            }
19379            multi_buffer::Event::ExcerptsExpanded { ids } => {
19380                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19381                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19382            }
19383            multi_buffer::Event::Reparsed(buffer_id) => {
19384                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19385                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19386
19387                cx.emit(EditorEvent::Reparsed(*buffer_id));
19388            }
19389            multi_buffer::Event::DiffHunksToggled => {
19390                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19391            }
19392            multi_buffer::Event::LanguageChanged(buffer_id) => {
19393                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19394                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19395                cx.emit(EditorEvent::Reparsed(*buffer_id));
19396                cx.notify();
19397            }
19398            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19399            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19400            multi_buffer::Event::FileHandleChanged
19401            | multi_buffer::Event::Reloaded
19402            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19403            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19404            multi_buffer::Event::DiagnosticsUpdated => {
19405                self.update_diagnostics_state(window, cx);
19406            }
19407            _ => {}
19408        };
19409    }
19410
19411    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19412        if !self.diagnostics_enabled() {
19413            return;
19414        }
19415        self.refresh_active_diagnostics(cx);
19416        self.refresh_inline_diagnostics(true, window, cx);
19417        self.scrollbar_marker_state.dirty = true;
19418        cx.notify();
19419    }
19420
19421    pub fn start_temporary_diff_override(&mut self) {
19422        self.load_diff_task.take();
19423        self.temporary_diff_override = true;
19424    }
19425
19426    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19427        self.temporary_diff_override = false;
19428        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19429        self.buffer.update(cx, |buffer, cx| {
19430            buffer.set_all_diff_hunks_collapsed(cx);
19431        });
19432
19433        if let Some(project) = self.project.clone() {
19434            self.load_diff_task = Some(
19435                update_uncommitted_diff_for_buffer(
19436                    cx.entity(),
19437                    &project,
19438                    self.buffer.read(cx).all_buffers(),
19439                    self.buffer.clone(),
19440                    cx,
19441                )
19442                .shared(),
19443            );
19444        }
19445    }
19446
19447    fn on_display_map_changed(
19448        &mut self,
19449        _: Entity<DisplayMap>,
19450        _: &mut Window,
19451        cx: &mut Context<Self>,
19452    ) {
19453        cx.notify();
19454    }
19455
19456    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19457        let new_severity = if self.diagnostics_enabled() {
19458            EditorSettings::get_global(cx)
19459                .diagnostics_max_severity
19460                .unwrap_or(DiagnosticSeverity::Hint)
19461        } else {
19462            DiagnosticSeverity::Off
19463        };
19464        self.set_max_diagnostics_severity(new_severity, cx);
19465        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19466        self.update_edit_prediction_settings(cx);
19467        self.refresh_inline_completion(true, false, window, cx);
19468        self.refresh_inlay_hints(
19469            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19470                self.selections.newest_anchor().head(),
19471                &self.buffer.read(cx).snapshot(cx),
19472                cx,
19473            )),
19474            cx,
19475        );
19476
19477        let old_cursor_shape = self.cursor_shape;
19478
19479        {
19480            let editor_settings = EditorSettings::get_global(cx);
19481            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19482            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19483            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19484            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19485            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19486        }
19487
19488        if old_cursor_shape != self.cursor_shape {
19489            cx.emit(EditorEvent::CursorShapeChanged);
19490        }
19491
19492        let project_settings = ProjectSettings::get_global(cx);
19493        self.serialize_dirty_buffers =
19494            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19495
19496        if self.mode.is_full() {
19497            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19498            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19499            if self.show_inline_diagnostics != show_inline_diagnostics {
19500                self.show_inline_diagnostics = show_inline_diagnostics;
19501                self.refresh_inline_diagnostics(false, window, cx);
19502            }
19503
19504            if self.git_blame_inline_enabled != inline_blame_enabled {
19505                self.toggle_git_blame_inline_internal(false, window, cx);
19506            }
19507
19508            let minimap_settings = EditorSettings::get_global(cx).minimap;
19509            if self.minimap_visibility != MinimapVisibility::Disabled {
19510                if self.minimap_visibility.settings_visibility()
19511                    != minimap_settings.minimap_enabled()
19512                {
19513                    self.set_minimap_visibility(
19514                        MinimapVisibility::for_mode(self.mode(), cx),
19515                        window,
19516                        cx,
19517                    );
19518                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19519                    minimap_entity.update(cx, |minimap_editor, cx| {
19520                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19521                    })
19522                }
19523            }
19524        }
19525
19526        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19527            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19528        }) {
19529            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19530                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19531            }
19532            self.refresh_colors(None, None, window, cx);
19533        }
19534
19535        cx.notify();
19536    }
19537
19538    pub fn set_searchable(&mut self, searchable: bool) {
19539        self.searchable = searchable;
19540    }
19541
19542    pub fn searchable(&self) -> bool {
19543        self.searchable
19544    }
19545
19546    fn open_proposed_changes_editor(
19547        &mut self,
19548        _: &OpenProposedChangesEditor,
19549        window: &mut Window,
19550        cx: &mut Context<Self>,
19551    ) {
19552        let Some(workspace) = self.workspace() else {
19553            cx.propagate();
19554            return;
19555        };
19556
19557        let selections = self.selections.all::<usize>(cx);
19558        let multi_buffer = self.buffer.read(cx);
19559        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19560        let mut new_selections_by_buffer = HashMap::default();
19561        for selection in selections {
19562            for (buffer, range, _) in
19563                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19564            {
19565                let mut range = range.to_point(buffer);
19566                range.start.column = 0;
19567                range.end.column = buffer.line_len(range.end.row);
19568                new_selections_by_buffer
19569                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19570                    .or_insert(Vec::new())
19571                    .push(range)
19572            }
19573        }
19574
19575        let proposed_changes_buffers = new_selections_by_buffer
19576            .into_iter()
19577            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19578            .collect::<Vec<_>>();
19579        let proposed_changes_editor = cx.new(|cx| {
19580            ProposedChangesEditor::new(
19581                "Proposed changes",
19582                proposed_changes_buffers,
19583                self.project.clone(),
19584                window,
19585                cx,
19586            )
19587        });
19588
19589        window.defer(cx, move |window, cx| {
19590            workspace.update(cx, |workspace, cx| {
19591                workspace.active_pane().update(cx, |pane, cx| {
19592                    pane.add_item(
19593                        Box::new(proposed_changes_editor),
19594                        true,
19595                        true,
19596                        None,
19597                        window,
19598                        cx,
19599                    );
19600                });
19601            });
19602        });
19603    }
19604
19605    pub fn open_excerpts_in_split(
19606        &mut self,
19607        _: &OpenExcerptsSplit,
19608        window: &mut Window,
19609        cx: &mut Context<Self>,
19610    ) {
19611        self.open_excerpts_common(None, true, window, cx)
19612    }
19613
19614    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19615        self.open_excerpts_common(None, false, window, cx)
19616    }
19617
19618    fn open_excerpts_common(
19619        &mut self,
19620        jump_data: Option<JumpData>,
19621        split: bool,
19622        window: &mut Window,
19623        cx: &mut Context<Self>,
19624    ) {
19625        let Some(workspace) = self.workspace() else {
19626            cx.propagate();
19627            return;
19628        };
19629
19630        if self.buffer.read(cx).is_singleton() {
19631            cx.propagate();
19632            return;
19633        }
19634
19635        let mut new_selections_by_buffer = HashMap::default();
19636        match &jump_data {
19637            Some(JumpData::MultiBufferPoint {
19638                excerpt_id,
19639                position,
19640                anchor,
19641                line_offset_from_top,
19642            }) => {
19643                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19644                if let Some(buffer) = multi_buffer_snapshot
19645                    .buffer_id_for_excerpt(*excerpt_id)
19646                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19647                {
19648                    let buffer_snapshot = buffer.read(cx).snapshot();
19649                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19650                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19651                    } else {
19652                        buffer_snapshot.clip_point(*position, Bias::Left)
19653                    };
19654                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19655                    new_selections_by_buffer.insert(
19656                        buffer,
19657                        (
19658                            vec![jump_to_offset..jump_to_offset],
19659                            Some(*line_offset_from_top),
19660                        ),
19661                    );
19662                }
19663            }
19664            Some(JumpData::MultiBufferRow {
19665                row,
19666                line_offset_from_top,
19667            }) => {
19668                let point = MultiBufferPoint::new(row.0, 0);
19669                if let Some((buffer, buffer_point, _)) =
19670                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19671                {
19672                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19673                    new_selections_by_buffer
19674                        .entry(buffer)
19675                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19676                        .0
19677                        .push(buffer_offset..buffer_offset)
19678                }
19679            }
19680            None => {
19681                let selections = self.selections.all::<usize>(cx);
19682                let multi_buffer = self.buffer.read(cx);
19683                for selection in selections {
19684                    for (snapshot, range, _, anchor) in multi_buffer
19685                        .snapshot(cx)
19686                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19687                    {
19688                        if let Some(anchor) = anchor {
19689                            // selection is in a deleted hunk
19690                            let Some(buffer_id) = anchor.buffer_id else {
19691                                continue;
19692                            };
19693                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19694                                continue;
19695                            };
19696                            let offset = text::ToOffset::to_offset(
19697                                &anchor.text_anchor,
19698                                &buffer_handle.read(cx).snapshot(),
19699                            );
19700                            let range = offset..offset;
19701                            new_selections_by_buffer
19702                                .entry(buffer_handle)
19703                                .or_insert((Vec::new(), None))
19704                                .0
19705                                .push(range)
19706                        } else {
19707                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19708                            else {
19709                                continue;
19710                            };
19711                            new_selections_by_buffer
19712                                .entry(buffer_handle)
19713                                .or_insert((Vec::new(), None))
19714                                .0
19715                                .push(range)
19716                        }
19717                    }
19718                }
19719            }
19720        }
19721
19722        new_selections_by_buffer
19723            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19724
19725        if new_selections_by_buffer.is_empty() {
19726            return;
19727        }
19728
19729        // We defer the pane interaction because we ourselves are a workspace item
19730        // and activating a new item causes the pane to call a method on us reentrantly,
19731        // which panics if we're on the stack.
19732        window.defer(cx, move |window, cx| {
19733            workspace.update(cx, |workspace, cx| {
19734                let pane = if split {
19735                    workspace.adjacent_pane(window, cx)
19736                } else {
19737                    workspace.active_pane().clone()
19738                };
19739
19740                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19741                    let editor = buffer
19742                        .read(cx)
19743                        .file()
19744                        .is_none()
19745                        .then(|| {
19746                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19747                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19748                            // Instead, we try to activate the existing editor in the pane first.
19749                            let (editor, pane_item_index) =
19750                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19751                                    let editor = item.downcast::<Editor>()?;
19752                                    let singleton_buffer =
19753                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19754                                    if singleton_buffer == buffer {
19755                                        Some((editor, i))
19756                                    } else {
19757                                        None
19758                                    }
19759                                })?;
19760                            pane.update(cx, |pane, cx| {
19761                                pane.activate_item(pane_item_index, true, true, window, cx)
19762                            });
19763                            Some(editor)
19764                        })
19765                        .flatten()
19766                        .unwrap_or_else(|| {
19767                            workspace.open_project_item::<Self>(
19768                                pane.clone(),
19769                                buffer,
19770                                true,
19771                                true,
19772                                window,
19773                                cx,
19774                            )
19775                        });
19776
19777                    editor.update(cx, |editor, cx| {
19778                        let autoscroll = match scroll_offset {
19779                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19780                            None => Autoscroll::newest(),
19781                        };
19782                        let nav_history = editor.nav_history.take();
19783                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19784                            s.select_ranges(ranges);
19785                        });
19786                        editor.nav_history = nav_history;
19787                    });
19788                }
19789            })
19790        });
19791    }
19792
19793    // For now, don't allow opening excerpts in buffers that aren't backed by
19794    // regular project files.
19795    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19796        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19797    }
19798
19799    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19800        let snapshot = self.buffer.read(cx).read(cx);
19801        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19802        Some(
19803            ranges
19804                .iter()
19805                .map(move |range| {
19806                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19807                })
19808                .collect(),
19809        )
19810    }
19811
19812    fn selection_replacement_ranges(
19813        &self,
19814        range: Range<OffsetUtf16>,
19815        cx: &mut App,
19816    ) -> Vec<Range<OffsetUtf16>> {
19817        let selections = self.selections.all::<OffsetUtf16>(cx);
19818        let newest_selection = selections
19819            .iter()
19820            .max_by_key(|selection| selection.id)
19821            .unwrap();
19822        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19823        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19824        let snapshot = self.buffer.read(cx).read(cx);
19825        selections
19826            .into_iter()
19827            .map(|mut selection| {
19828                selection.start.0 =
19829                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19830                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19831                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19832                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19833            })
19834            .collect()
19835    }
19836
19837    fn report_editor_event(
19838        &self,
19839        event_type: &'static str,
19840        file_extension: Option<String>,
19841        cx: &App,
19842    ) {
19843        if cfg!(any(test, feature = "test-support")) {
19844            return;
19845        }
19846
19847        let Some(project) = &self.project else { return };
19848
19849        // If None, we are in a file without an extension
19850        let file = self
19851            .buffer
19852            .read(cx)
19853            .as_singleton()
19854            .and_then(|b| b.read(cx).file());
19855        let file_extension = file_extension.or(file
19856            .as_ref()
19857            .and_then(|file| Path::new(file.file_name(cx)).extension())
19858            .and_then(|e| e.to_str())
19859            .map(|a| a.to_string()));
19860
19861        let vim_mode = vim_enabled(cx);
19862
19863        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19864        let copilot_enabled = edit_predictions_provider
19865            == language::language_settings::EditPredictionProvider::Copilot;
19866        let copilot_enabled_for_language = self
19867            .buffer
19868            .read(cx)
19869            .language_settings(cx)
19870            .show_edit_predictions;
19871
19872        let project = project.read(cx);
19873        telemetry::event!(
19874            event_type,
19875            file_extension,
19876            vim_mode,
19877            copilot_enabled,
19878            copilot_enabled_for_language,
19879            edit_predictions_provider,
19880            is_via_ssh = project.is_via_ssh(),
19881        );
19882    }
19883
19884    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19885    /// with each line being an array of {text, highlight} objects.
19886    fn copy_highlight_json(
19887        &mut self,
19888        _: &CopyHighlightJson,
19889        window: &mut Window,
19890        cx: &mut Context<Self>,
19891    ) {
19892        #[derive(Serialize)]
19893        struct Chunk<'a> {
19894            text: String,
19895            highlight: Option<&'a str>,
19896        }
19897
19898        let snapshot = self.buffer.read(cx).snapshot(cx);
19899        let range = self
19900            .selected_text_range(false, window, cx)
19901            .and_then(|selection| {
19902                if selection.range.is_empty() {
19903                    None
19904                } else {
19905                    Some(selection.range)
19906                }
19907            })
19908            .unwrap_or_else(|| 0..snapshot.len());
19909
19910        let chunks = snapshot.chunks(range, true);
19911        let mut lines = Vec::new();
19912        let mut line: VecDeque<Chunk> = VecDeque::new();
19913
19914        let Some(style) = self.style.as_ref() else {
19915            return;
19916        };
19917
19918        for chunk in chunks {
19919            let highlight = chunk
19920                .syntax_highlight_id
19921                .and_then(|id| id.name(&style.syntax));
19922            let mut chunk_lines = chunk.text.split('\n').peekable();
19923            while let Some(text) = chunk_lines.next() {
19924                let mut merged_with_last_token = false;
19925                if let Some(last_token) = line.back_mut() {
19926                    if last_token.highlight == highlight {
19927                        last_token.text.push_str(text);
19928                        merged_with_last_token = true;
19929                    }
19930                }
19931
19932                if !merged_with_last_token {
19933                    line.push_back(Chunk {
19934                        text: text.into(),
19935                        highlight,
19936                    });
19937                }
19938
19939                if chunk_lines.peek().is_some() {
19940                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19941                        line.pop_front();
19942                    }
19943                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19944                        line.pop_back();
19945                    }
19946
19947                    lines.push(mem::take(&mut line));
19948                }
19949            }
19950        }
19951
19952        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19953            return;
19954        };
19955        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19956    }
19957
19958    pub fn open_context_menu(
19959        &mut self,
19960        _: &OpenContextMenu,
19961        window: &mut Window,
19962        cx: &mut Context<Self>,
19963    ) {
19964        self.request_autoscroll(Autoscroll::newest(), cx);
19965        let position = self.selections.newest_display(cx).start;
19966        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19967    }
19968
19969    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19970        &self.inlay_hint_cache
19971    }
19972
19973    pub fn replay_insert_event(
19974        &mut self,
19975        text: &str,
19976        relative_utf16_range: Option<Range<isize>>,
19977        window: &mut Window,
19978        cx: &mut Context<Self>,
19979    ) {
19980        if !self.input_enabled {
19981            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19982            return;
19983        }
19984        if let Some(relative_utf16_range) = relative_utf16_range {
19985            let selections = self.selections.all::<OffsetUtf16>(cx);
19986            self.change_selections(None, window, cx, |s| {
19987                let new_ranges = selections.into_iter().map(|range| {
19988                    let start = OffsetUtf16(
19989                        range
19990                            .head()
19991                            .0
19992                            .saturating_add_signed(relative_utf16_range.start),
19993                    );
19994                    let end = OffsetUtf16(
19995                        range
19996                            .head()
19997                            .0
19998                            .saturating_add_signed(relative_utf16_range.end),
19999                    );
20000                    start..end
20001                });
20002                s.select_ranges(new_ranges);
20003            });
20004        }
20005
20006        self.handle_input(text, window, cx);
20007    }
20008
20009    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20010        let Some(provider) = self.semantics_provider.as_ref() else {
20011            return false;
20012        };
20013
20014        let mut supports = false;
20015        self.buffer().update(cx, |this, cx| {
20016            this.for_each_buffer(|buffer| {
20017                supports |= provider.supports_inlay_hints(buffer, cx);
20018            });
20019        });
20020
20021        supports
20022    }
20023
20024    pub fn is_focused(&self, window: &Window) -> bool {
20025        self.focus_handle.is_focused(window)
20026    }
20027
20028    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20029        cx.emit(EditorEvent::Focused);
20030
20031        if let Some(descendant) = self
20032            .last_focused_descendant
20033            .take()
20034            .and_then(|descendant| descendant.upgrade())
20035        {
20036            window.focus(&descendant);
20037        } else {
20038            if let Some(blame) = self.blame.as_ref() {
20039                blame.update(cx, GitBlame::focus)
20040            }
20041
20042            self.blink_manager.update(cx, BlinkManager::enable);
20043            self.show_cursor_names(window, cx);
20044            self.buffer.update(cx, |buffer, cx| {
20045                buffer.finalize_last_transaction(cx);
20046                if self.leader_id.is_none() {
20047                    buffer.set_active_selections(
20048                        &self.selections.disjoint_anchors(),
20049                        self.selections.line_mode,
20050                        self.cursor_shape,
20051                        cx,
20052                    );
20053                }
20054            });
20055        }
20056    }
20057
20058    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20059        cx.emit(EditorEvent::FocusedIn)
20060    }
20061
20062    fn handle_focus_out(
20063        &mut self,
20064        event: FocusOutEvent,
20065        _window: &mut Window,
20066        cx: &mut Context<Self>,
20067    ) {
20068        if event.blurred != self.focus_handle {
20069            self.last_focused_descendant = Some(event.blurred);
20070        }
20071        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20072    }
20073
20074    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20075        self.blink_manager.update(cx, BlinkManager::disable);
20076        self.buffer
20077            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20078
20079        if let Some(blame) = self.blame.as_ref() {
20080            blame.update(cx, GitBlame::blur)
20081        }
20082        if !self.hover_state.focused(window, cx) {
20083            hide_hover(self, cx);
20084        }
20085        if !self
20086            .context_menu
20087            .borrow()
20088            .as_ref()
20089            .is_some_and(|context_menu| context_menu.focused(window, cx))
20090        {
20091            self.hide_context_menu(window, cx);
20092        }
20093        self.discard_inline_completion(false, cx);
20094        cx.emit(EditorEvent::Blurred);
20095        cx.notify();
20096    }
20097
20098    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20099        let mut pending: String = window
20100            .pending_input_keystrokes()
20101            .into_iter()
20102            .flatten()
20103            .filter_map(|keystroke| {
20104                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20105                    keystroke.key_char.clone()
20106                } else {
20107                    None
20108                }
20109            })
20110            .collect();
20111
20112        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20113            pending = "".to_string();
20114        }
20115
20116        let existing_pending = self
20117            .text_highlights::<PendingInput>(cx)
20118            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20119        if existing_pending.is_none() && pending.is_empty() {
20120            return;
20121        }
20122        let transaction =
20123            self.transact(window, cx, |this, window, cx| {
20124                let selections = this.selections.all::<usize>(cx);
20125                let edits = selections
20126                    .iter()
20127                    .map(|selection| (selection.end..selection.end, pending.clone()));
20128                this.edit(edits, cx);
20129                this.change_selections(None, window, cx, |s| {
20130                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20131                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20132                    }));
20133                });
20134                if let Some(existing_ranges) = existing_pending {
20135                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20136                    this.edit(edits, cx);
20137                }
20138            });
20139
20140        let snapshot = self.snapshot(window, cx);
20141        let ranges = self
20142            .selections
20143            .all::<usize>(cx)
20144            .into_iter()
20145            .map(|selection| {
20146                snapshot.buffer_snapshot.anchor_after(selection.end)
20147                    ..snapshot
20148                        .buffer_snapshot
20149                        .anchor_before(selection.end + pending.len())
20150            })
20151            .collect();
20152
20153        if pending.is_empty() {
20154            self.clear_highlights::<PendingInput>(cx);
20155        } else {
20156            self.highlight_text::<PendingInput>(
20157                ranges,
20158                HighlightStyle {
20159                    underline: Some(UnderlineStyle {
20160                        thickness: px(1.),
20161                        color: None,
20162                        wavy: false,
20163                    }),
20164                    ..Default::default()
20165                },
20166                cx,
20167            );
20168        }
20169
20170        self.ime_transaction = self.ime_transaction.or(transaction);
20171        if let Some(transaction) = self.ime_transaction {
20172            self.buffer.update(cx, |buffer, cx| {
20173                buffer.group_until_transaction(transaction, cx);
20174            });
20175        }
20176
20177        if self.text_highlights::<PendingInput>(cx).is_none() {
20178            self.ime_transaction.take();
20179        }
20180    }
20181
20182    pub fn register_action_renderer(
20183        &mut self,
20184        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20185    ) -> Subscription {
20186        let id = self.next_editor_action_id.post_inc();
20187        self.editor_actions
20188            .borrow_mut()
20189            .insert(id, Box::new(listener));
20190
20191        let editor_actions = self.editor_actions.clone();
20192        Subscription::new(move || {
20193            editor_actions.borrow_mut().remove(&id);
20194        })
20195    }
20196
20197    pub fn register_action<A: Action>(
20198        &mut self,
20199        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20200    ) -> Subscription {
20201        let id = self.next_editor_action_id.post_inc();
20202        let listener = Arc::new(listener);
20203        self.editor_actions.borrow_mut().insert(
20204            id,
20205            Box::new(move |_, window, _| {
20206                let listener = listener.clone();
20207                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20208                    let action = action.downcast_ref().unwrap();
20209                    if phase == DispatchPhase::Bubble {
20210                        listener(action, window, cx)
20211                    }
20212                })
20213            }),
20214        );
20215
20216        let editor_actions = self.editor_actions.clone();
20217        Subscription::new(move || {
20218            editor_actions.borrow_mut().remove(&id);
20219        })
20220    }
20221
20222    pub fn file_header_size(&self) -> u32 {
20223        FILE_HEADER_HEIGHT
20224    }
20225
20226    pub fn restore(
20227        &mut self,
20228        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20229        window: &mut Window,
20230        cx: &mut Context<Self>,
20231    ) {
20232        let workspace = self.workspace();
20233        let project = self.project.as_ref();
20234        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20235            let mut tasks = Vec::new();
20236            for (buffer_id, changes) in revert_changes {
20237                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20238                    buffer.update(cx, |buffer, cx| {
20239                        buffer.edit(
20240                            changes
20241                                .into_iter()
20242                                .map(|(range, text)| (range, text.to_string())),
20243                            None,
20244                            cx,
20245                        );
20246                    });
20247
20248                    if let Some(project) =
20249                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20250                    {
20251                        project.update(cx, |project, cx| {
20252                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20253                        })
20254                    }
20255                }
20256            }
20257            tasks
20258        });
20259        cx.spawn_in(window, async move |_, cx| {
20260            for (buffer, task) in save_tasks {
20261                let result = task.await;
20262                if result.is_err() {
20263                    let Some(path) = buffer
20264                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20265                        .ok()
20266                    else {
20267                        continue;
20268                    };
20269                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20270                        let Some(task) = cx
20271                            .update_window_entity(&workspace, |workspace, window, cx| {
20272                                workspace
20273                                    .open_path_preview(path, None, false, false, false, window, cx)
20274                            })
20275                            .ok()
20276                        else {
20277                            continue;
20278                        };
20279                        task.await.log_err();
20280                    }
20281                }
20282            }
20283        })
20284        .detach();
20285        self.change_selections(None, window, cx, |selections| selections.refresh());
20286    }
20287
20288    pub fn to_pixel_point(
20289        &self,
20290        source: multi_buffer::Anchor,
20291        editor_snapshot: &EditorSnapshot,
20292        window: &mut Window,
20293    ) -> Option<gpui::Point<Pixels>> {
20294        let source_point = source.to_display_point(editor_snapshot);
20295        self.display_to_pixel_point(source_point, editor_snapshot, window)
20296    }
20297
20298    pub fn display_to_pixel_point(
20299        &self,
20300        source: DisplayPoint,
20301        editor_snapshot: &EditorSnapshot,
20302        window: &mut Window,
20303    ) -> Option<gpui::Point<Pixels>> {
20304        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20305        let text_layout_details = self.text_layout_details(window);
20306        let scroll_top = text_layout_details
20307            .scroll_anchor
20308            .scroll_position(editor_snapshot)
20309            .y;
20310
20311        if source.row().as_f32() < scroll_top.floor() {
20312            return None;
20313        }
20314        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20315        let source_y = line_height * (source.row().as_f32() - scroll_top);
20316        Some(gpui::Point::new(source_x, source_y))
20317    }
20318
20319    pub fn has_visible_completions_menu(&self) -> bool {
20320        !self.edit_prediction_preview_is_active()
20321            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20322                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20323            })
20324    }
20325
20326    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20327        if self.mode.is_minimap() {
20328            return;
20329        }
20330        self.addons
20331            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20332    }
20333
20334    pub fn unregister_addon<T: Addon>(&mut self) {
20335        self.addons.remove(&std::any::TypeId::of::<T>());
20336    }
20337
20338    pub fn addon<T: Addon>(&self) -> Option<&T> {
20339        let type_id = std::any::TypeId::of::<T>();
20340        self.addons
20341            .get(&type_id)
20342            .and_then(|item| item.to_any().downcast_ref::<T>())
20343    }
20344
20345    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20346        let type_id = std::any::TypeId::of::<T>();
20347        self.addons
20348            .get_mut(&type_id)
20349            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20350    }
20351
20352    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20353        let text_layout_details = self.text_layout_details(window);
20354        let style = &text_layout_details.editor_style;
20355        let font_id = window.text_system().resolve_font(&style.text.font());
20356        let font_size = style.text.font_size.to_pixels(window.rem_size());
20357        let line_height = style.text.line_height_in_pixels(window.rem_size());
20358        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20359
20360        gpui::Size::new(em_width, line_height)
20361    }
20362
20363    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20364        self.load_diff_task.clone()
20365    }
20366
20367    fn read_metadata_from_db(
20368        &mut self,
20369        item_id: u64,
20370        workspace_id: WorkspaceId,
20371        window: &mut Window,
20372        cx: &mut Context<Editor>,
20373    ) {
20374        if self.is_singleton(cx)
20375            && !self.mode.is_minimap()
20376            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20377        {
20378            let buffer_snapshot = OnceCell::new();
20379
20380            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20381                if !folds.is_empty() {
20382                    let snapshot =
20383                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20384                    self.fold_ranges(
20385                        folds
20386                            .into_iter()
20387                            .map(|(start, end)| {
20388                                snapshot.clip_offset(start, Bias::Left)
20389                                    ..snapshot.clip_offset(end, Bias::Right)
20390                            })
20391                            .collect(),
20392                        false,
20393                        window,
20394                        cx,
20395                    );
20396                }
20397            }
20398
20399            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20400                if !selections.is_empty() {
20401                    let snapshot =
20402                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20403                    // skip adding the initial selection to selection history
20404                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20405                    self.change_selections(None, window, cx, |s| {
20406                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20407                            snapshot.clip_offset(start, Bias::Left)
20408                                ..snapshot.clip_offset(end, Bias::Right)
20409                        }));
20410                    });
20411                    self.selection_history.mode = SelectionHistoryMode::Normal;
20412                }
20413            };
20414        }
20415
20416        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20417    }
20418
20419    fn update_lsp_data(
20420        &mut self,
20421        for_server_id: Option<LanguageServerId>,
20422        for_buffer: Option<BufferId>,
20423        window: &mut Window,
20424        cx: &mut Context<'_, Self>,
20425    ) {
20426        self.pull_diagnostics(for_buffer, window, cx);
20427        self.refresh_colors(for_server_id, for_buffer, window, cx);
20428    }
20429}
20430
20431fn vim_enabled(cx: &App) -> bool {
20432    cx.global::<SettingsStore>()
20433        .raw_user_settings()
20434        .get("vim_mode")
20435        == Some(&serde_json::Value::Bool(true))
20436}
20437
20438fn process_completion_for_edit(
20439    completion: &Completion,
20440    intent: CompletionIntent,
20441    buffer: &Entity<Buffer>,
20442    cursor_position: &text::Anchor,
20443    cx: &mut Context<Editor>,
20444) -> CompletionEdit {
20445    let buffer = buffer.read(cx);
20446    let buffer_snapshot = buffer.snapshot();
20447    let (snippet, new_text) = if completion.is_snippet() {
20448        // Workaround for typescript language server issues so that methods don't expand within
20449        // strings and functions with type expressions. The previous point is used because the query
20450        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20451        let mut snippet_source = completion.new_text.clone();
20452        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20453        previous_point.column = previous_point.column.saturating_sub(1);
20454        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20455            if scope.prefers_label_for_snippet_in_completion() {
20456                if let Some(label) = completion.label() {
20457                    if matches!(
20458                        completion.kind(),
20459                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20460                    ) {
20461                        snippet_source = label;
20462                    }
20463                }
20464            }
20465        }
20466        match Snippet::parse(&snippet_source).log_err() {
20467            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20468            None => (None, completion.new_text.clone()),
20469        }
20470    } else {
20471        (None, completion.new_text.clone())
20472    };
20473
20474    let mut range_to_replace = {
20475        let replace_range = &completion.replace_range;
20476        if let CompletionSource::Lsp {
20477            insert_range: Some(insert_range),
20478            ..
20479        } = &completion.source
20480        {
20481            debug_assert_eq!(
20482                insert_range.start, replace_range.start,
20483                "insert_range and replace_range should start at the same position"
20484            );
20485            debug_assert!(
20486                insert_range
20487                    .start
20488                    .cmp(&cursor_position, &buffer_snapshot)
20489                    .is_le(),
20490                "insert_range should start before or at cursor position"
20491            );
20492            debug_assert!(
20493                replace_range
20494                    .start
20495                    .cmp(&cursor_position, &buffer_snapshot)
20496                    .is_le(),
20497                "replace_range should start before or at cursor position"
20498            );
20499            debug_assert!(
20500                insert_range
20501                    .end
20502                    .cmp(&cursor_position, &buffer_snapshot)
20503                    .is_le(),
20504                "insert_range should end before or at cursor position"
20505            );
20506
20507            let should_replace = match intent {
20508                CompletionIntent::CompleteWithInsert => false,
20509                CompletionIntent::CompleteWithReplace => true,
20510                CompletionIntent::Complete | CompletionIntent::Compose => {
20511                    let insert_mode =
20512                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20513                            .completions
20514                            .lsp_insert_mode;
20515                    match insert_mode {
20516                        LspInsertMode::Insert => false,
20517                        LspInsertMode::Replace => true,
20518                        LspInsertMode::ReplaceSubsequence => {
20519                            let mut text_to_replace = buffer.chars_for_range(
20520                                buffer.anchor_before(replace_range.start)
20521                                    ..buffer.anchor_after(replace_range.end),
20522                            );
20523                            let mut current_needle = text_to_replace.next();
20524                            for haystack_ch in completion.label.text.chars() {
20525                                if let Some(needle_ch) = current_needle {
20526                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20527                                        current_needle = text_to_replace.next();
20528                                    }
20529                                }
20530                            }
20531                            current_needle.is_none()
20532                        }
20533                        LspInsertMode::ReplaceSuffix => {
20534                            if replace_range
20535                                .end
20536                                .cmp(&cursor_position, &buffer_snapshot)
20537                                .is_gt()
20538                            {
20539                                let range_after_cursor = *cursor_position..replace_range.end;
20540                                let text_after_cursor = buffer
20541                                    .text_for_range(
20542                                        buffer.anchor_before(range_after_cursor.start)
20543                                            ..buffer.anchor_after(range_after_cursor.end),
20544                                    )
20545                                    .collect::<String>()
20546                                    .to_ascii_lowercase();
20547                                completion
20548                                    .label
20549                                    .text
20550                                    .to_ascii_lowercase()
20551                                    .ends_with(&text_after_cursor)
20552                            } else {
20553                                true
20554                            }
20555                        }
20556                    }
20557                }
20558            };
20559
20560            if should_replace {
20561                replace_range.clone()
20562            } else {
20563                insert_range.clone()
20564            }
20565        } else {
20566            replace_range.clone()
20567        }
20568    };
20569
20570    if range_to_replace
20571        .end
20572        .cmp(&cursor_position, &buffer_snapshot)
20573        .is_lt()
20574    {
20575        range_to_replace.end = *cursor_position;
20576    }
20577
20578    CompletionEdit {
20579        new_text,
20580        replace_range: range_to_replace.to_offset(&buffer),
20581        snippet,
20582    }
20583}
20584
20585struct CompletionEdit {
20586    new_text: String,
20587    replace_range: Range<usize>,
20588    snippet: Option<Snippet>,
20589}
20590
20591fn insert_extra_newline_brackets(
20592    buffer: &MultiBufferSnapshot,
20593    range: Range<usize>,
20594    language: &language::LanguageScope,
20595) -> bool {
20596    let leading_whitespace_len = buffer
20597        .reversed_chars_at(range.start)
20598        .take_while(|c| c.is_whitespace() && *c != '\n')
20599        .map(|c| c.len_utf8())
20600        .sum::<usize>();
20601    let trailing_whitespace_len = buffer
20602        .chars_at(range.end)
20603        .take_while(|c| c.is_whitespace() && *c != '\n')
20604        .map(|c| c.len_utf8())
20605        .sum::<usize>();
20606    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20607
20608    language.brackets().any(|(pair, enabled)| {
20609        let pair_start = pair.start.trim_end();
20610        let pair_end = pair.end.trim_start();
20611
20612        enabled
20613            && pair.newline
20614            && buffer.contains_str_at(range.end, pair_end)
20615            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20616    })
20617}
20618
20619fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20620    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20621        [(buffer, range, _)] => (*buffer, range.clone()),
20622        _ => return false,
20623    };
20624    let pair = {
20625        let mut result: Option<BracketMatch> = None;
20626
20627        for pair in buffer
20628            .all_bracket_ranges(range.clone())
20629            .filter(move |pair| {
20630                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20631            })
20632        {
20633            let len = pair.close_range.end - pair.open_range.start;
20634
20635            if let Some(existing) = &result {
20636                let existing_len = existing.close_range.end - existing.open_range.start;
20637                if len > existing_len {
20638                    continue;
20639                }
20640            }
20641
20642            result = Some(pair);
20643        }
20644
20645        result
20646    };
20647    let Some(pair) = pair else {
20648        return false;
20649    };
20650    pair.newline_only
20651        && buffer
20652            .chars_for_range(pair.open_range.end..range.start)
20653            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20654            .all(|c| c.is_whitespace() && c != '\n')
20655}
20656
20657fn update_uncommitted_diff_for_buffer(
20658    editor: Entity<Editor>,
20659    project: &Entity<Project>,
20660    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20661    buffer: Entity<MultiBuffer>,
20662    cx: &mut App,
20663) -> Task<()> {
20664    let mut tasks = Vec::new();
20665    project.update(cx, |project, cx| {
20666        for buffer in buffers {
20667            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20668                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20669            }
20670        }
20671    });
20672    cx.spawn(async move |cx| {
20673        let diffs = future::join_all(tasks).await;
20674        if editor
20675            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20676            .unwrap_or(false)
20677        {
20678            return;
20679        }
20680
20681        buffer
20682            .update(cx, |buffer, cx| {
20683                for diff in diffs.into_iter().flatten() {
20684                    buffer.add_diff(diff, cx);
20685                }
20686            })
20687            .ok();
20688    })
20689}
20690
20691fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20692    let tab_size = tab_size.get() as usize;
20693    let mut width = offset;
20694
20695    for ch in text.chars() {
20696        width += if ch == '\t' {
20697            tab_size - (width % tab_size)
20698        } else {
20699            1
20700        };
20701    }
20702
20703    width - offset
20704}
20705
20706#[cfg(test)]
20707mod tests {
20708    use super::*;
20709
20710    #[test]
20711    fn test_string_size_with_expanded_tabs() {
20712        let nz = |val| NonZeroU32::new(val).unwrap();
20713        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20714        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20715        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20716        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20717        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20718        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20719        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20720        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20721    }
20722}
20723
20724/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20725struct WordBreakingTokenizer<'a> {
20726    input: &'a str,
20727}
20728
20729impl<'a> WordBreakingTokenizer<'a> {
20730    fn new(input: &'a str) -> Self {
20731        Self { input }
20732    }
20733}
20734
20735fn is_char_ideographic(ch: char) -> bool {
20736    use unicode_script::Script::*;
20737    use unicode_script::UnicodeScript;
20738    matches!(ch.script(), Han | Tangut | Yi)
20739}
20740
20741fn is_grapheme_ideographic(text: &str) -> bool {
20742    text.chars().any(is_char_ideographic)
20743}
20744
20745fn is_grapheme_whitespace(text: &str) -> bool {
20746    text.chars().any(|x| x.is_whitespace())
20747}
20748
20749fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20750    text.chars().next().map_or(false, |ch| {
20751        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20752    })
20753}
20754
20755#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20756enum WordBreakToken<'a> {
20757    Word { token: &'a str, grapheme_len: usize },
20758    InlineWhitespace { token: &'a str, grapheme_len: usize },
20759    Newline,
20760}
20761
20762impl<'a> Iterator for WordBreakingTokenizer<'a> {
20763    /// Yields a span, the count of graphemes in the token, and whether it was
20764    /// whitespace. Note that it also breaks at word boundaries.
20765    type Item = WordBreakToken<'a>;
20766
20767    fn next(&mut self) -> Option<Self::Item> {
20768        use unicode_segmentation::UnicodeSegmentation;
20769        if self.input.is_empty() {
20770            return None;
20771        }
20772
20773        let mut iter = self.input.graphemes(true).peekable();
20774        let mut offset = 0;
20775        let mut grapheme_len = 0;
20776        if let Some(first_grapheme) = iter.next() {
20777            let is_newline = first_grapheme == "\n";
20778            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20779            offset += first_grapheme.len();
20780            grapheme_len += 1;
20781            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20782                if let Some(grapheme) = iter.peek().copied() {
20783                    if should_stay_with_preceding_ideograph(grapheme) {
20784                        offset += grapheme.len();
20785                        grapheme_len += 1;
20786                    }
20787                }
20788            } else {
20789                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20790                let mut next_word_bound = words.peek().copied();
20791                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20792                    next_word_bound = words.next();
20793                }
20794                while let Some(grapheme) = iter.peek().copied() {
20795                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20796                        break;
20797                    };
20798                    if is_grapheme_whitespace(grapheme) != is_whitespace
20799                        || (grapheme == "\n") != is_newline
20800                    {
20801                        break;
20802                    };
20803                    offset += grapheme.len();
20804                    grapheme_len += 1;
20805                    iter.next();
20806                }
20807            }
20808            let token = &self.input[..offset];
20809            self.input = &self.input[offset..];
20810            if token == "\n" {
20811                Some(WordBreakToken::Newline)
20812            } else if is_whitespace {
20813                Some(WordBreakToken::InlineWhitespace {
20814                    token,
20815                    grapheme_len,
20816                })
20817            } else {
20818                Some(WordBreakToken::Word {
20819                    token,
20820                    grapheme_len,
20821                })
20822            }
20823        } else {
20824            None
20825        }
20826    }
20827}
20828
20829#[test]
20830fn test_word_breaking_tokenizer() {
20831    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20832        ("", &[]),
20833        ("  ", &[whitespace("  ", 2)]),
20834        ("Ʒ", &[word("Ʒ", 1)]),
20835        ("Ǽ", &[word("Ǽ", 1)]),
20836        ("", &[word("", 1)]),
20837        ("⋑⋑", &[word("⋑⋑", 2)]),
20838        (
20839            "原理,进而",
20840            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20841        ),
20842        (
20843            "hello world",
20844            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20845        ),
20846        (
20847            "hello, world",
20848            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20849        ),
20850        (
20851            "  hello world",
20852            &[
20853                whitespace("  ", 2),
20854                word("hello", 5),
20855                whitespace(" ", 1),
20856                word("world", 5),
20857            ],
20858        ),
20859        (
20860            "这是什么 \n 钢笔",
20861            &[
20862                word("", 1),
20863                word("", 1),
20864                word("", 1),
20865                word("", 1),
20866                whitespace(" ", 1),
20867                newline(),
20868                whitespace(" ", 1),
20869                word("", 1),
20870                word("", 1),
20871            ],
20872        ),
20873        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20874    ];
20875
20876    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20877        WordBreakToken::Word {
20878            token,
20879            grapheme_len,
20880        }
20881    }
20882
20883    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20884        WordBreakToken::InlineWhitespace {
20885            token,
20886            grapheme_len,
20887        }
20888    }
20889
20890    fn newline() -> WordBreakToken<'static> {
20891        WordBreakToken::Newline
20892    }
20893
20894    for (input, result) in tests {
20895        assert_eq!(
20896            WordBreakingTokenizer::new(input)
20897                .collect::<Vec<_>>()
20898                .as_slice(),
20899            *result,
20900        );
20901    }
20902}
20903
20904fn wrap_with_prefix(
20905    line_prefix: String,
20906    unwrapped_text: String,
20907    wrap_column: usize,
20908    tab_size: NonZeroU32,
20909    preserve_existing_whitespace: bool,
20910) -> String {
20911    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20912    let mut wrapped_text = String::new();
20913    let mut current_line = line_prefix.clone();
20914
20915    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20916    let mut current_line_len = line_prefix_len;
20917    let mut in_whitespace = false;
20918    for token in tokenizer {
20919        let have_preceding_whitespace = in_whitespace;
20920        match token {
20921            WordBreakToken::Word {
20922                token,
20923                grapheme_len,
20924            } => {
20925                in_whitespace = false;
20926                if current_line_len + grapheme_len > wrap_column
20927                    && current_line_len != line_prefix_len
20928                {
20929                    wrapped_text.push_str(current_line.trim_end());
20930                    wrapped_text.push('\n');
20931                    current_line.truncate(line_prefix.len());
20932                    current_line_len = line_prefix_len;
20933                }
20934                current_line.push_str(token);
20935                current_line_len += grapheme_len;
20936            }
20937            WordBreakToken::InlineWhitespace {
20938                mut token,
20939                mut grapheme_len,
20940            } => {
20941                in_whitespace = true;
20942                if have_preceding_whitespace && !preserve_existing_whitespace {
20943                    continue;
20944                }
20945                if !preserve_existing_whitespace {
20946                    token = " ";
20947                    grapheme_len = 1;
20948                }
20949                if current_line_len + grapheme_len > wrap_column {
20950                    wrapped_text.push_str(current_line.trim_end());
20951                    wrapped_text.push('\n');
20952                    current_line.truncate(line_prefix.len());
20953                    current_line_len = line_prefix_len;
20954                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20955                    current_line.push_str(token);
20956                    current_line_len += grapheme_len;
20957                }
20958            }
20959            WordBreakToken::Newline => {
20960                in_whitespace = true;
20961                if preserve_existing_whitespace {
20962                    wrapped_text.push_str(current_line.trim_end());
20963                    wrapped_text.push('\n');
20964                    current_line.truncate(line_prefix.len());
20965                    current_line_len = line_prefix_len;
20966                } else if have_preceding_whitespace {
20967                    continue;
20968                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20969                {
20970                    wrapped_text.push_str(current_line.trim_end());
20971                    wrapped_text.push('\n');
20972                    current_line.truncate(line_prefix.len());
20973                    current_line_len = line_prefix_len;
20974                } else if current_line_len != line_prefix_len {
20975                    current_line.push(' ');
20976                    current_line_len += 1;
20977                }
20978            }
20979        }
20980    }
20981
20982    if !current_line.is_empty() {
20983        wrapped_text.push_str(&current_line);
20984    }
20985    wrapped_text
20986}
20987
20988#[test]
20989fn test_wrap_with_prefix() {
20990    assert_eq!(
20991        wrap_with_prefix(
20992            "# ".to_string(),
20993            "abcdefg".to_string(),
20994            4,
20995            NonZeroU32::new(4).unwrap(),
20996            false,
20997        ),
20998        "# abcdefg"
20999    );
21000    assert_eq!(
21001        wrap_with_prefix(
21002            "".to_string(),
21003            "\thello world".to_string(),
21004            8,
21005            NonZeroU32::new(4).unwrap(),
21006            false,
21007        ),
21008        "hello\nworld"
21009    );
21010    assert_eq!(
21011        wrap_with_prefix(
21012            "// ".to_string(),
21013            "xx \nyy zz aa bb cc".to_string(),
21014            12,
21015            NonZeroU32::new(4).unwrap(),
21016            false,
21017        ),
21018        "// xx yy zz\n// aa bb cc"
21019    );
21020    assert_eq!(
21021        wrap_with_prefix(
21022            String::new(),
21023            "这是什么 \n 钢笔".to_string(),
21024            3,
21025            NonZeroU32::new(4).unwrap(),
21026            false,
21027        ),
21028        "这是什\n么 钢\n"
21029    );
21030}
21031
21032pub trait CollaborationHub {
21033    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21034    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21035    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21036}
21037
21038impl CollaborationHub for Entity<Project> {
21039    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21040        self.read(cx).collaborators()
21041    }
21042
21043    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21044        self.read(cx).user_store().read(cx).participant_indices()
21045    }
21046
21047    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21048        let this = self.read(cx);
21049        let user_ids = this.collaborators().values().map(|c| c.user_id);
21050        this.user_store().read(cx).participant_names(user_ids, cx)
21051    }
21052}
21053
21054pub trait SemanticsProvider {
21055    fn hover(
21056        &self,
21057        buffer: &Entity<Buffer>,
21058        position: text::Anchor,
21059        cx: &mut App,
21060    ) -> Option<Task<Vec<project::Hover>>>;
21061
21062    fn inline_values(
21063        &self,
21064        buffer_handle: Entity<Buffer>,
21065        range: Range<text::Anchor>,
21066        cx: &mut App,
21067    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21068
21069    fn inlay_hints(
21070        &self,
21071        buffer_handle: Entity<Buffer>,
21072        range: Range<text::Anchor>,
21073        cx: &mut App,
21074    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21075
21076    fn resolve_inlay_hint(
21077        &self,
21078        hint: InlayHint,
21079        buffer_handle: Entity<Buffer>,
21080        server_id: LanguageServerId,
21081        cx: &mut App,
21082    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21083
21084    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21085
21086    fn document_highlights(
21087        &self,
21088        buffer: &Entity<Buffer>,
21089        position: text::Anchor,
21090        cx: &mut App,
21091    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21092
21093    fn definitions(
21094        &self,
21095        buffer: &Entity<Buffer>,
21096        position: text::Anchor,
21097        kind: GotoDefinitionKind,
21098        cx: &mut App,
21099    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21100
21101    fn range_for_rename(
21102        &self,
21103        buffer: &Entity<Buffer>,
21104        position: text::Anchor,
21105        cx: &mut App,
21106    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21107
21108    fn perform_rename(
21109        &self,
21110        buffer: &Entity<Buffer>,
21111        position: text::Anchor,
21112        new_name: String,
21113        cx: &mut App,
21114    ) -> Option<Task<Result<ProjectTransaction>>>;
21115}
21116
21117pub trait CompletionProvider {
21118    fn completions(
21119        &self,
21120        excerpt_id: ExcerptId,
21121        buffer: &Entity<Buffer>,
21122        buffer_position: text::Anchor,
21123        trigger: CompletionContext,
21124        window: &mut Window,
21125        cx: &mut Context<Editor>,
21126    ) -> Task<Result<Vec<CompletionResponse>>>;
21127
21128    fn resolve_completions(
21129        &self,
21130        _buffer: Entity<Buffer>,
21131        _completion_indices: Vec<usize>,
21132        _completions: Rc<RefCell<Box<[Completion]>>>,
21133        _cx: &mut Context<Editor>,
21134    ) -> Task<Result<bool>> {
21135        Task::ready(Ok(false))
21136    }
21137
21138    fn apply_additional_edits_for_completion(
21139        &self,
21140        _buffer: Entity<Buffer>,
21141        _completions: Rc<RefCell<Box<[Completion]>>>,
21142        _completion_index: usize,
21143        _push_to_history: bool,
21144        _cx: &mut Context<Editor>,
21145    ) -> Task<Result<Option<language::Transaction>>> {
21146        Task::ready(Ok(None))
21147    }
21148
21149    fn is_completion_trigger(
21150        &self,
21151        buffer: &Entity<Buffer>,
21152        position: language::Anchor,
21153        text: &str,
21154        trigger_in_words: bool,
21155        menu_is_open: bool,
21156        cx: &mut Context<Editor>,
21157    ) -> bool;
21158
21159    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21160
21161    fn sort_completions(&self) -> bool {
21162        true
21163    }
21164
21165    fn filter_completions(&self) -> bool {
21166        true
21167    }
21168}
21169
21170pub trait CodeActionProvider {
21171    fn id(&self) -> Arc<str>;
21172
21173    fn code_actions(
21174        &self,
21175        buffer: &Entity<Buffer>,
21176        range: Range<text::Anchor>,
21177        window: &mut Window,
21178        cx: &mut App,
21179    ) -> Task<Result<Vec<CodeAction>>>;
21180
21181    fn apply_code_action(
21182        &self,
21183        buffer_handle: Entity<Buffer>,
21184        action: CodeAction,
21185        excerpt_id: ExcerptId,
21186        push_to_history: bool,
21187        window: &mut Window,
21188        cx: &mut App,
21189    ) -> Task<Result<ProjectTransaction>>;
21190}
21191
21192impl CodeActionProvider for Entity<Project> {
21193    fn id(&self) -> Arc<str> {
21194        "project".into()
21195    }
21196
21197    fn code_actions(
21198        &self,
21199        buffer: &Entity<Buffer>,
21200        range: Range<text::Anchor>,
21201        _window: &mut Window,
21202        cx: &mut App,
21203    ) -> Task<Result<Vec<CodeAction>>> {
21204        self.update(cx, |project, cx| {
21205            let code_lens = project.code_lens(buffer, range.clone(), cx);
21206            let code_actions = project.code_actions(buffer, range, None, cx);
21207            cx.background_spawn(async move {
21208                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21209                Ok(code_lens
21210                    .context("code lens fetch")?
21211                    .into_iter()
21212                    .chain(code_actions.context("code action fetch")?)
21213                    .collect())
21214            })
21215        })
21216    }
21217
21218    fn apply_code_action(
21219        &self,
21220        buffer_handle: Entity<Buffer>,
21221        action: CodeAction,
21222        _excerpt_id: ExcerptId,
21223        push_to_history: bool,
21224        _window: &mut Window,
21225        cx: &mut App,
21226    ) -> Task<Result<ProjectTransaction>> {
21227        self.update(cx, |project, cx| {
21228            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21229        })
21230    }
21231}
21232
21233fn snippet_completions(
21234    project: &Project,
21235    buffer: &Entity<Buffer>,
21236    buffer_position: text::Anchor,
21237    cx: &mut App,
21238) -> Task<Result<CompletionResponse>> {
21239    let languages = buffer.read(cx).languages_at(buffer_position);
21240    let snippet_store = project.snippets().read(cx);
21241
21242    let scopes: Vec<_> = languages
21243        .iter()
21244        .filter_map(|language| {
21245            let language_name = language.lsp_id();
21246            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21247
21248            if snippets.is_empty() {
21249                None
21250            } else {
21251                Some((language.default_scope(), snippets))
21252            }
21253        })
21254        .collect();
21255
21256    if scopes.is_empty() {
21257        return Task::ready(Ok(CompletionResponse {
21258            completions: vec![],
21259            is_incomplete: false,
21260        }));
21261    }
21262
21263    let snapshot = buffer.read(cx).text_snapshot();
21264    let chars: String = snapshot
21265        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21266        .collect();
21267    let executor = cx.background_executor().clone();
21268
21269    cx.background_spawn(async move {
21270        let mut is_incomplete = false;
21271        let mut completions: Vec<Completion> = Vec::new();
21272        for (scope, snippets) in scopes.into_iter() {
21273            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21274            let mut last_word = chars
21275                .chars()
21276                .take_while(|c| classifier.is_word(*c))
21277                .collect::<String>();
21278            last_word = last_word.chars().rev().collect();
21279
21280            if last_word.is_empty() {
21281                return Ok(CompletionResponse {
21282                    completions: vec![],
21283                    is_incomplete: true,
21284                });
21285            }
21286
21287            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21288            let to_lsp = |point: &text::Anchor| {
21289                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21290                point_to_lsp(end)
21291            };
21292            let lsp_end = to_lsp(&buffer_position);
21293
21294            let candidates = snippets
21295                .iter()
21296                .enumerate()
21297                .flat_map(|(ix, snippet)| {
21298                    snippet
21299                        .prefix
21300                        .iter()
21301                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21302                })
21303                .collect::<Vec<StringMatchCandidate>>();
21304
21305            const MAX_RESULTS: usize = 100;
21306            let mut matches = fuzzy::match_strings(
21307                &candidates,
21308                &last_word,
21309                last_word.chars().any(|c| c.is_uppercase()),
21310                true,
21311                MAX_RESULTS,
21312                &Default::default(),
21313                executor.clone(),
21314            )
21315            .await;
21316
21317            if matches.len() >= MAX_RESULTS {
21318                is_incomplete = true;
21319            }
21320
21321            // Remove all candidates where the query's start does not match the start of any word in the candidate
21322            if let Some(query_start) = last_word.chars().next() {
21323                matches.retain(|string_match| {
21324                    split_words(&string_match.string).any(|word| {
21325                        // Check that the first codepoint of the word as lowercase matches the first
21326                        // codepoint of the query as lowercase
21327                        word.chars()
21328                            .flat_map(|codepoint| codepoint.to_lowercase())
21329                            .zip(query_start.to_lowercase())
21330                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21331                    })
21332                });
21333            }
21334
21335            let matched_strings = matches
21336                .into_iter()
21337                .map(|m| m.string)
21338                .collect::<HashSet<_>>();
21339
21340            completions.extend(snippets.iter().filter_map(|snippet| {
21341                let matching_prefix = snippet
21342                    .prefix
21343                    .iter()
21344                    .find(|prefix| matched_strings.contains(*prefix))?;
21345                let start = as_offset - last_word.len();
21346                let start = snapshot.anchor_before(start);
21347                let range = start..buffer_position;
21348                let lsp_start = to_lsp(&start);
21349                let lsp_range = lsp::Range {
21350                    start: lsp_start,
21351                    end: lsp_end,
21352                };
21353                Some(Completion {
21354                    replace_range: range,
21355                    new_text: snippet.body.clone(),
21356                    source: CompletionSource::Lsp {
21357                        insert_range: None,
21358                        server_id: LanguageServerId(usize::MAX),
21359                        resolved: true,
21360                        lsp_completion: Box::new(lsp::CompletionItem {
21361                            label: snippet.prefix.first().unwrap().clone(),
21362                            kind: Some(CompletionItemKind::SNIPPET),
21363                            label_details: snippet.description.as_ref().map(|description| {
21364                                lsp::CompletionItemLabelDetails {
21365                                    detail: Some(description.clone()),
21366                                    description: None,
21367                                }
21368                            }),
21369                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21370                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21371                                lsp::InsertReplaceEdit {
21372                                    new_text: snippet.body.clone(),
21373                                    insert: lsp_range,
21374                                    replace: lsp_range,
21375                                },
21376                            )),
21377                            filter_text: Some(snippet.body.clone()),
21378                            sort_text: Some(char::MAX.to_string()),
21379                            ..lsp::CompletionItem::default()
21380                        }),
21381                        lsp_defaults: None,
21382                    },
21383                    label: CodeLabel {
21384                        text: matching_prefix.clone(),
21385                        runs: Vec::new(),
21386                        filter_range: 0..matching_prefix.len(),
21387                    },
21388                    icon_path: None,
21389                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21390                        single_line: snippet.name.clone().into(),
21391                        plain_text: snippet
21392                            .description
21393                            .clone()
21394                            .map(|description| description.into()),
21395                    }),
21396                    insert_text_mode: None,
21397                    confirm: None,
21398                })
21399            }))
21400        }
21401
21402        Ok(CompletionResponse {
21403            completions,
21404            is_incomplete,
21405        })
21406    })
21407}
21408
21409impl CompletionProvider for Entity<Project> {
21410    fn completions(
21411        &self,
21412        _excerpt_id: ExcerptId,
21413        buffer: &Entity<Buffer>,
21414        buffer_position: text::Anchor,
21415        options: CompletionContext,
21416        _window: &mut Window,
21417        cx: &mut Context<Editor>,
21418    ) -> Task<Result<Vec<CompletionResponse>>> {
21419        self.update(cx, |project, cx| {
21420            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21421            let project_completions = project.completions(buffer, buffer_position, options, cx);
21422            cx.background_spawn(async move {
21423                let mut responses = project_completions.await?;
21424                let snippets = snippets.await?;
21425                if !snippets.completions.is_empty() {
21426                    responses.push(snippets);
21427                }
21428                Ok(responses)
21429            })
21430        })
21431    }
21432
21433    fn resolve_completions(
21434        &self,
21435        buffer: Entity<Buffer>,
21436        completion_indices: Vec<usize>,
21437        completions: Rc<RefCell<Box<[Completion]>>>,
21438        cx: &mut Context<Editor>,
21439    ) -> Task<Result<bool>> {
21440        self.update(cx, |project, cx| {
21441            project.lsp_store().update(cx, |lsp_store, cx| {
21442                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21443            })
21444        })
21445    }
21446
21447    fn apply_additional_edits_for_completion(
21448        &self,
21449        buffer: Entity<Buffer>,
21450        completions: Rc<RefCell<Box<[Completion]>>>,
21451        completion_index: usize,
21452        push_to_history: bool,
21453        cx: &mut Context<Editor>,
21454    ) -> Task<Result<Option<language::Transaction>>> {
21455        self.update(cx, |project, cx| {
21456            project.lsp_store().update(cx, |lsp_store, cx| {
21457                lsp_store.apply_additional_edits_for_completion(
21458                    buffer,
21459                    completions,
21460                    completion_index,
21461                    push_to_history,
21462                    cx,
21463                )
21464            })
21465        })
21466    }
21467
21468    fn is_completion_trigger(
21469        &self,
21470        buffer: &Entity<Buffer>,
21471        position: language::Anchor,
21472        text: &str,
21473        trigger_in_words: bool,
21474        menu_is_open: bool,
21475        cx: &mut Context<Editor>,
21476    ) -> bool {
21477        let mut chars = text.chars();
21478        let char = if let Some(char) = chars.next() {
21479            char
21480        } else {
21481            return false;
21482        };
21483        if chars.next().is_some() {
21484            return false;
21485        }
21486
21487        let buffer = buffer.read(cx);
21488        let snapshot = buffer.snapshot();
21489        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21490            return false;
21491        }
21492        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21493        if trigger_in_words && classifier.is_word(char) {
21494            return true;
21495        }
21496
21497        buffer.completion_triggers().contains(text)
21498    }
21499}
21500
21501impl SemanticsProvider for Entity<Project> {
21502    fn hover(
21503        &self,
21504        buffer: &Entity<Buffer>,
21505        position: text::Anchor,
21506        cx: &mut App,
21507    ) -> Option<Task<Vec<project::Hover>>> {
21508        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21509    }
21510
21511    fn document_highlights(
21512        &self,
21513        buffer: &Entity<Buffer>,
21514        position: text::Anchor,
21515        cx: &mut App,
21516    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21517        Some(self.update(cx, |project, cx| {
21518            project.document_highlights(buffer, position, cx)
21519        }))
21520    }
21521
21522    fn definitions(
21523        &self,
21524        buffer: &Entity<Buffer>,
21525        position: text::Anchor,
21526        kind: GotoDefinitionKind,
21527        cx: &mut App,
21528    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21529        Some(self.update(cx, |project, cx| match kind {
21530            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21531            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21532            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21533            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21534        }))
21535    }
21536
21537    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21538        // TODO: make this work for remote projects
21539        self.update(cx, |project, cx| {
21540            if project
21541                .active_debug_session(cx)
21542                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21543            {
21544                return true;
21545            }
21546
21547            buffer.update(cx, |buffer, cx| {
21548                project.any_language_server_supports_inlay_hints(buffer, cx)
21549            })
21550        })
21551    }
21552
21553    fn inline_values(
21554        &self,
21555        buffer_handle: Entity<Buffer>,
21556        range: Range<text::Anchor>,
21557        cx: &mut App,
21558    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21559        self.update(cx, |project, cx| {
21560            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21561
21562            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21563        })
21564    }
21565
21566    fn inlay_hints(
21567        &self,
21568        buffer_handle: Entity<Buffer>,
21569        range: Range<text::Anchor>,
21570        cx: &mut App,
21571    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21572        Some(self.update(cx, |project, cx| {
21573            project.inlay_hints(buffer_handle, range, cx)
21574        }))
21575    }
21576
21577    fn resolve_inlay_hint(
21578        &self,
21579        hint: InlayHint,
21580        buffer_handle: Entity<Buffer>,
21581        server_id: LanguageServerId,
21582        cx: &mut App,
21583    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21584        Some(self.update(cx, |project, cx| {
21585            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21586        }))
21587    }
21588
21589    fn range_for_rename(
21590        &self,
21591        buffer: &Entity<Buffer>,
21592        position: text::Anchor,
21593        cx: &mut App,
21594    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21595        Some(self.update(cx, |project, cx| {
21596            let buffer = buffer.clone();
21597            let task = project.prepare_rename(buffer.clone(), position, cx);
21598            cx.spawn(async move |_, cx| {
21599                Ok(match task.await? {
21600                    PrepareRenameResponse::Success(range) => Some(range),
21601                    PrepareRenameResponse::InvalidPosition => None,
21602                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21603                        // Fallback on using TreeSitter info to determine identifier range
21604                        buffer.read_with(cx, |buffer, _| {
21605                            let snapshot = buffer.snapshot();
21606                            let (range, kind) = snapshot.surrounding_word(position);
21607                            if kind != Some(CharKind::Word) {
21608                                return None;
21609                            }
21610                            Some(
21611                                snapshot.anchor_before(range.start)
21612                                    ..snapshot.anchor_after(range.end),
21613                            )
21614                        })?
21615                    }
21616                })
21617            })
21618        }))
21619    }
21620
21621    fn perform_rename(
21622        &self,
21623        buffer: &Entity<Buffer>,
21624        position: text::Anchor,
21625        new_name: String,
21626        cx: &mut App,
21627    ) -> Option<Task<Result<ProjectTransaction>>> {
21628        Some(self.update(cx, |project, cx| {
21629            project.perform_rename(buffer.clone(), position, new_name, cx)
21630        }))
21631    }
21632}
21633
21634fn inlay_hint_settings(
21635    location: Anchor,
21636    snapshot: &MultiBufferSnapshot,
21637    cx: &mut Context<Editor>,
21638) -> InlayHintSettings {
21639    let file = snapshot.file_at(location);
21640    let language = snapshot.language_at(location).map(|l| l.name());
21641    language_settings(language, file, cx).inlay_hints
21642}
21643
21644fn consume_contiguous_rows(
21645    contiguous_row_selections: &mut Vec<Selection<Point>>,
21646    selection: &Selection<Point>,
21647    display_map: &DisplaySnapshot,
21648    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21649) -> (MultiBufferRow, MultiBufferRow) {
21650    contiguous_row_selections.push(selection.clone());
21651    let start_row = MultiBufferRow(selection.start.row);
21652    let mut end_row = ending_row(selection, display_map);
21653
21654    while let Some(next_selection) = selections.peek() {
21655        if next_selection.start.row <= end_row.0 {
21656            end_row = ending_row(next_selection, display_map);
21657            contiguous_row_selections.push(selections.next().unwrap().clone());
21658        } else {
21659            break;
21660        }
21661    }
21662    (start_row, end_row)
21663}
21664
21665fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21666    if next_selection.end.column > 0 || next_selection.is_empty() {
21667        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21668    } else {
21669        MultiBufferRow(next_selection.end.row)
21670    }
21671}
21672
21673impl EditorSnapshot {
21674    pub fn remote_selections_in_range<'a>(
21675        &'a self,
21676        range: &'a Range<Anchor>,
21677        collaboration_hub: &dyn CollaborationHub,
21678        cx: &'a App,
21679    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21680        let participant_names = collaboration_hub.user_names(cx);
21681        let participant_indices = collaboration_hub.user_participant_indices(cx);
21682        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21683        let collaborators_by_replica_id = collaborators_by_peer_id
21684            .values()
21685            .map(|collaborator| (collaborator.replica_id, collaborator))
21686            .collect::<HashMap<_, _>>();
21687        self.buffer_snapshot
21688            .selections_in_range(range, false)
21689            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21690                if replica_id == AGENT_REPLICA_ID {
21691                    Some(RemoteSelection {
21692                        replica_id,
21693                        selection,
21694                        cursor_shape,
21695                        line_mode,
21696                        collaborator_id: CollaboratorId::Agent,
21697                        user_name: Some("Agent".into()),
21698                        color: cx.theme().players().agent(),
21699                    })
21700                } else {
21701                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21702                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21703                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21704                    Some(RemoteSelection {
21705                        replica_id,
21706                        selection,
21707                        cursor_shape,
21708                        line_mode,
21709                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21710                        user_name,
21711                        color: if let Some(index) = participant_index {
21712                            cx.theme().players().color_for_participant(index.0)
21713                        } else {
21714                            cx.theme().players().absent()
21715                        },
21716                    })
21717                }
21718            })
21719    }
21720
21721    pub fn hunks_for_ranges(
21722        &self,
21723        ranges: impl IntoIterator<Item = Range<Point>>,
21724    ) -> Vec<MultiBufferDiffHunk> {
21725        let mut hunks = Vec::new();
21726        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21727            HashMap::default();
21728        for query_range in ranges {
21729            let query_rows =
21730                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21731            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21732                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21733            ) {
21734                // Include deleted hunks that are adjacent to the query range, because
21735                // otherwise they would be missed.
21736                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21737                if hunk.status().is_deleted() {
21738                    intersects_range |= hunk.row_range.start == query_rows.end;
21739                    intersects_range |= hunk.row_range.end == query_rows.start;
21740                }
21741                if intersects_range {
21742                    if !processed_buffer_rows
21743                        .entry(hunk.buffer_id)
21744                        .or_default()
21745                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21746                    {
21747                        continue;
21748                    }
21749                    hunks.push(hunk);
21750                }
21751            }
21752        }
21753
21754        hunks
21755    }
21756
21757    fn display_diff_hunks_for_rows<'a>(
21758        &'a self,
21759        display_rows: Range<DisplayRow>,
21760        folded_buffers: &'a HashSet<BufferId>,
21761    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21762        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21763        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21764
21765        self.buffer_snapshot
21766            .diff_hunks_in_range(buffer_start..buffer_end)
21767            .filter_map(|hunk| {
21768                if folded_buffers.contains(&hunk.buffer_id) {
21769                    return None;
21770                }
21771
21772                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21773                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21774
21775                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21776                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21777
21778                let display_hunk = if hunk_display_start.column() != 0 {
21779                    DisplayDiffHunk::Folded {
21780                        display_row: hunk_display_start.row(),
21781                    }
21782                } else {
21783                    let mut end_row = hunk_display_end.row();
21784                    if hunk_display_end.column() > 0 {
21785                        end_row.0 += 1;
21786                    }
21787                    let is_created_file = hunk.is_created_file();
21788                    DisplayDiffHunk::Unfolded {
21789                        status: hunk.status(),
21790                        diff_base_byte_range: hunk.diff_base_byte_range,
21791                        display_row_range: hunk_display_start.row()..end_row,
21792                        multi_buffer_range: Anchor::range_in_buffer(
21793                            hunk.excerpt_id,
21794                            hunk.buffer_id,
21795                            hunk.buffer_range,
21796                        ),
21797                        is_created_file,
21798                    }
21799                };
21800
21801                Some(display_hunk)
21802            })
21803    }
21804
21805    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21806        self.display_snapshot.buffer_snapshot.language_at(position)
21807    }
21808
21809    pub fn is_focused(&self) -> bool {
21810        self.is_focused
21811    }
21812
21813    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21814        self.placeholder_text.as_ref()
21815    }
21816
21817    pub fn scroll_position(&self) -> gpui::Point<f32> {
21818        self.scroll_anchor.scroll_position(&self.display_snapshot)
21819    }
21820
21821    fn gutter_dimensions(
21822        &self,
21823        font_id: FontId,
21824        font_size: Pixels,
21825        max_line_number_width: Pixels,
21826        cx: &App,
21827    ) -> Option<GutterDimensions> {
21828        if !self.show_gutter {
21829            return None;
21830        }
21831
21832        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21833        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21834
21835        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21836            matches!(
21837                ProjectSettings::get_global(cx).git.git_gutter,
21838                Some(GitGutterSetting::TrackedFiles)
21839            )
21840        });
21841        let gutter_settings = EditorSettings::get_global(cx).gutter;
21842        let show_line_numbers = self
21843            .show_line_numbers
21844            .unwrap_or(gutter_settings.line_numbers);
21845        let line_gutter_width = if show_line_numbers {
21846            // Avoid flicker-like gutter resizes when the line number gains another digit by
21847            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21848            let min_width_for_number_on_gutter =
21849                ch_advance * gutter_settings.min_line_number_digits as f32;
21850            max_line_number_width.max(min_width_for_number_on_gutter)
21851        } else {
21852            0.0.into()
21853        };
21854
21855        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21856        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21857
21858        let git_blame_entries_width =
21859            self.git_blame_gutter_max_author_length
21860                .map(|max_author_length| {
21861                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21862                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21863
21864                    /// The number of characters to dedicate to gaps and margins.
21865                    const SPACING_WIDTH: usize = 4;
21866
21867                    let max_char_count = max_author_length.min(renderer.max_author_length())
21868                        + ::git::SHORT_SHA_LENGTH
21869                        + MAX_RELATIVE_TIMESTAMP.len()
21870                        + SPACING_WIDTH;
21871
21872                    ch_advance * max_char_count
21873                });
21874
21875        let is_singleton = self.buffer_snapshot.is_singleton();
21876
21877        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21878        left_padding += if !is_singleton {
21879            ch_width * 4.0
21880        } else if show_runnables || show_breakpoints {
21881            ch_width * 3.0
21882        } else if show_git_gutter && show_line_numbers {
21883            ch_width * 2.0
21884        } else if show_git_gutter || show_line_numbers {
21885            ch_width
21886        } else {
21887            px(0.)
21888        };
21889
21890        let shows_folds = is_singleton && gutter_settings.folds;
21891
21892        let right_padding = if shows_folds && show_line_numbers {
21893            ch_width * 4.0
21894        } else if shows_folds || (!is_singleton && show_line_numbers) {
21895            ch_width * 3.0
21896        } else if show_line_numbers {
21897            ch_width
21898        } else {
21899            px(0.)
21900        };
21901
21902        Some(GutterDimensions {
21903            left_padding,
21904            right_padding,
21905            width: line_gutter_width + left_padding + right_padding,
21906            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21907            git_blame_entries_width,
21908        })
21909    }
21910
21911    pub fn render_crease_toggle(
21912        &self,
21913        buffer_row: MultiBufferRow,
21914        row_contains_cursor: bool,
21915        editor: Entity<Editor>,
21916        window: &mut Window,
21917        cx: &mut App,
21918    ) -> Option<AnyElement> {
21919        let folded = self.is_line_folded(buffer_row);
21920        let mut is_foldable = false;
21921
21922        if let Some(crease) = self
21923            .crease_snapshot
21924            .query_row(buffer_row, &self.buffer_snapshot)
21925        {
21926            is_foldable = true;
21927            match crease {
21928                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21929                    if let Some(render_toggle) = render_toggle {
21930                        let toggle_callback =
21931                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21932                                if folded {
21933                                    editor.update(cx, |editor, cx| {
21934                                        editor.fold_at(buffer_row, window, cx)
21935                                    });
21936                                } else {
21937                                    editor.update(cx, |editor, cx| {
21938                                        editor.unfold_at(buffer_row, window, cx)
21939                                    });
21940                                }
21941                            });
21942                        return Some((render_toggle)(
21943                            buffer_row,
21944                            folded,
21945                            toggle_callback,
21946                            window,
21947                            cx,
21948                        ));
21949                    }
21950                }
21951            }
21952        }
21953
21954        is_foldable |= self.starts_indent(buffer_row);
21955
21956        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21957            Some(
21958                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21959                    .toggle_state(folded)
21960                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21961                        if folded {
21962                            this.unfold_at(buffer_row, window, cx);
21963                        } else {
21964                            this.fold_at(buffer_row, window, cx);
21965                        }
21966                    }))
21967                    .into_any_element(),
21968            )
21969        } else {
21970            None
21971        }
21972    }
21973
21974    pub fn render_crease_trailer(
21975        &self,
21976        buffer_row: MultiBufferRow,
21977        window: &mut Window,
21978        cx: &mut App,
21979    ) -> Option<AnyElement> {
21980        let folded = self.is_line_folded(buffer_row);
21981        if let Crease::Inline { render_trailer, .. } = self
21982            .crease_snapshot
21983            .query_row(buffer_row, &self.buffer_snapshot)?
21984        {
21985            let render_trailer = render_trailer.as_ref()?;
21986            Some(render_trailer(buffer_row, folded, window, cx))
21987        } else {
21988            None
21989        }
21990    }
21991}
21992
21993impl Deref for EditorSnapshot {
21994    type Target = DisplaySnapshot;
21995
21996    fn deref(&self) -> &Self::Target {
21997        &self.display_snapshot
21998    }
21999}
22000
22001#[derive(Clone, Debug, PartialEq, Eq)]
22002pub enum EditorEvent {
22003    InputIgnored {
22004        text: Arc<str>,
22005    },
22006    InputHandled {
22007        utf16_range_to_replace: Option<Range<isize>>,
22008        text: Arc<str>,
22009    },
22010    ExcerptsAdded {
22011        buffer: Entity<Buffer>,
22012        predecessor: ExcerptId,
22013        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22014    },
22015    ExcerptsRemoved {
22016        ids: Vec<ExcerptId>,
22017        removed_buffer_ids: Vec<BufferId>,
22018    },
22019    BufferFoldToggled {
22020        ids: Vec<ExcerptId>,
22021        folded: bool,
22022    },
22023    ExcerptsEdited {
22024        ids: Vec<ExcerptId>,
22025    },
22026    ExcerptsExpanded {
22027        ids: Vec<ExcerptId>,
22028    },
22029    BufferEdited,
22030    Edited {
22031        transaction_id: clock::Lamport,
22032    },
22033    Reparsed(BufferId),
22034    Focused,
22035    FocusedIn,
22036    Blurred,
22037    DirtyChanged,
22038    Saved,
22039    TitleChanged,
22040    DiffBaseChanged,
22041    SelectionsChanged {
22042        local: bool,
22043    },
22044    ScrollPositionChanged {
22045        local: bool,
22046        autoscroll: bool,
22047    },
22048    Closed,
22049    TransactionUndone {
22050        transaction_id: clock::Lamport,
22051    },
22052    TransactionBegun {
22053        transaction_id: clock::Lamport,
22054    },
22055    Reloaded,
22056    CursorShapeChanged,
22057    PushedToNavHistory {
22058        anchor: Anchor,
22059        is_deactivate: bool,
22060    },
22061}
22062
22063impl EventEmitter<EditorEvent> for Editor {}
22064
22065impl Focusable for Editor {
22066    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22067        self.focus_handle.clone()
22068    }
22069}
22070
22071impl Render for Editor {
22072    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22073        let settings = ThemeSettings::get_global(cx);
22074
22075        let mut text_style = match self.mode {
22076            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22077                color: cx.theme().colors().editor_foreground,
22078                font_family: settings.ui_font.family.clone(),
22079                font_features: settings.ui_font.features.clone(),
22080                font_fallbacks: settings.ui_font.fallbacks.clone(),
22081                font_size: rems(0.875).into(),
22082                font_weight: settings.ui_font.weight,
22083                line_height: relative(settings.buffer_line_height.value()),
22084                ..Default::default()
22085            },
22086            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22087                color: cx.theme().colors().editor_foreground,
22088                font_family: settings.buffer_font.family.clone(),
22089                font_features: settings.buffer_font.features.clone(),
22090                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22091                font_size: settings.buffer_font_size(cx).into(),
22092                font_weight: settings.buffer_font.weight,
22093                line_height: relative(settings.buffer_line_height.value()),
22094                ..Default::default()
22095            },
22096        };
22097        if let Some(text_style_refinement) = &self.text_style_refinement {
22098            text_style.refine(text_style_refinement)
22099        }
22100
22101        let background = match self.mode {
22102            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22103            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22104            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22105            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22106        };
22107
22108        EditorElement::new(
22109            &cx.entity(),
22110            EditorStyle {
22111                background,
22112                local_player: cx.theme().players().local(),
22113                text: text_style,
22114                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22115                syntax: cx.theme().syntax().clone(),
22116                status: cx.theme().status().clone(),
22117                inlay_hints_style: make_inlay_hints_style(cx),
22118                inline_completion_styles: make_suggestion_styles(cx),
22119                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22120                show_underlines: self.diagnostics_enabled(),
22121            },
22122        )
22123    }
22124}
22125
22126impl EntityInputHandler for Editor {
22127    fn text_for_range(
22128        &mut self,
22129        range_utf16: Range<usize>,
22130        adjusted_range: &mut Option<Range<usize>>,
22131        _: &mut Window,
22132        cx: &mut Context<Self>,
22133    ) -> Option<String> {
22134        let snapshot = self.buffer.read(cx).read(cx);
22135        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22136        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22137        if (start.0..end.0) != range_utf16 {
22138            adjusted_range.replace(start.0..end.0);
22139        }
22140        Some(snapshot.text_for_range(start..end).collect())
22141    }
22142
22143    fn selected_text_range(
22144        &mut self,
22145        ignore_disabled_input: bool,
22146        _: &mut Window,
22147        cx: &mut Context<Self>,
22148    ) -> Option<UTF16Selection> {
22149        // Prevent the IME menu from appearing when holding down an alphabetic key
22150        // while input is disabled.
22151        if !ignore_disabled_input && !self.input_enabled {
22152            return None;
22153        }
22154
22155        let selection = self.selections.newest::<OffsetUtf16>(cx);
22156        let range = selection.range();
22157
22158        Some(UTF16Selection {
22159            range: range.start.0..range.end.0,
22160            reversed: selection.reversed,
22161        })
22162    }
22163
22164    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22165        let snapshot = self.buffer.read(cx).read(cx);
22166        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22167        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22168    }
22169
22170    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22171        self.clear_highlights::<InputComposition>(cx);
22172        self.ime_transaction.take();
22173    }
22174
22175    fn replace_text_in_range(
22176        &mut self,
22177        range_utf16: Option<Range<usize>>,
22178        text: &str,
22179        window: &mut Window,
22180        cx: &mut Context<Self>,
22181    ) {
22182        if !self.input_enabled {
22183            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22184            return;
22185        }
22186
22187        self.transact(window, cx, |this, window, cx| {
22188            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22189                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22190                Some(this.selection_replacement_ranges(range_utf16, cx))
22191            } else {
22192                this.marked_text_ranges(cx)
22193            };
22194
22195            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22196                let newest_selection_id = this.selections.newest_anchor().id;
22197                this.selections
22198                    .all::<OffsetUtf16>(cx)
22199                    .iter()
22200                    .zip(ranges_to_replace.iter())
22201                    .find_map(|(selection, range)| {
22202                        if selection.id == newest_selection_id {
22203                            Some(
22204                                (range.start.0 as isize - selection.head().0 as isize)
22205                                    ..(range.end.0 as isize - selection.head().0 as isize),
22206                            )
22207                        } else {
22208                            None
22209                        }
22210                    })
22211            });
22212
22213            cx.emit(EditorEvent::InputHandled {
22214                utf16_range_to_replace: range_to_replace,
22215                text: text.into(),
22216            });
22217
22218            if let Some(new_selected_ranges) = new_selected_ranges {
22219                this.change_selections(None, window, cx, |selections| {
22220                    selections.select_ranges(new_selected_ranges)
22221                });
22222                this.backspace(&Default::default(), window, cx);
22223            }
22224
22225            this.handle_input(text, window, cx);
22226        });
22227
22228        if let Some(transaction) = self.ime_transaction {
22229            self.buffer.update(cx, |buffer, cx| {
22230                buffer.group_until_transaction(transaction, cx);
22231            });
22232        }
22233
22234        self.unmark_text(window, cx);
22235    }
22236
22237    fn replace_and_mark_text_in_range(
22238        &mut self,
22239        range_utf16: Option<Range<usize>>,
22240        text: &str,
22241        new_selected_range_utf16: Option<Range<usize>>,
22242        window: &mut Window,
22243        cx: &mut Context<Self>,
22244    ) {
22245        if !self.input_enabled {
22246            return;
22247        }
22248
22249        let transaction = self.transact(window, cx, |this, window, cx| {
22250            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22251                let snapshot = this.buffer.read(cx).read(cx);
22252                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22253                    for marked_range in &mut marked_ranges {
22254                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22255                        marked_range.start.0 += relative_range_utf16.start;
22256                        marked_range.start =
22257                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22258                        marked_range.end =
22259                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22260                    }
22261                }
22262                Some(marked_ranges)
22263            } else if let Some(range_utf16) = range_utf16 {
22264                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22265                Some(this.selection_replacement_ranges(range_utf16, cx))
22266            } else {
22267                None
22268            };
22269
22270            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22271                let newest_selection_id = this.selections.newest_anchor().id;
22272                this.selections
22273                    .all::<OffsetUtf16>(cx)
22274                    .iter()
22275                    .zip(ranges_to_replace.iter())
22276                    .find_map(|(selection, range)| {
22277                        if selection.id == newest_selection_id {
22278                            Some(
22279                                (range.start.0 as isize - selection.head().0 as isize)
22280                                    ..(range.end.0 as isize - selection.head().0 as isize),
22281                            )
22282                        } else {
22283                            None
22284                        }
22285                    })
22286            });
22287
22288            cx.emit(EditorEvent::InputHandled {
22289                utf16_range_to_replace: range_to_replace,
22290                text: text.into(),
22291            });
22292
22293            if let Some(ranges) = ranges_to_replace {
22294                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22295            }
22296
22297            let marked_ranges = {
22298                let snapshot = this.buffer.read(cx).read(cx);
22299                this.selections
22300                    .disjoint_anchors()
22301                    .iter()
22302                    .map(|selection| {
22303                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22304                    })
22305                    .collect::<Vec<_>>()
22306            };
22307
22308            if text.is_empty() {
22309                this.unmark_text(window, cx);
22310            } else {
22311                this.highlight_text::<InputComposition>(
22312                    marked_ranges.clone(),
22313                    HighlightStyle {
22314                        underline: Some(UnderlineStyle {
22315                            thickness: px(1.),
22316                            color: None,
22317                            wavy: false,
22318                        }),
22319                        ..Default::default()
22320                    },
22321                    cx,
22322                );
22323            }
22324
22325            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22326            let use_autoclose = this.use_autoclose;
22327            let use_auto_surround = this.use_auto_surround;
22328            this.set_use_autoclose(false);
22329            this.set_use_auto_surround(false);
22330            this.handle_input(text, window, cx);
22331            this.set_use_autoclose(use_autoclose);
22332            this.set_use_auto_surround(use_auto_surround);
22333
22334            if let Some(new_selected_range) = new_selected_range_utf16 {
22335                let snapshot = this.buffer.read(cx).read(cx);
22336                let new_selected_ranges = marked_ranges
22337                    .into_iter()
22338                    .map(|marked_range| {
22339                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22340                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22341                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22342                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22343                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22344                    })
22345                    .collect::<Vec<_>>();
22346
22347                drop(snapshot);
22348                this.change_selections(None, window, cx, |selections| {
22349                    selections.select_ranges(new_selected_ranges)
22350                });
22351            }
22352        });
22353
22354        self.ime_transaction = self.ime_transaction.or(transaction);
22355        if let Some(transaction) = self.ime_transaction {
22356            self.buffer.update(cx, |buffer, cx| {
22357                buffer.group_until_transaction(transaction, cx);
22358            });
22359        }
22360
22361        if self.text_highlights::<InputComposition>(cx).is_none() {
22362            self.ime_transaction.take();
22363        }
22364    }
22365
22366    fn bounds_for_range(
22367        &mut self,
22368        range_utf16: Range<usize>,
22369        element_bounds: gpui::Bounds<Pixels>,
22370        window: &mut Window,
22371        cx: &mut Context<Self>,
22372    ) -> Option<gpui::Bounds<Pixels>> {
22373        let text_layout_details = self.text_layout_details(window);
22374        let gpui::Size {
22375            width: em_width,
22376            height: line_height,
22377        } = self.character_size(window);
22378
22379        let snapshot = self.snapshot(window, cx);
22380        let scroll_position = snapshot.scroll_position();
22381        let scroll_left = scroll_position.x * em_width;
22382
22383        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22384        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22385            + self.gutter_dimensions.width
22386            + self.gutter_dimensions.margin;
22387        let y = line_height * (start.row().as_f32() - scroll_position.y);
22388
22389        Some(Bounds {
22390            origin: element_bounds.origin + point(x, y),
22391            size: size(em_width, line_height),
22392        })
22393    }
22394
22395    fn character_index_for_point(
22396        &mut self,
22397        point: gpui::Point<Pixels>,
22398        _window: &mut Window,
22399        _cx: &mut Context<Self>,
22400    ) -> Option<usize> {
22401        let position_map = self.last_position_map.as_ref()?;
22402        if !position_map.text_hitbox.contains(&point) {
22403            return None;
22404        }
22405        let display_point = position_map.point_for_position(point).previous_valid;
22406        let anchor = position_map
22407            .snapshot
22408            .display_point_to_anchor(display_point, Bias::Left);
22409        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22410        Some(utf16_offset.0)
22411    }
22412}
22413
22414trait SelectionExt {
22415    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22416    fn spanned_rows(
22417        &self,
22418        include_end_if_at_line_start: bool,
22419        map: &DisplaySnapshot,
22420    ) -> Range<MultiBufferRow>;
22421}
22422
22423impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22424    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22425        let start = self
22426            .start
22427            .to_point(&map.buffer_snapshot)
22428            .to_display_point(map);
22429        let end = self
22430            .end
22431            .to_point(&map.buffer_snapshot)
22432            .to_display_point(map);
22433        if self.reversed {
22434            end..start
22435        } else {
22436            start..end
22437        }
22438    }
22439
22440    fn spanned_rows(
22441        &self,
22442        include_end_if_at_line_start: bool,
22443        map: &DisplaySnapshot,
22444    ) -> Range<MultiBufferRow> {
22445        let start = self.start.to_point(&map.buffer_snapshot);
22446        let mut end = self.end.to_point(&map.buffer_snapshot);
22447        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22448            end.row -= 1;
22449        }
22450
22451        let buffer_start = map.prev_line_boundary(start).0;
22452        let buffer_end = map.next_line_boundary(end).0;
22453        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22454    }
22455}
22456
22457impl<T: InvalidationRegion> InvalidationStack<T> {
22458    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22459    where
22460        S: Clone + ToOffset,
22461    {
22462        while let Some(region) = self.last() {
22463            let all_selections_inside_invalidation_ranges =
22464                if selections.len() == region.ranges().len() {
22465                    selections
22466                        .iter()
22467                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22468                        .all(|(selection, invalidation_range)| {
22469                            let head = selection.head().to_offset(buffer);
22470                            invalidation_range.start <= head && invalidation_range.end >= head
22471                        })
22472                } else {
22473                    false
22474                };
22475
22476            if all_selections_inside_invalidation_ranges {
22477                break;
22478            } else {
22479                self.pop();
22480            }
22481        }
22482    }
22483}
22484
22485impl<T> Default for InvalidationStack<T> {
22486    fn default() -> Self {
22487        Self(Default::default())
22488    }
22489}
22490
22491impl<T> Deref for InvalidationStack<T> {
22492    type Target = Vec<T>;
22493
22494    fn deref(&self) -> &Self::Target {
22495        &self.0
22496    }
22497}
22498
22499impl<T> DerefMut for InvalidationStack<T> {
22500    fn deref_mut(&mut self) -> &mut Self::Target {
22501        &mut self.0
22502    }
22503}
22504
22505impl InvalidationRegion for SnippetState {
22506    fn ranges(&self) -> &[Range<Anchor>] {
22507        &self.ranges[self.active_index]
22508    }
22509}
22510
22511fn inline_completion_edit_text(
22512    current_snapshot: &BufferSnapshot,
22513    edits: &[(Range<Anchor>, String)],
22514    edit_preview: &EditPreview,
22515    include_deletions: bool,
22516    cx: &App,
22517) -> HighlightedText {
22518    let edits = edits
22519        .iter()
22520        .map(|(anchor, text)| {
22521            (
22522                anchor.start.text_anchor..anchor.end.text_anchor,
22523                text.clone(),
22524            )
22525        })
22526        .collect::<Vec<_>>();
22527
22528    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22529}
22530
22531pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22532    match severity {
22533        lsp::DiagnosticSeverity::ERROR => colors.error,
22534        lsp::DiagnosticSeverity::WARNING => colors.warning,
22535        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22536        lsp::DiagnosticSeverity::HINT => colors.info,
22537        _ => colors.ignored,
22538    }
22539}
22540
22541pub fn styled_runs_for_code_label<'a>(
22542    label: &'a CodeLabel,
22543    syntax_theme: &'a theme::SyntaxTheme,
22544) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22545    let fade_out = HighlightStyle {
22546        fade_out: Some(0.35),
22547        ..Default::default()
22548    };
22549
22550    let mut prev_end = label.filter_range.end;
22551    label
22552        .runs
22553        .iter()
22554        .enumerate()
22555        .flat_map(move |(ix, (range, highlight_id))| {
22556            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22557                style
22558            } else {
22559                return Default::default();
22560            };
22561            let mut muted_style = style;
22562            muted_style.highlight(fade_out);
22563
22564            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22565            if range.start >= label.filter_range.end {
22566                if range.start > prev_end {
22567                    runs.push((prev_end..range.start, fade_out));
22568                }
22569                runs.push((range.clone(), muted_style));
22570            } else if range.end <= label.filter_range.end {
22571                runs.push((range.clone(), style));
22572            } else {
22573                runs.push((range.start..label.filter_range.end, style));
22574                runs.push((label.filter_range.end..range.end, muted_style));
22575            }
22576            prev_end = cmp::max(prev_end, range.end);
22577
22578            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22579                runs.push((prev_end..label.text.len(), fade_out));
22580            }
22581
22582            runs
22583        })
22584}
22585
22586pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22587    let mut prev_index = 0;
22588    let mut prev_codepoint: Option<char> = None;
22589    text.char_indices()
22590        .chain([(text.len(), '\0')])
22591        .filter_map(move |(index, codepoint)| {
22592            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22593            let is_boundary = index == text.len()
22594                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22595                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22596            if is_boundary {
22597                let chunk = &text[prev_index..index];
22598                prev_index = index;
22599                Some(chunk)
22600            } else {
22601                None
22602            }
22603        })
22604}
22605
22606pub trait RangeToAnchorExt: Sized {
22607    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22608
22609    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22610        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22611        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22612    }
22613}
22614
22615impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22616    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22617        let start_offset = self.start.to_offset(snapshot);
22618        let end_offset = self.end.to_offset(snapshot);
22619        if start_offset == end_offset {
22620            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22621        } else {
22622            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22623        }
22624    }
22625}
22626
22627pub trait RowExt {
22628    fn as_f32(&self) -> f32;
22629
22630    fn next_row(&self) -> Self;
22631
22632    fn previous_row(&self) -> Self;
22633
22634    fn minus(&self, other: Self) -> u32;
22635}
22636
22637impl RowExt for DisplayRow {
22638    fn as_f32(&self) -> f32 {
22639        self.0 as f32
22640    }
22641
22642    fn next_row(&self) -> Self {
22643        Self(self.0 + 1)
22644    }
22645
22646    fn previous_row(&self) -> Self {
22647        Self(self.0.saturating_sub(1))
22648    }
22649
22650    fn minus(&self, other: Self) -> u32 {
22651        self.0 - other.0
22652    }
22653}
22654
22655impl RowExt for MultiBufferRow {
22656    fn as_f32(&self) -> f32 {
22657        self.0 as f32
22658    }
22659
22660    fn next_row(&self) -> Self {
22661        Self(self.0 + 1)
22662    }
22663
22664    fn previous_row(&self) -> Self {
22665        Self(self.0.saturating_sub(1))
22666    }
22667
22668    fn minus(&self, other: Self) -> u32 {
22669        self.0 - other.0
22670    }
22671}
22672
22673trait RowRangeExt {
22674    type Row;
22675
22676    fn len(&self) -> usize;
22677
22678    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22679}
22680
22681impl RowRangeExt for Range<MultiBufferRow> {
22682    type Row = MultiBufferRow;
22683
22684    fn len(&self) -> usize {
22685        (self.end.0 - self.start.0) as usize
22686    }
22687
22688    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22689        (self.start.0..self.end.0).map(MultiBufferRow)
22690    }
22691}
22692
22693impl RowRangeExt for Range<DisplayRow> {
22694    type Row = DisplayRow;
22695
22696    fn len(&self) -> usize {
22697        (self.end.0 - self.start.0) as usize
22698    }
22699
22700    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22701        (self.start.0..self.end.0).map(DisplayRow)
22702    }
22703}
22704
22705/// If select range has more than one line, we
22706/// just point the cursor to range.start.
22707fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22708    if range.start.row == range.end.row {
22709        range
22710    } else {
22711        range.start..range.start
22712    }
22713}
22714pub struct KillRing(ClipboardItem);
22715impl Global for KillRing {}
22716
22717const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22718
22719enum BreakpointPromptEditAction {
22720    Log,
22721    Condition,
22722    HitCondition,
22723}
22724
22725struct BreakpointPromptEditor {
22726    pub(crate) prompt: Entity<Editor>,
22727    editor: WeakEntity<Editor>,
22728    breakpoint_anchor: Anchor,
22729    breakpoint: Breakpoint,
22730    edit_action: BreakpointPromptEditAction,
22731    block_ids: HashSet<CustomBlockId>,
22732    editor_margins: Arc<Mutex<EditorMargins>>,
22733    _subscriptions: Vec<Subscription>,
22734}
22735
22736impl BreakpointPromptEditor {
22737    const MAX_LINES: u8 = 4;
22738
22739    fn new(
22740        editor: WeakEntity<Editor>,
22741        breakpoint_anchor: Anchor,
22742        breakpoint: Breakpoint,
22743        edit_action: BreakpointPromptEditAction,
22744        window: &mut Window,
22745        cx: &mut Context<Self>,
22746    ) -> Self {
22747        let base_text = match edit_action {
22748            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22749            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22750            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22751        }
22752        .map(|msg| msg.to_string())
22753        .unwrap_or_default();
22754
22755        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22756        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22757
22758        let prompt = cx.new(|cx| {
22759            let mut prompt = Editor::new(
22760                EditorMode::AutoHeight {
22761                    min_lines: 1,
22762                    max_lines: Some(Self::MAX_LINES as usize),
22763                },
22764                buffer,
22765                None,
22766                window,
22767                cx,
22768            );
22769            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22770            prompt.set_show_cursor_when_unfocused(false, cx);
22771            prompt.set_placeholder_text(
22772                match edit_action {
22773                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22774                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22775                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22776                },
22777                cx,
22778            );
22779
22780            prompt
22781        });
22782
22783        Self {
22784            prompt,
22785            editor,
22786            breakpoint_anchor,
22787            breakpoint,
22788            edit_action,
22789            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22790            block_ids: Default::default(),
22791            _subscriptions: vec![],
22792        }
22793    }
22794
22795    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22796        self.block_ids.extend(block_ids)
22797    }
22798
22799    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22800        if let Some(editor) = self.editor.upgrade() {
22801            let message = self
22802                .prompt
22803                .read(cx)
22804                .buffer
22805                .read(cx)
22806                .as_singleton()
22807                .expect("A multi buffer in breakpoint prompt isn't possible")
22808                .read(cx)
22809                .as_rope()
22810                .to_string();
22811
22812            editor.update(cx, |editor, cx| {
22813                editor.edit_breakpoint_at_anchor(
22814                    self.breakpoint_anchor,
22815                    self.breakpoint.clone(),
22816                    match self.edit_action {
22817                        BreakpointPromptEditAction::Log => {
22818                            BreakpointEditAction::EditLogMessage(message.into())
22819                        }
22820                        BreakpointPromptEditAction::Condition => {
22821                            BreakpointEditAction::EditCondition(message.into())
22822                        }
22823                        BreakpointPromptEditAction::HitCondition => {
22824                            BreakpointEditAction::EditHitCondition(message.into())
22825                        }
22826                    },
22827                    cx,
22828                );
22829
22830                editor.remove_blocks(self.block_ids.clone(), None, cx);
22831                cx.focus_self(window);
22832            });
22833        }
22834    }
22835
22836    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22837        self.editor
22838            .update(cx, |editor, cx| {
22839                editor.remove_blocks(self.block_ids.clone(), None, cx);
22840                window.focus(&editor.focus_handle);
22841            })
22842            .log_err();
22843    }
22844
22845    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22846        let settings = ThemeSettings::get_global(cx);
22847        let text_style = TextStyle {
22848            color: if self.prompt.read(cx).read_only(cx) {
22849                cx.theme().colors().text_disabled
22850            } else {
22851                cx.theme().colors().text
22852            },
22853            font_family: settings.buffer_font.family.clone(),
22854            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22855            font_size: settings.buffer_font_size(cx).into(),
22856            font_weight: settings.buffer_font.weight,
22857            line_height: relative(settings.buffer_line_height.value()),
22858            ..Default::default()
22859        };
22860        EditorElement::new(
22861            &self.prompt,
22862            EditorStyle {
22863                background: cx.theme().colors().editor_background,
22864                local_player: cx.theme().players().local(),
22865                text: text_style,
22866                ..Default::default()
22867            },
22868        )
22869    }
22870}
22871
22872impl Render for BreakpointPromptEditor {
22873    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22874        let editor_margins = *self.editor_margins.lock();
22875        let gutter_dimensions = editor_margins.gutter;
22876        h_flex()
22877            .key_context("Editor")
22878            .bg(cx.theme().colors().editor_background)
22879            .border_y_1()
22880            .border_color(cx.theme().status().info_border)
22881            .size_full()
22882            .py(window.line_height() / 2.5)
22883            .on_action(cx.listener(Self::confirm))
22884            .on_action(cx.listener(Self::cancel))
22885            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22886            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22887    }
22888}
22889
22890impl Focusable for BreakpointPromptEditor {
22891    fn focus_handle(&self, cx: &App) -> FocusHandle {
22892        self.prompt.focus_handle(cx)
22893    }
22894}
22895
22896fn all_edits_insertions_or_deletions(
22897    edits: &Vec<(Range<Anchor>, String)>,
22898    snapshot: &MultiBufferSnapshot,
22899) -> bool {
22900    let mut all_insertions = true;
22901    let mut all_deletions = true;
22902
22903    for (range, new_text) in edits.iter() {
22904        let range_is_empty = range.to_offset(&snapshot).is_empty();
22905        let text_is_empty = new_text.is_empty();
22906
22907        if range_is_empty != text_is_empty {
22908            if range_is_empty {
22909                all_deletions = false;
22910            } else {
22911                all_insertions = false;
22912            }
22913        } else {
22914            return false;
22915        }
22916
22917        if !all_insertions && !all_deletions {
22918            return false;
22919        }
22920    }
22921    all_insertions || all_deletions
22922}
22923
22924struct MissingEditPredictionKeybindingTooltip;
22925
22926impl Render for MissingEditPredictionKeybindingTooltip {
22927    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22928        ui::tooltip_container(window, cx, |container, _, cx| {
22929            container
22930                .flex_shrink_0()
22931                .max_w_80()
22932                .min_h(rems_from_px(124.))
22933                .justify_between()
22934                .child(
22935                    v_flex()
22936                        .flex_1()
22937                        .text_ui_sm(cx)
22938                        .child(Label::new("Conflict with Accept Keybinding"))
22939                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22940                )
22941                .child(
22942                    h_flex()
22943                        .pb_1()
22944                        .gap_1()
22945                        .items_end()
22946                        .w_full()
22947                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22948                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22949                        }))
22950                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22951                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22952                        })),
22953                )
22954        })
22955    }
22956}
22957
22958#[derive(Debug, Clone, Copy, PartialEq)]
22959pub struct LineHighlight {
22960    pub background: Background,
22961    pub border: Option<gpui::Hsla>,
22962    pub include_gutter: bool,
22963    pub type_id: Option<TypeId>,
22964}
22965
22966fn render_diff_hunk_controls(
22967    row: u32,
22968    status: &DiffHunkStatus,
22969    hunk_range: Range<Anchor>,
22970    is_created_file: bool,
22971    line_height: Pixels,
22972    editor: &Entity<Editor>,
22973    _window: &mut Window,
22974    cx: &mut App,
22975) -> AnyElement {
22976    h_flex()
22977        .h(line_height)
22978        .mr_1()
22979        .gap_1()
22980        .px_0p5()
22981        .pb_1()
22982        .border_x_1()
22983        .border_b_1()
22984        .border_color(cx.theme().colors().border_variant)
22985        .rounded_b_lg()
22986        .bg(cx.theme().colors().editor_background)
22987        .gap_1()
22988        .block_mouse_except_scroll()
22989        .shadow_md()
22990        .child(if status.has_secondary_hunk() {
22991            Button::new(("stage", row as u64), "Stage")
22992                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22993                .tooltip({
22994                    let focus_handle = editor.focus_handle(cx);
22995                    move |window, cx| {
22996                        Tooltip::for_action_in(
22997                            "Stage Hunk",
22998                            &::git::ToggleStaged,
22999                            &focus_handle,
23000                            window,
23001                            cx,
23002                        )
23003                    }
23004                })
23005                .on_click({
23006                    let editor = editor.clone();
23007                    move |_event, _window, cx| {
23008                        editor.update(cx, |editor, cx| {
23009                            editor.stage_or_unstage_diff_hunks(
23010                                true,
23011                                vec![hunk_range.start..hunk_range.start],
23012                                cx,
23013                            );
23014                        });
23015                    }
23016                })
23017        } else {
23018            Button::new(("unstage", row as u64), "Unstage")
23019                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23020                .tooltip({
23021                    let focus_handle = editor.focus_handle(cx);
23022                    move |window, cx| {
23023                        Tooltip::for_action_in(
23024                            "Unstage Hunk",
23025                            &::git::ToggleStaged,
23026                            &focus_handle,
23027                            window,
23028                            cx,
23029                        )
23030                    }
23031                })
23032                .on_click({
23033                    let editor = editor.clone();
23034                    move |_event, _window, cx| {
23035                        editor.update(cx, |editor, cx| {
23036                            editor.stage_or_unstage_diff_hunks(
23037                                false,
23038                                vec![hunk_range.start..hunk_range.start],
23039                                cx,
23040                            );
23041                        });
23042                    }
23043                })
23044        })
23045        .child(
23046            Button::new(("restore", row as u64), "Restore")
23047                .tooltip({
23048                    let focus_handle = editor.focus_handle(cx);
23049                    move |window, cx| {
23050                        Tooltip::for_action_in(
23051                            "Restore Hunk",
23052                            &::git::Restore,
23053                            &focus_handle,
23054                            window,
23055                            cx,
23056                        )
23057                    }
23058                })
23059                .on_click({
23060                    let editor = editor.clone();
23061                    move |_event, window, cx| {
23062                        editor.update(cx, |editor, cx| {
23063                            let snapshot = editor.snapshot(window, cx);
23064                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23065                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23066                        });
23067                    }
23068                })
23069                .disabled(is_created_file),
23070        )
23071        .when(
23072            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23073            |el| {
23074                el.child(
23075                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23076                        .shape(IconButtonShape::Square)
23077                        .icon_size(IconSize::Small)
23078                        // .disabled(!has_multiple_hunks)
23079                        .tooltip({
23080                            let focus_handle = editor.focus_handle(cx);
23081                            move |window, cx| {
23082                                Tooltip::for_action_in(
23083                                    "Next Hunk",
23084                                    &GoToHunk,
23085                                    &focus_handle,
23086                                    window,
23087                                    cx,
23088                                )
23089                            }
23090                        })
23091                        .on_click({
23092                            let editor = editor.clone();
23093                            move |_event, window, cx| {
23094                                editor.update(cx, |editor, cx| {
23095                                    let snapshot = editor.snapshot(window, cx);
23096                                    let position =
23097                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23098                                    editor.go_to_hunk_before_or_after_position(
23099                                        &snapshot,
23100                                        position,
23101                                        Direction::Next,
23102                                        window,
23103                                        cx,
23104                                    );
23105                                    editor.expand_selected_diff_hunks(cx);
23106                                });
23107                            }
23108                        }),
23109                )
23110                .child(
23111                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23112                        .shape(IconButtonShape::Square)
23113                        .icon_size(IconSize::Small)
23114                        // .disabled(!has_multiple_hunks)
23115                        .tooltip({
23116                            let focus_handle = editor.focus_handle(cx);
23117                            move |window, cx| {
23118                                Tooltip::for_action_in(
23119                                    "Previous Hunk",
23120                                    &GoToPreviousHunk,
23121                                    &focus_handle,
23122                                    window,
23123                                    cx,
23124                                )
23125                            }
23126                        })
23127                        .on_click({
23128                            let editor = editor.clone();
23129                            move |_event, window, cx| {
23130                                editor.update(cx, |editor, cx| {
23131                                    let snapshot = editor.snapshot(window, cx);
23132                                    let point =
23133                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23134                                    editor.go_to_hunk_before_or_after_position(
23135                                        &snapshot,
23136                                        point,
23137                                        Direction::Prev,
23138                                        window,
23139                                        cx,
23140                                    );
23141                                    editor.expand_selected_diff_hunks(cx);
23142                                });
23143                            }
23144                        }),
23145                )
23146            },
23147        )
23148        .into_any_element()
23149}