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 position = display_map
 3392                    .clip_point(position, Bias::Left)
 3393                    .to_offset(&display_map, Bias::Left);
 3394                let (range, _) = buffer.surrounding_word(position, false);
 3395                start = buffer.anchor_before(range.start);
 3396                end = buffer.anchor_before(range.end);
 3397                mode = SelectMode::Word(start..end);
 3398                auto_scroll = true;
 3399            }
 3400            3 => {
 3401                let position = display_map
 3402                    .clip_point(position, Bias::Left)
 3403                    .to_point(&display_map);
 3404                let line_start = display_map.prev_line_boundary(position).0;
 3405                let next_line_start = buffer.clip_point(
 3406                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3407                    Bias::Left,
 3408                );
 3409                start = buffer.anchor_before(line_start);
 3410                end = buffer.anchor_before(next_line_start);
 3411                mode = SelectMode::Line(start..end);
 3412                auto_scroll = true;
 3413            }
 3414            _ => {
 3415                start = buffer.anchor_before(0);
 3416                end = buffer.anchor_before(buffer.len());
 3417                mode = SelectMode::All;
 3418                auto_scroll = false;
 3419            }
 3420        }
 3421        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3422
 3423        let point_to_delete: Option<usize> = {
 3424            let selected_points: Vec<Selection<Point>> =
 3425                self.selections.disjoint_in_range(start..end, cx);
 3426
 3427            if !add || click_count > 1 {
 3428                None
 3429            } else if !selected_points.is_empty() {
 3430                Some(selected_points[0].id)
 3431            } else {
 3432                let clicked_point_already_selected =
 3433                    self.selections.disjoint.iter().find(|selection| {
 3434                        selection.start.to_point(buffer) == start.to_point(buffer)
 3435                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3436                    });
 3437
 3438                clicked_point_already_selected.map(|selection| selection.id)
 3439            }
 3440        };
 3441
 3442        let selections_count = self.selections.count();
 3443
 3444        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3445            if let Some(point_to_delete) = point_to_delete {
 3446                s.delete(point_to_delete);
 3447
 3448                if selections_count == 1 {
 3449                    s.set_pending_anchor_range(start..end, mode);
 3450                }
 3451            } else {
 3452                if !add {
 3453                    s.clear_disjoint();
 3454                }
 3455
 3456                s.set_pending_anchor_range(start..end, mode);
 3457            }
 3458        });
 3459    }
 3460
 3461    fn begin_columnar_selection(
 3462        &mut self,
 3463        position: DisplayPoint,
 3464        goal_column: u32,
 3465        reset: bool,
 3466        mode: ColumnarMode,
 3467        window: &mut Window,
 3468        cx: &mut Context<Self>,
 3469    ) {
 3470        if !self.focus_handle.is_focused(window) {
 3471            self.last_focused_descendant = None;
 3472            window.focus(&self.focus_handle);
 3473        }
 3474
 3475        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3476
 3477        if reset {
 3478            let pointer_position = display_map
 3479                .buffer_snapshot
 3480                .anchor_before(position.to_point(&display_map));
 3481
 3482            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3483                s.clear_disjoint();
 3484                s.set_pending_anchor_range(
 3485                    pointer_position..pointer_position,
 3486                    SelectMode::Character,
 3487                );
 3488            });
 3489        };
 3490
 3491        let tail = self.selections.newest::<Point>(cx).tail();
 3492        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3493        self.columnar_selection_state = match mode {
 3494            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3495                selection_tail: selection_anchor,
 3496                display_point: if reset {
 3497                    if position.column() != goal_column {
 3498                        Some(DisplayPoint::new(position.row(), goal_column))
 3499                    } else {
 3500                        None
 3501                    }
 3502                } else {
 3503                    None
 3504                },
 3505            }),
 3506            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3507                selection_tail: selection_anchor,
 3508            }),
 3509        };
 3510
 3511        if !reset {
 3512            self.select_columns(position, goal_column, &display_map, window, cx);
 3513        }
 3514    }
 3515
 3516    fn update_selection(
 3517        &mut self,
 3518        position: DisplayPoint,
 3519        goal_column: u32,
 3520        scroll_delta: gpui::Point<f32>,
 3521        window: &mut Window,
 3522        cx: &mut Context<Self>,
 3523    ) {
 3524        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3525
 3526        if self.columnar_selection_state.is_some() {
 3527            self.select_columns(position, goal_column, &display_map, window, cx);
 3528        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3529            let buffer = &display_map.buffer_snapshot;
 3530            let head;
 3531            let tail;
 3532            let mode = self.selections.pending_mode().unwrap();
 3533            match &mode {
 3534                SelectMode::Character => {
 3535                    head = position.to_point(&display_map);
 3536                    tail = pending.tail().to_point(buffer);
 3537                }
 3538                SelectMode::Word(original_range) => {
 3539                    let offset = display_map
 3540                        .clip_point(position, Bias::Left)
 3541                        .to_offset(&display_map, Bias::Left);
 3542                    let original_range = original_range.to_offset(buffer);
 3543
 3544                    let head_offset = if buffer.is_inside_word(offset, false)
 3545                        || original_range.contains(&offset)
 3546                    {
 3547                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3548                        if word_range.start < original_range.start {
 3549                            word_range.start
 3550                        } else {
 3551                            word_range.end
 3552                        }
 3553                    } else {
 3554                        offset
 3555                    };
 3556
 3557                    head = head_offset.to_point(buffer);
 3558                    if head_offset <= original_range.start {
 3559                        tail = original_range.end.to_point(buffer);
 3560                    } else {
 3561                        tail = original_range.start.to_point(buffer);
 3562                    }
 3563                }
 3564                SelectMode::Line(original_range) => {
 3565                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3566
 3567                    let position = display_map
 3568                        .clip_point(position, Bias::Left)
 3569                        .to_point(&display_map);
 3570                    let line_start = display_map.prev_line_boundary(position).0;
 3571                    let next_line_start = buffer.clip_point(
 3572                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3573                        Bias::Left,
 3574                    );
 3575
 3576                    if line_start < original_range.start {
 3577                        head = line_start
 3578                    } else {
 3579                        head = next_line_start
 3580                    }
 3581
 3582                    if head <= original_range.start {
 3583                        tail = original_range.end;
 3584                    } else {
 3585                        tail = original_range.start;
 3586                    }
 3587                }
 3588                SelectMode::All => {
 3589                    return;
 3590                }
 3591            };
 3592
 3593            if head < tail {
 3594                pending.start = buffer.anchor_before(head);
 3595                pending.end = buffer.anchor_before(tail);
 3596                pending.reversed = true;
 3597            } else {
 3598                pending.start = buffer.anchor_before(tail);
 3599                pending.end = buffer.anchor_before(head);
 3600                pending.reversed = false;
 3601            }
 3602
 3603            self.change_selections(None, window, cx, |s| {
 3604                s.set_pending(pending, mode);
 3605            });
 3606        } else {
 3607            log::error!("update_selection dispatched with no pending selection");
 3608            return;
 3609        }
 3610
 3611        self.apply_scroll_delta(scroll_delta, window, cx);
 3612        cx.notify();
 3613    }
 3614
 3615    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3616        self.columnar_selection_state.take();
 3617        if self.selections.pending_anchor().is_some() {
 3618            let selections = self.selections.all::<usize>(cx);
 3619            self.change_selections(None, window, cx, |s| {
 3620                s.select(selections);
 3621                s.clear_pending();
 3622            });
 3623        }
 3624    }
 3625
 3626    fn select_columns(
 3627        &mut self,
 3628        head: DisplayPoint,
 3629        goal_column: u32,
 3630        display_map: &DisplaySnapshot,
 3631        window: &mut Window,
 3632        cx: &mut Context<Self>,
 3633    ) {
 3634        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3635            return;
 3636        };
 3637
 3638        let tail = match columnar_state {
 3639            ColumnarSelectionState::FromMouse {
 3640                selection_tail,
 3641                display_point,
 3642            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3643            ColumnarSelectionState::FromSelection { selection_tail } => {
 3644                selection_tail.to_display_point(&display_map)
 3645            }
 3646        };
 3647
 3648        let start_row = cmp::min(tail.row(), head.row());
 3649        let end_row = cmp::max(tail.row(), head.row());
 3650        let start_column = cmp::min(tail.column(), goal_column);
 3651        let end_column = cmp::max(tail.column(), goal_column);
 3652        let reversed = start_column < tail.column();
 3653
 3654        let selection_ranges = (start_row.0..=end_row.0)
 3655            .map(DisplayRow)
 3656            .filter_map(|row| {
 3657                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3658                    || start_column <= display_map.line_len(row))
 3659                    && !display_map.is_block_line(row)
 3660                {
 3661                    let start = display_map
 3662                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3663                        .to_point(display_map);
 3664                    let end = display_map
 3665                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3666                        .to_point(display_map);
 3667                    if reversed {
 3668                        Some(end..start)
 3669                    } else {
 3670                        Some(start..end)
 3671                    }
 3672                } else {
 3673                    None
 3674                }
 3675            })
 3676            .collect::<Vec<_>>();
 3677
 3678        let ranges = match columnar_state {
 3679            ColumnarSelectionState::FromMouse { .. } => {
 3680                let mut non_empty_ranges = selection_ranges
 3681                    .iter()
 3682                    .filter(|selection_range| selection_range.start != selection_range.end)
 3683                    .peekable();
 3684                if non_empty_ranges.peek().is_some() {
 3685                    non_empty_ranges.cloned().collect()
 3686                } else {
 3687                    selection_ranges
 3688                }
 3689            }
 3690            _ => selection_ranges,
 3691        };
 3692
 3693        self.change_selections(None, window, cx, |s| {
 3694            s.select_ranges(ranges);
 3695        });
 3696        cx.notify();
 3697    }
 3698
 3699    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3700        self.selections
 3701            .all_adjusted(cx)
 3702            .iter()
 3703            .any(|selection| !selection.is_empty())
 3704    }
 3705
 3706    pub fn has_pending_nonempty_selection(&self) -> bool {
 3707        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3708            Some(Selection { start, end, .. }) => start != end,
 3709            None => false,
 3710        };
 3711
 3712        pending_nonempty_selection
 3713            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3714    }
 3715
 3716    pub fn has_pending_selection(&self) -> bool {
 3717        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3718    }
 3719
 3720    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3721        self.selection_mark_mode = false;
 3722        self.selection_drag_state = SelectionDragState::None;
 3723
 3724        if self.clear_expanded_diff_hunks(cx) {
 3725            cx.notify();
 3726            return;
 3727        }
 3728        if self.dismiss_menus_and_popups(true, window, cx) {
 3729            return;
 3730        }
 3731
 3732        if self.mode.is_full()
 3733            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3734        {
 3735            return;
 3736        }
 3737
 3738        cx.propagate();
 3739    }
 3740
 3741    pub fn dismiss_menus_and_popups(
 3742        &mut self,
 3743        is_user_requested: bool,
 3744        window: &mut Window,
 3745        cx: &mut Context<Self>,
 3746    ) -> bool {
 3747        if self.take_rename(false, window, cx).is_some() {
 3748            return true;
 3749        }
 3750
 3751        if hide_hover(self, cx) {
 3752            return true;
 3753        }
 3754
 3755        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3756            return true;
 3757        }
 3758
 3759        if self.hide_context_menu(window, cx).is_some() {
 3760            return true;
 3761        }
 3762
 3763        if self.mouse_context_menu.take().is_some() {
 3764            return true;
 3765        }
 3766
 3767        if is_user_requested && self.discard_inline_completion(true, cx) {
 3768            return true;
 3769        }
 3770
 3771        if self.snippet_stack.pop().is_some() {
 3772            return true;
 3773        }
 3774
 3775        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3776            self.dismiss_diagnostics(cx);
 3777            return true;
 3778        }
 3779
 3780        false
 3781    }
 3782
 3783    fn linked_editing_ranges_for(
 3784        &self,
 3785        selection: Range<text::Anchor>,
 3786        cx: &App,
 3787    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3788        if self.linked_edit_ranges.is_empty() {
 3789            return None;
 3790        }
 3791        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3792            selection.end.buffer_id.and_then(|end_buffer_id| {
 3793                if selection.start.buffer_id != Some(end_buffer_id) {
 3794                    return None;
 3795                }
 3796                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3797                let snapshot = buffer.read(cx).snapshot();
 3798                self.linked_edit_ranges
 3799                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3800                    .map(|ranges| (ranges, snapshot, buffer))
 3801            })?;
 3802        use text::ToOffset as TO;
 3803        // find offset from the start of current range to current cursor position
 3804        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3805
 3806        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3807        let start_difference = start_offset - start_byte_offset;
 3808        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3809        let end_difference = end_offset - start_byte_offset;
 3810        // Current range has associated linked ranges.
 3811        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3812        for range in linked_ranges.iter() {
 3813            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3814            let end_offset = start_offset + end_difference;
 3815            let start_offset = start_offset + start_difference;
 3816            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3817                continue;
 3818            }
 3819            if self.selections.disjoint_anchor_ranges().any(|s| {
 3820                if s.start.buffer_id != selection.start.buffer_id
 3821                    || s.end.buffer_id != selection.end.buffer_id
 3822                {
 3823                    return false;
 3824                }
 3825                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3826                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3827            }) {
 3828                continue;
 3829            }
 3830            let start = buffer_snapshot.anchor_after(start_offset);
 3831            let end = buffer_snapshot.anchor_after(end_offset);
 3832            linked_edits
 3833                .entry(buffer.clone())
 3834                .or_default()
 3835                .push(start..end);
 3836        }
 3837        Some(linked_edits)
 3838    }
 3839
 3840    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3841        let text: Arc<str> = text.into();
 3842
 3843        if self.read_only(cx) {
 3844            return;
 3845        }
 3846
 3847        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3848
 3849        let selections = self.selections.all_adjusted(cx);
 3850        let mut bracket_inserted = false;
 3851        let mut edits = Vec::new();
 3852        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3853        let mut new_selections = Vec::with_capacity(selections.len());
 3854        let mut new_autoclose_regions = Vec::new();
 3855        let snapshot = self.buffer.read(cx).read(cx);
 3856        let mut clear_linked_edit_ranges = false;
 3857
 3858        for (selection, autoclose_region) in
 3859            self.selections_with_autoclose_regions(selections, &snapshot)
 3860        {
 3861            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3862                // Determine if the inserted text matches the opening or closing
 3863                // bracket of any of this language's bracket pairs.
 3864                let mut bracket_pair = None;
 3865                let mut is_bracket_pair_start = false;
 3866                let mut is_bracket_pair_end = false;
 3867                if !text.is_empty() {
 3868                    let mut bracket_pair_matching_end = None;
 3869                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3870                    //  and they are removing the character that triggered IME popup.
 3871                    for (pair, enabled) in scope.brackets() {
 3872                        if !pair.close && !pair.surround {
 3873                            continue;
 3874                        }
 3875
 3876                        if enabled && pair.start.ends_with(text.as_ref()) {
 3877                            let prefix_len = pair.start.len() - text.len();
 3878                            let preceding_text_matches_prefix = prefix_len == 0
 3879                                || (selection.start.column >= (prefix_len as u32)
 3880                                    && snapshot.contains_str_at(
 3881                                        Point::new(
 3882                                            selection.start.row,
 3883                                            selection.start.column - (prefix_len as u32),
 3884                                        ),
 3885                                        &pair.start[..prefix_len],
 3886                                    ));
 3887                            if preceding_text_matches_prefix {
 3888                                bracket_pair = Some(pair.clone());
 3889                                is_bracket_pair_start = true;
 3890                                break;
 3891                            }
 3892                        }
 3893                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3894                        {
 3895                            // take first bracket pair matching end, but don't break in case a later bracket
 3896                            // pair matches start
 3897                            bracket_pair_matching_end = Some(pair.clone());
 3898                        }
 3899                    }
 3900                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3901                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3902                        is_bracket_pair_end = true;
 3903                    }
 3904                }
 3905
 3906                if let Some(bracket_pair) = bracket_pair {
 3907                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3908                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3909                    let auto_surround =
 3910                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3911                    if selection.is_empty() {
 3912                        if is_bracket_pair_start {
 3913                            // If the inserted text is a suffix of an opening bracket and the
 3914                            // selection is preceded by the rest of the opening bracket, then
 3915                            // insert the closing bracket.
 3916                            let following_text_allows_autoclose = snapshot
 3917                                .chars_at(selection.start)
 3918                                .next()
 3919                                .map_or(true, |c| scope.should_autoclose_before(c));
 3920
 3921                            let preceding_text_allows_autoclose = selection.start.column == 0
 3922                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3923                                    true,
 3924                                    |c| {
 3925                                        bracket_pair.start != bracket_pair.end
 3926                                            || !snapshot
 3927                                                .char_classifier_at(selection.start)
 3928                                                .is_word(c)
 3929                                    },
 3930                                );
 3931
 3932                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3933                                && bracket_pair.start.len() == 1
 3934                            {
 3935                                let target = bracket_pair.start.chars().next().unwrap();
 3936                                let current_line_count = snapshot
 3937                                    .reversed_chars_at(selection.start)
 3938                                    .take_while(|&c| c != '\n')
 3939                                    .filter(|&c| c == target)
 3940                                    .count();
 3941                                current_line_count % 2 == 1
 3942                            } else {
 3943                                false
 3944                            };
 3945
 3946                            if autoclose
 3947                                && bracket_pair.close
 3948                                && following_text_allows_autoclose
 3949                                && preceding_text_allows_autoclose
 3950                                && !is_closing_quote
 3951                            {
 3952                                let anchor = snapshot.anchor_before(selection.end);
 3953                                new_selections.push((selection.map(|_| anchor), text.len()));
 3954                                new_autoclose_regions.push((
 3955                                    anchor,
 3956                                    text.len(),
 3957                                    selection.id,
 3958                                    bracket_pair.clone(),
 3959                                ));
 3960                                edits.push((
 3961                                    selection.range(),
 3962                                    format!("{}{}", text, bracket_pair.end).into(),
 3963                                ));
 3964                                bracket_inserted = true;
 3965                                continue;
 3966                            }
 3967                        }
 3968
 3969                        if let Some(region) = autoclose_region {
 3970                            // If the selection is followed by an auto-inserted closing bracket,
 3971                            // then don't insert that closing bracket again; just move the selection
 3972                            // past the closing bracket.
 3973                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3974                                && text.as_ref() == region.pair.end.as_str();
 3975                            if should_skip {
 3976                                let anchor = snapshot.anchor_after(selection.end);
 3977                                new_selections
 3978                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3979                                continue;
 3980                            }
 3981                        }
 3982
 3983                        let always_treat_brackets_as_autoclosed = snapshot
 3984                            .language_settings_at(selection.start, cx)
 3985                            .always_treat_brackets_as_autoclosed;
 3986                        if always_treat_brackets_as_autoclosed
 3987                            && is_bracket_pair_end
 3988                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3989                        {
 3990                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3991                            // and the inserted text is a closing bracket and the selection is followed
 3992                            // by the closing bracket then move the selection past the closing bracket.
 3993                            let anchor = snapshot.anchor_after(selection.end);
 3994                            new_selections.push((selection.map(|_| anchor), text.len()));
 3995                            continue;
 3996                        }
 3997                    }
 3998                    // If an opening bracket is 1 character long and is typed while
 3999                    // text is selected, then surround that text with the bracket pair.
 4000                    else if auto_surround
 4001                        && bracket_pair.surround
 4002                        && is_bracket_pair_start
 4003                        && bracket_pair.start.chars().count() == 1
 4004                    {
 4005                        edits.push((selection.start..selection.start, text.clone()));
 4006                        edits.push((
 4007                            selection.end..selection.end,
 4008                            bracket_pair.end.as_str().into(),
 4009                        ));
 4010                        bracket_inserted = true;
 4011                        new_selections.push((
 4012                            Selection {
 4013                                id: selection.id,
 4014                                start: snapshot.anchor_after(selection.start),
 4015                                end: snapshot.anchor_before(selection.end),
 4016                                reversed: selection.reversed,
 4017                                goal: selection.goal,
 4018                            },
 4019                            0,
 4020                        ));
 4021                        continue;
 4022                    }
 4023                }
 4024            }
 4025
 4026            if self.auto_replace_emoji_shortcode
 4027                && selection.is_empty()
 4028                && text.as_ref().ends_with(':')
 4029            {
 4030                if let Some(possible_emoji_short_code) =
 4031                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4032                {
 4033                    if !possible_emoji_short_code.is_empty() {
 4034                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4035                            let emoji_shortcode_start = Point::new(
 4036                                selection.start.row,
 4037                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4038                            );
 4039
 4040                            // Remove shortcode from buffer
 4041                            edits.push((
 4042                                emoji_shortcode_start..selection.start,
 4043                                "".to_string().into(),
 4044                            ));
 4045                            new_selections.push((
 4046                                Selection {
 4047                                    id: selection.id,
 4048                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4049                                    end: snapshot.anchor_before(selection.start),
 4050                                    reversed: selection.reversed,
 4051                                    goal: selection.goal,
 4052                                },
 4053                                0,
 4054                            ));
 4055
 4056                            // Insert emoji
 4057                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4058                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4059                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4060
 4061                            continue;
 4062                        }
 4063                    }
 4064                }
 4065            }
 4066
 4067            // If not handling any auto-close operation, then just replace the selected
 4068            // text with the given input and move the selection to the end of the
 4069            // newly inserted text.
 4070            let anchor = snapshot.anchor_after(selection.end);
 4071            if !self.linked_edit_ranges.is_empty() {
 4072                let start_anchor = snapshot.anchor_before(selection.start);
 4073
 4074                let is_word_char = text.chars().next().map_or(true, |char| {
 4075                    let classifier = snapshot
 4076                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4077                        .ignore_punctuation(true);
 4078                    classifier.is_word(char)
 4079                });
 4080
 4081                if is_word_char {
 4082                    if let Some(ranges) = self
 4083                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4084                    {
 4085                        for (buffer, edits) in ranges {
 4086                            linked_edits
 4087                                .entry(buffer.clone())
 4088                                .or_default()
 4089                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4090                        }
 4091                    }
 4092                } else {
 4093                    clear_linked_edit_ranges = true;
 4094                }
 4095            }
 4096
 4097            new_selections.push((selection.map(|_| anchor), 0));
 4098            edits.push((selection.start..selection.end, text.clone()));
 4099        }
 4100
 4101        drop(snapshot);
 4102
 4103        self.transact(window, cx, |this, window, cx| {
 4104            if clear_linked_edit_ranges {
 4105                this.linked_edit_ranges.clear();
 4106            }
 4107            let initial_buffer_versions =
 4108                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4109
 4110            this.buffer.update(cx, |buffer, cx| {
 4111                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4112            });
 4113            for (buffer, edits) in linked_edits {
 4114                buffer.update(cx, |buffer, cx| {
 4115                    let snapshot = buffer.snapshot();
 4116                    let edits = edits
 4117                        .into_iter()
 4118                        .map(|(range, text)| {
 4119                            use text::ToPoint as TP;
 4120                            let end_point = TP::to_point(&range.end, &snapshot);
 4121                            let start_point = TP::to_point(&range.start, &snapshot);
 4122                            (start_point..end_point, text)
 4123                        })
 4124                        .sorted_by_key(|(range, _)| range.start);
 4125                    buffer.edit(edits, None, cx);
 4126                })
 4127            }
 4128            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4129            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4130            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4131            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4132                .zip(new_selection_deltas)
 4133                .map(|(selection, delta)| Selection {
 4134                    id: selection.id,
 4135                    start: selection.start + delta,
 4136                    end: selection.end + delta,
 4137                    reversed: selection.reversed,
 4138                    goal: SelectionGoal::None,
 4139                })
 4140                .collect::<Vec<_>>();
 4141
 4142            let mut i = 0;
 4143            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4144                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4145                let start = map.buffer_snapshot.anchor_before(position);
 4146                let end = map.buffer_snapshot.anchor_after(position);
 4147                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4148                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4149                        Ordering::Less => i += 1,
 4150                        Ordering::Greater => break,
 4151                        Ordering::Equal => {
 4152                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4153                                Ordering::Less => i += 1,
 4154                                Ordering::Equal => break,
 4155                                Ordering::Greater => break,
 4156                            }
 4157                        }
 4158                    }
 4159                }
 4160                this.autoclose_regions.insert(
 4161                    i,
 4162                    AutocloseRegion {
 4163                        selection_id,
 4164                        range: start..end,
 4165                        pair,
 4166                    },
 4167                );
 4168            }
 4169
 4170            let had_active_inline_completion = this.has_active_inline_completion();
 4171            this.change_selections(
 4172                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4173                window,
 4174                cx,
 4175                |s| s.select(new_selections),
 4176            );
 4177
 4178            if !bracket_inserted {
 4179                if let Some(on_type_format_task) =
 4180                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4181                {
 4182                    on_type_format_task.detach_and_log_err(cx);
 4183                }
 4184            }
 4185
 4186            let editor_settings = EditorSettings::get_global(cx);
 4187            if bracket_inserted
 4188                && (editor_settings.auto_signature_help
 4189                    || editor_settings.show_signature_help_after_edits)
 4190            {
 4191                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4192            }
 4193
 4194            let trigger_in_words =
 4195                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4196            if this.hard_wrap.is_some() {
 4197                let latest: Range<Point> = this.selections.newest(cx).range();
 4198                if latest.is_empty()
 4199                    && this
 4200                        .buffer()
 4201                        .read(cx)
 4202                        .snapshot(cx)
 4203                        .line_len(MultiBufferRow(latest.start.row))
 4204                        == latest.start.column
 4205                {
 4206                    this.rewrap_impl(
 4207                        RewrapOptions {
 4208                            override_language_settings: true,
 4209                            preserve_existing_whitespace: true,
 4210                        },
 4211                        cx,
 4212                    )
 4213                }
 4214            }
 4215            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4216            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4217            this.refresh_inline_completion(true, false, window, cx);
 4218            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4219        });
 4220    }
 4221
 4222    fn find_possible_emoji_shortcode_at_position(
 4223        snapshot: &MultiBufferSnapshot,
 4224        position: Point,
 4225    ) -> Option<String> {
 4226        let mut chars = Vec::new();
 4227        let mut found_colon = false;
 4228        for char in snapshot.reversed_chars_at(position).take(100) {
 4229            // Found a possible emoji shortcode in the middle of the buffer
 4230            if found_colon {
 4231                if char.is_whitespace() {
 4232                    chars.reverse();
 4233                    return Some(chars.iter().collect());
 4234                }
 4235                // If the previous character is not a whitespace, we are in the middle of a word
 4236                // and we only want to complete the shortcode if the word is made up of other emojis
 4237                let mut containing_word = String::new();
 4238                for ch in snapshot
 4239                    .reversed_chars_at(position)
 4240                    .skip(chars.len() + 1)
 4241                    .take(100)
 4242                {
 4243                    if ch.is_whitespace() {
 4244                        break;
 4245                    }
 4246                    containing_word.push(ch);
 4247                }
 4248                let containing_word = containing_word.chars().rev().collect::<String>();
 4249                if util::word_consists_of_emojis(containing_word.as_str()) {
 4250                    chars.reverse();
 4251                    return Some(chars.iter().collect());
 4252                }
 4253            }
 4254
 4255            if char.is_whitespace() || !char.is_ascii() {
 4256                return None;
 4257            }
 4258            if char == ':' {
 4259                found_colon = true;
 4260            } else {
 4261                chars.push(char);
 4262            }
 4263        }
 4264        // Found a possible emoji shortcode at the beginning of the buffer
 4265        chars.reverse();
 4266        Some(chars.iter().collect())
 4267    }
 4268
 4269    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4270        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4271        self.transact(window, cx, |this, window, cx| {
 4272            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4273                let selections = this.selections.all::<usize>(cx);
 4274                let multi_buffer = this.buffer.read(cx);
 4275                let buffer = multi_buffer.snapshot(cx);
 4276                selections
 4277                    .iter()
 4278                    .map(|selection| {
 4279                        let start_point = selection.start.to_point(&buffer);
 4280                        let mut existing_indent =
 4281                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4282                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4283                        let start = selection.start;
 4284                        let end = selection.end;
 4285                        let selection_is_empty = start == end;
 4286                        let language_scope = buffer.language_scope_at(start);
 4287                        let (
 4288                            comment_delimiter,
 4289                            doc_delimiter,
 4290                            insert_extra_newline,
 4291                            indent_on_newline,
 4292                            indent_on_extra_newline,
 4293                        ) = if let Some(language) = &language_scope {
 4294                            let mut insert_extra_newline =
 4295                                insert_extra_newline_brackets(&buffer, start..end, language)
 4296                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4297
 4298                            // Comment extension on newline is allowed only for cursor selections
 4299                            let comment_delimiter = maybe!({
 4300                                if !selection_is_empty {
 4301                                    return None;
 4302                                }
 4303
 4304                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4305                                    return None;
 4306                                }
 4307
 4308                                let delimiters = language.line_comment_prefixes();
 4309                                let max_len_of_delimiter =
 4310                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4311                                let (snapshot, range) =
 4312                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4313
 4314                                let num_of_whitespaces = snapshot
 4315                                    .chars_for_range(range.clone())
 4316                                    .take_while(|c| c.is_whitespace())
 4317                                    .count();
 4318                                let comment_candidate = snapshot
 4319                                    .chars_for_range(range)
 4320                                    .skip(num_of_whitespaces)
 4321                                    .take(max_len_of_delimiter)
 4322                                    .collect::<String>();
 4323                                let (delimiter, trimmed_len) = delimiters
 4324                                    .iter()
 4325                                    .filter_map(|delimiter| {
 4326                                        let prefix = delimiter.trim_end();
 4327                                        if comment_candidate.starts_with(prefix) {
 4328                                            Some((delimiter, prefix.len()))
 4329                                        } else {
 4330                                            None
 4331                                        }
 4332                                    })
 4333                                    .max_by_key(|(_, len)| *len)?;
 4334
 4335                                let cursor_is_placed_after_comment_marker =
 4336                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4337                                if cursor_is_placed_after_comment_marker {
 4338                                    Some(delimiter.clone())
 4339                                } else {
 4340                                    None
 4341                                }
 4342                            });
 4343
 4344                            let mut indent_on_newline = IndentSize::spaces(0);
 4345                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4346
 4347                            let doc_delimiter = maybe!({
 4348                                if !selection_is_empty {
 4349                                    return None;
 4350                                }
 4351
 4352                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4353                                    return None;
 4354                                }
 4355
 4356                                let DocumentationConfig {
 4357                                    start: start_tag,
 4358                                    end: end_tag,
 4359                                    prefix: delimiter,
 4360                                    tab_size: len,
 4361                                } = language.documentation()?;
 4362
 4363                                let is_within_block_comment = buffer
 4364                                    .language_scope_at(start_point)
 4365                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4366                                if !is_within_block_comment {
 4367                                    return None;
 4368                                }
 4369
 4370                                let (snapshot, range) =
 4371                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4372
 4373                                let num_of_whitespaces = snapshot
 4374                                    .chars_for_range(range.clone())
 4375                                    .take_while(|c| c.is_whitespace())
 4376                                    .count();
 4377
 4378                                // 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.
 4379                                let column = start_point.column;
 4380                                let cursor_is_after_start_tag = {
 4381                                    let start_tag_len = start_tag.len();
 4382                                    let start_tag_line = snapshot
 4383                                        .chars_for_range(range.clone())
 4384                                        .skip(num_of_whitespaces)
 4385                                        .take(start_tag_len)
 4386                                        .collect::<String>();
 4387                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4388                                        num_of_whitespaces + start_tag_len <= column as usize
 4389                                    } else {
 4390                                        false
 4391                                    }
 4392                                };
 4393
 4394                                let cursor_is_after_delimiter = {
 4395                                    let delimiter_trim = delimiter.trim_end();
 4396                                    let delimiter_line = snapshot
 4397                                        .chars_for_range(range.clone())
 4398                                        .skip(num_of_whitespaces)
 4399                                        .take(delimiter_trim.len())
 4400                                        .collect::<String>();
 4401                                    if delimiter_line.starts_with(delimiter_trim) {
 4402                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4403                                    } else {
 4404                                        false
 4405                                    }
 4406                                };
 4407
 4408                                let cursor_is_before_end_tag_if_exists = {
 4409                                    let mut char_position = 0u32;
 4410                                    let mut end_tag_offset = None;
 4411
 4412                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4413                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4414                                            let chars_before_match =
 4415                                                chunk[..byte_pos].chars().count() as u32;
 4416                                            end_tag_offset =
 4417                                                Some(char_position + chars_before_match);
 4418                                            break 'outer;
 4419                                        }
 4420                                        char_position += chunk.chars().count() as u32;
 4421                                    }
 4422
 4423                                    if let Some(end_tag_offset) = end_tag_offset {
 4424                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4425                                        if cursor_is_after_start_tag {
 4426                                            if cursor_is_before_end_tag {
 4427                                                insert_extra_newline = true;
 4428                                            }
 4429                                            let cursor_is_at_start_of_end_tag =
 4430                                                column == end_tag_offset;
 4431                                            if cursor_is_at_start_of_end_tag {
 4432                                                indent_on_extra_newline.len = (*len).into();
 4433                                            }
 4434                                        }
 4435                                        cursor_is_before_end_tag
 4436                                    } else {
 4437                                        true
 4438                                    }
 4439                                };
 4440
 4441                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4442                                    && cursor_is_before_end_tag_if_exists
 4443                                {
 4444                                    if cursor_is_after_start_tag {
 4445                                        indent_on_newline.len = (*len).into();
 4446                                    }
 4447                                    Some(delimiter.clone())
 4448                                } else {
 4449                                    None
 4450                                }
 4451                            });
 4452
 4453                            (
 4454                                comment_delimiter,
 4455                                doc_delimiter,
 4456                                insert_extra_newline,
 4457                                indent_on_newline,
 4458                                indent_on_extra_newline,
 4459                            )
 4460                        } else {
 4461                            (
 4462                                None,
 4463                                None,
 4464                                false,
 4465                                IndentSize::default(),
 4466                                IndentSize::default(),
 4467                            )
 4468                        };
 4469
 4470                        let prevent_auto_indent = doc_delimiter.is_some();
 4471                        let delimiter = comment_delimiter.or(doc_delimiter);
 4472
 4473                        let capacity_for_delimiter =
 4474                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4475                        let mut new_text = String::with_capacity(
 4476                            1 + capacity_for_delimiter
 4477                                + existing_indent.len as usize
 4478                                + indent_on_newline.len as usize
 4479                                + indent_on_extra_newline.len as usize,
 4480                        );
 4481                        new_text.push('\n');
 4482                        new_text.extend(existing_indent.chars());
 4483                        new_text.extend(indent_on_newline.chars());
 4484
 4485                        if let Some(delimiter) = &delimiter {
 4486                            new_text.push_str(delimiter);
 4487                        }
 4488
 4489                        if insert_extra_newline {
 4490                            new_text.push('\n');
 4491                            new_text.extend(existing_indent.chars());
 4492                            new_text.extend(indent_on_extra_newline.chars());
 4493                        }
 4494
 4495                        let anchor = buffer.anchor_after(end);
 4496                        let new_selection = selection.map(|_| anchor);
 4497                        (
 4498                            ((start..end, new_text), prevent_auto_indent),
 4499                            (insert_extra_newline, new_selection),
 4500                        )
 4501                    })
 4502                    .unzip()
 4503            };
 4504
 4505            let mut auto_indent_edits = Vec::new();
 4506            let mut edits = Vec::new();
 4507            for (edit, prevent_auto_indent) in edits_with_flags {
 4508                if prevent_auto_indent {
 4509                    edits.push(edit);
 4510                } else {
 4511                    auto_indent_edits.push(edit);
 4512                }
 4513            }
 4514            if !edits.is_empty() {
 4515                this.edit(edits, cx);
 4516            }
 4517            if !auto_indent_edits.is_empty() {
 4518                this.edit_with_autoindent(auto_indent_edits, cx);
 4519            }
 4520
 4521            let buffer = this.buffer.read(cx).snapshot(cx);
 4522            let new_selections = selection_info
 4523                .into_iter()
 4524                .map(|(extra_newline_inserted, new_selection)| {
 4525                    let mut cursor = new_selection.end.to_point(&buffer);
 4526                    if extra_newline_inserted {
 4527                        cursor.row -= 1;
 4528                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4529                    }
 4530                    new_selection.map(|_| cursor)
 4531                })
 4532                .collect();
 4533
 4534            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4535                s.select(new_selections)
 4536            });
 4537            this.refresh_inline_completion(true, false, window, cx);
 4538        });
 4539    }
 4540
 4541    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4542        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4543
 4544        let buffer = self.buffer.read(cx);
 4545        let snapshot = buffer.snapshot(cx);
 4546
 4547        let mut edits = Vec::new();
 4548        let mut rows = Vec::new();
 4549
 4550        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4551            let cursor = selection.head();
 4552            let row = cursor.row;
 4553
 4554            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4555
 4556            let newline = "\n".to_string();
 4557            edits.push((start_of_line..start_of_line, newline));
 4558
 4559            rows.push(row + rows_inserted as u32);
 4560        }
 4561
 4562        self.transact(window, cx, |editor, window, cx| {
 4563            editor.edit(edits, cx);
 4564
 4565            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4566                let mut index = 0;
 4567                s.move_cursors_with(|map, _, _| {
 4568                    let row = rows[index];
 4569                    index += 1;
 4570
 4571                    let point = Point::new(row, 0);
 4572                    let boundary = map.next_line_boundary(point).1;
 4573                    let clipped = map.clip_point(boundary, Bias::Left);
 4574
 4575                    (clipped, SelectionGoal::None)
 4576                });
 4577            });
 4578
 4579            let mut indent_edits = Vec::new();
 4580            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4581            for row in rows {
 4582                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4583                for (row, indent) in indents {
 4584                    if indent.len == 0 {
 4585                        continue;
 4586                    }
 4587
 4588                    let text = match indent.kind {
 4589                        IndentKind::Space => " ".repeat(indent.len as usize),
 4590                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4591                    };
 4592                    let point = Point::new(row.0, 0);
 4593                    indent_edits.push((point..point, text));
 4594                }
 4595            }
 4596            editor.edit(indent_edits, cx);
 4597        });
 4598    }
 4599
 4600    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4601        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4602
 4603        let buffer = self.buffer.read(cx);
 4604        let snapshot = buffer.snapshot(cx);
 4605
 4606        let mut edits = Vec::new();
 4607        let mut rows = Vec::new();
 4608        let mut rows_inserted = 0;
 4609
 4610        for selection in self.selections.all_adjusted(cx) {
 4611            let cursor = selection.head();
 4612            let row = cursor.row;
 4613
 4614            let point = Point::new(row + 1, 0);
 4615            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4616
 4617            let newline = "\n".to_string();
 4618            edits.push((start_of_line..start_of_line, newline));
 4619
 4620            rows_inserted += 1;
 4621            rows.push(row + rows_inserted);
 4622        }
 4623
 4624        self.transact(window, cx, |editor, window, cx| {
 4625            editor.edit(edits, cx);
 4626
 4627            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4628                let mut index = 0;
 4629                s.move_cursors_with(|map, _, _| {
 4630                    let row = rows[index];
 4631                    index += 1;
 4632
 4633                    let point = Point::new(row, 0);
 4634                    let boundary = map.next_line_boundary(point).1;
 4635                    let clipped = map.clip_point(boundary, Bias::Left);
 4636
 4637                    (clipped, SelectionGoal::None)
 4638                });
 4639            });
 4640
 4641            let mut indent_edits = Vec::new();
 4642            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4643            for row in rows {
 4644                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4645                for (row, indent) in indents {
 4646                    if indent.len == 0 {
 4647                        continue;
 4648                    }
 4649
 4650                    let text = match indent.kind {
 4651                        IndentKind::Space => " ".repeat(indent.len as usize),
 4652                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4653                    };
 4654                    let point = Point::new(row.0, 0);
 4655                    indent_edits.push((point..point, text));
 4656                }
 4657            }
 4658            editor.edit(indent_edits, cx);
 4659        });
 4660    }
 4661
 4662    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4663        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4664            original_indent_columns: Vec::new(),
 4665        });
 4666        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4667    }
 4668
 4669    fn insert_with_autoindent_mode(
 4670        &mut self,
 4671        text: &str,
 4672        autoindent_mode: Option<AutoindentMode>,
 4673        window: &mut Window,
 4674        cx: &mut Context<Self>,
 4675    ) {
 4676        if self.read_only(cx) {
 4677            return;
 4678        }
 4679
 4680        let text: Arc<str> = text.into();
 4681        self.transact(window, cx, |this, window, cx| {
 4682            let old_selections = this.selections.all_adjusted(cx);
 4683            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4684                let anchors = {
 4685                    let snapshot = buffer.read(cx);
 4686                    old_selections
 4687                        .iter()
 4688                        .map(|s| {
 4689                            let anchor = snapshot.anchor_after(s.head());
 4690                            s.map(|_| anchor)
 4691                        })
 4692                        .collect::<Vec<_>>()
 4693                };
 4694                buffer.edit(
 4695                    old_selections
 4696                        .iter()
 4697                        .map(|s| (s.start..s.end, text.clone())),
 4698                    autoindent_mode,
 4699                    cx,
 4700                );
 4701                anchors
 4702            });
 4703
 4704            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4705                s.select_anchors(selection_anchors);
 4706            });
 4707
 4708            cx.notify();
 4709        });
 4710    }
 4711
 4712    fn trigger_completion_on_input(
 4713        &mut self,
 4714        text: &str,
 4715        trigger_in_words: bool,
 4716        window: &mut Window,
 4717        cx: &mut Context<Self>,
 4718    ) {
 4719        let completions_source = self
 4720            .context_menu
 4721            .borrow()
 4722            .as_ref()
 4723            .and_then(|menu| match menu {
 4724                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4725                CodeContextMenu::CodeActions(_) => None,
 4726            });
 4727
 4728        match completions_source {
 4729            Some(CompletionsMenuSource::Words) => {
 4730                self.show_word_completions(&ShowWordCompletions, window, cx)
 4731            }
 4732            Some(CompletionsMenuSource::Normal)
 4733            | Some(CompletionsMenuSource::SnippetChoices)
 4734            | None
 4735                if self.is_completion_trigger(
 4736                    text,
 4737                    trigger_in_words,
 4738                    completions_source.is_some(),
 4739                    cx,
 4740                ) =>
 4741            {
 4742                self.show_completions(
 4743                    &ShowCompletions {
 4744                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4745                    },
 4746                    window,
 4747                    cx,
 4748                )
 4749            }
 4750            _ => {
 4751                self.hide_context_menu(window, cx);
 4752            }
 4753        }
 4754    }
 4755
 4756    fn is_completion_trigger(
 4757        &self,
 4758        text: &str,
 4759        trigger_in_words: bool,
 4760        menu_is_open: bool,
 4761        cx: &mut Context<Self>,
 4762    ) -> bool {
 4763        let position = self.selections.newest_anchor().head();
 4764        let multibuffer = self.buffer.read(cx);
 4765        let Some(buffer) = position
 4766            .buffer_id
 4767            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4768        else {
 4769            return false;
 4770        };
 4771
 4772        if let Some(completion_provider) = &self.completion_provider {
 4773            completion_provider.is_completion_trigger(
 4774                &buffer,
 4775                position.text_anchor,
 4776                text,
 4777                trigger_in_words,
 4778                menu_is_open,
 4779                cx,
 4780            )
 4781        } else {
 4782            false
 4783        }
 4784    }
 4785
 4786    /// If any empty selections is touching the start of its innermost containing autoclose
 4787    /// region, expand it to select the brackets.
 4788    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4789        let selections = self.selections.all::<usize>(cx);
 4790        let buffer = self.buffer.read(cx).read(cx);
 4791        let new_selections = self
 4792            .selections_with_autoclose_regions(selections, &buffer)
 4793            .map(|(mut selection, region)| {
 4794                if !selection.is_empty() {
 4795                    return selection;
 4796                }
 4797
 4798                if let Some(region) = region {
 4799                    let mut range = region.range.to_offset(&buffer);
 4800                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4801                        range.start -= region.pair.start.len();
 4802                        if buffer.contains_str_at(range.start, &region.pair.start)
 4803                            && buffer.contains_str_at(range.end, &region.pair.end)
 4804                        {
 4805                            range.end += region.pair.end.len();
 4806                            selection.start = range.start;
 4807                            selection.end = range.end;
 4808
 4809                            return selection;
 4810                        }
 4811                    }
 4812                }
 4813
 4814                let always_treat_brackets_as_autoclosed = buffer
 4815                    .language_settings_at(selection.start, cx)
 4816                    .always_treat_brackets_as_autoclosed;
 4817
 4818                if !always_treat_brackets_as_autoclosed {
 4819                    return selection;
 4820                }
 4821
 4822                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4823                    for (pair, enabled) in scope.brackets() {
 4824                        if !enabled || !pair.close {
 4825                            continue;
 4826                        }
 4827
 4828                        if buffer.contains_str_at(selection.start, &pair.end) {
 4829                            let pair_start_len = pair.start.len();
 4830                            if buffer.contains_str_at(
 4831                                selection.start.saturating_sub(pair_start_len),
 4832                                &pair.start,
 4833                            ) {
 4834                                selection.start -= pair_start_len;
 4835                                selection.end += pair.end.len();
 4836
 4837                                return selection;
 4838                            }
 4839                        }
 4840                    }
 4841                }
 4842
 4843                selection
 4844            })
 4845            .collect();
 4846
 4847        drop(buffer);
 4848        self.change_selections(None, window, cx, |selections| {
 4849            selections.select(new_selections)
 4850        });
 4851    }
 4852
 4853    /// Iterate the given selections, and for each one, find the smallest surrounding
 4854    /// autoclose region. This uses the ordering of the selections and the autoclose
 4855    /// regions to avoid repeated comparisons.
 4856    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4857        &'a self,
 4858        selections: impl IntoIterator<Item = Selection<D>>,
 4859        buffer: &'a MultiBufferSnapshot,
 4860    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4861        let mut i = 0;
 4862        let mut regions = self.autoclose_regions.as_slice();
 4863        selections.into_iter().map(move |selection| {
 4864            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4865
 4866            let mut enclosing = None;
 4867            while let Some(pair_state) = regions.get(i) {
 4868                if pair_state.range.end.to_offset(buffer) < range.start {
 4869                    regions = &regions[i + 1..];
 4870                    i = 0;
 4871                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4872                    break;
 4873                } else {
 4874                    if pair_state.selection_id == selection.id {
 4875                        enclosing = Some(pair_state);
 4876                    }
 4877                    i += 1;
 4878                }
 4879            }
 4880
 4881            (selection, enclosing)
 4882        })
 4883    }
 4884
 4885    /// Remove any autoclose regions that no longer contain their selection.
 4886    fn invalidate_autoclose_regions(
 4887        &mut self,
 4888        mut selections: &[Selection<Anchor>],
 4889        buffer: &MultiBufferSnapshot,
 4890    ) {
 4891        self.autoclose_regions.retain(|state| {
 4892            let mut i = 0;
 4893            while let Some(selection) = selections.get(i) {
 4894                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4895                    selections = &selections[1..];
 4896                    continue;
 4897                }
 4898                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4899                    break;
 4900                }
 4901                if selection.id == state.selection_id {
 4902                    return true;
 4903                } else {
 4904                    i += 1;
 4905                }
 4906            }
 4907            false
 4908        });
 4909    }
 4910
 4911    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4912        let offset = position.to_offset(buffer);
 4913        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4914        if offset > word_range.start && kind == Some(CharKind::Word) {
 4915            Some(
 4916                buffer
 4917                    .text_for_range(word_range.start..offset)
 4918                    .collect::<String>(),
 4919            )
 4920        } else {
 4921            None
 4922        }
 4923    }
 4924
 4925    pub fn toggle_inline_values(
 4926        &mut self,
 4927        _: &ToggleInlineValues,
 4928        _: &mut Window,
 4929        cx: &mut Context<Self>,
 4930    ) {
 4931        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4932
 4933        self.refresh_inline_values(cx);
 4934    }
 4935
 4936    pub fn toggle_inlay_hints(
 4937        &mut self,
 4938        _: &ToggleInlayHints,
 4939        _: &mut Window,
 4940        cx: &mut Context<Self>,
 4941    ) {
 4942        self.refresh_inlay_hints(
 4943            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4944            cx,
 4945        );
 4946    }
 4947
 4948    pub fn inlay_hints_enabled(&self) -> bool {
 4949        self.inlay_hint_cache.enabled
 4950    }
 4951
 4952    pub fn inline_values_enabled(&self) -> bool {
 4953        self.inline_value_cache.enabled
 4954    }
 4955
 4956    #[cfg(any(test, feature = "test-support"))]
 4957    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4958        self.display_map
 4959            .read(cx)
 4960            .current_inlays()
 4961            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4962            .cloned()
 4963            .collect()
 4964    }
 4965
 4966    #[cfg(any(test, feature = "test-support"))]
 4967    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 4968        self.display_map
 4969            .read(cx)
 4970            .current_inlays()
 4971            .cloned()
 4972            .collect()
 4973    }
 4974
 4975    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4976        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4977            return;
 4978        }
 4979
 4980        let reason_description = reason.description();
 4981        let ignore_debounce = matches!(
 4982            reason,
 4983            InlayHintRefreshReason::SettingsChange(_)
 4984                | InlayHintRefreshReason::Toggle(_)
 4985                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4986                | InlayHintRefreshReason::ModifiersChanged(_)
 4987        );
 4988        let (invalidate_cache, required_languages) = match reason {
 4989            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4990                match self.inlay_hint_cache.modifiers_override(enabled) {
 4991                    Some(enabled) => {
 4992                        if enabled {
 4993                            (InvalidationStrategy::RefreshRequested, None)
 4994                        } else {
 4995                            self.splice_inlays(
 4996                                &self
 4997                                    .visible_inlay_hints(cx)
 4998                                    .iter()
 4999                                    .map(|inlay| inlay.id)
 5000                                    .collect::<Vec<InlayId>>(),
 5001                                Vec::new(),
 5002                                cx,
 5003                            );
 5004                            return;
 5005                        }
 5006                    }
 5007                    None => return,
 5008                }
 5009            }
 5010            InlayHintRefreshReason::Toggle(enabled) => {
 5011                if self.inlay_hint_cache.toggle(enabled) {
 5012                    if enabled {
 5013                        (InvalidationStrategy::RefreshRequested, None)
 5014                    } else {
 5015                        self.splice_inlays(
 5016                            &self
 5017                                .visible_inlay_hints(cx)
 5018                                .iter()
 5019                                .map(|inlay| inlay.id)
 5020                                .collect::<Vec<InlayId>>(),
 5021                            Vec::new(),
 5022                            cx,
 5023                        );
 5024                        return;
 5025                    }
 5026                } else {
 5027                    return;
 5028                }
 5029            }
 5030            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5031                match self.inlay_hint_cache.update_settings(
 5032                    &self.buffer,
 5033                    new_settings,
 5034                    self.visible_inlay_hints(cx),
 5035                    cx,
 5036                ) {
 5037                    ControlFlow::Break(Some(InlaySplice {
 5038                        to_remove,
 5039                        to_insert,
 5040                    })) => {
 5041                        self.splice_inlays(&to_remove, to_insert, cx);
 5042                        return;
 5043                    }
 5044                    ControlFlow::Break(None) => return,
 5045                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5046                }
 5047            }
 5048            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5049                if let Some(InlaySplice {
 5050                    to_remove,
 5051                    to_insert,
 5052                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5053                {
 5054                    self.splice_inlays(&to_remove, to_insert, cx);
 5055                }
 5056                self.display_map.update(cx, |display_map, _| {
 5057                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5058                });
 5059                return;
 5060            }
 5061            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5062            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5063                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5064            }
 5065            InlayHintRefreshReason::RefreshRequested => {
 5066                (InvalidationStrategy::RefreshRequested, None)
 5067            }
 5068        };
 5069
 5070        if let Some(InlaySplice {
 5071            to_remove,
 5072            to_insert,
 5073        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5074            reason_description,
 5075            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 5076            invalidate_cache,
 5077            ignore_debounce,
 5078            cx,
 5079        ) {
 5080            self.splice_inlays(&to_remove, to_insert, cx);
 5081        }
 5082    }
 5083
 5084    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5085        self.display_map
 5086            .read(cx)
 5087            .current_inlays()
 5088            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5089            .cloned()
 5090            .collect()
 5091    }
 5092
 5093    pub fn excerpts_for_inlay_hints_query(
 5094        &self,
 5095        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5096        cx: &mut Context<Editor>,
 5097    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5098        let Some(project) = self.project.as_ref() else {
 5099            return HashMap::default();
 5100        };
 5101        let project = project.read(cx);
 5102        let multi_buffer = self.buffer().read(cx);
 5103        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5104        let multi_buffer_visible_start = self
 5105            .scroll_manager
 5106            .anchor()
 5107            .anchor
 5108            .to_point(&multi_buffer_snapshot);
 5109        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5110            multi_buffer_visible_start
 5111                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5112            Bias::Left,
 5113        );
 5114        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5115        multi_buffer_snapshot
 5116            .range_to_buffer_ranges(multi_buffer_visible_range)
 5117            .into_iter()
 5118            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5119            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5120                let buffer_file = project::File::from_dyn(buffer.file())?;
 5121                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5122                let worktree_entry = buffer_worktree
 5123                    .read(cx)
 5124                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5125                if worktree_entry.is_ignored {
 5126                    return None;
 5127                }
 5128
 5129                let language = buffer.language()?;
 5130                if let Some(restrict_to_languages) = restrict_to_languages {
 5131                    if !restrict_to_languages.contains(language) {
 5132                        return None;
 5133                    }
 5134                }
 5135                Some((
 5136                    excerpt_id,
 5137                    (
 5138                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5139                        buffer.version().clone(),
 5140                        excerpt_visible_range,
 5141                    ),
 5142                ))
 5143            })
 5144            .collect()
 5145    }
 5146
 5147    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5148        TextLayoutDetails {
 5149            text_system: window.text_system().clone(),
 5150            editor_style: self.style.clone().unwrap(),
 5151            rem_size: window.rem_size(),
 5152            scroll_anchor: self.scroll_manager.anchor(),
 5153            visible_rows: self.visible_line_count(),
 5154            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5155        }
 5156    }
 5157
 5158    pub fn splice_inlays(
 5159        &self,
 5160        to_remove: &[InlayId],
 5161        to_insert: Vec<Inlay>,
 5162        cx: &mut Context<Self>,
 5163    ) {
 5164        self.display_map.update(cx, |display_map, cx| {
 5165            display_map.splice_inlays(to_remove, to_insert, cx)
 5166        });
 5167        cx.notify();
 5168    }
 5169
 5170    fn trigger_on_type_formatting(
 5171        &self,
 5172        input: String,
 5173        window: &mut Window,
 5174        cx: &mut Context<Self>,
 5175    ) -> Option<Task<Result<()>>> {
 5176        if input.len() != 1 {
 5177            return None;
 5178        }
 5179
 5180        let project = self.project.as_ref()?;
 5181        let position = self.selections.newest_anchor().head();
 5182        let (buffer, buffer_position) = self
 5183            .buffer
 5184            .read(cx)
 5185            .text_anchor_for_position(position, cx)?;
 5186
 5187        let settings = language_settings::language_settings(
 5188            buffer
 5189                .read(cx)
 5190                .language_at(buffer_position)
 5191                .map(|l| l.name()),
 5192            buffer.read(cx).file(),
 5193            cx,
 5194        );
 5195        if !settings.use_on_type_format {
 5196            return None;
 5197        }
 5198
 5199        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5200        // hence we do LSP request & edit on host side only — add formats to host's history.
 5201        let push_to_lsp_host_history = true;
 5202        // If this is not the host, append its history with new edits.
 5203        let push_to_client_history = project.read(cx).is_via_collab();
 5204
 5205        let on_type_formatting = project.update(cx, |project, cx| {
 5206            project.on_type_format(
 5207                buffer.clone(),
 5208                buffer_position,
 5209                input,
 5210                push_to_lsp_host_history,
 5211                cx,
 5212            )
 5213        });
 5214        Some(cx.spawn_in(window, async move |editor, cx| {
 5215            if let Some(transaction) = on_type_formatting.await? {
 5216                if push_to_client_history {
 5217                    buffer
 5218                        .update(cx, |buffer, _| {
 5219                            buffer.push_transaction(transaction, Instant::now());
 5220                            buffer.finalize_last_transaction();
 5221                        })
 5222                        .ok();
 5223                }
 5224                editor.update(cx, |editor, cx| {
 5225                    editor.refresh_document_highlights(cx);
 5226                })?;
 5227            }
 5228            Ok(())
 5229        }))
 5230    }
 5231
 5232    pub fn show_word_completions(
 5233        &mut self,
 5234        _: &ShowWordCompletions,
 5235        window: &mut Window,
 5236        cx: &mut Context<Self>,
 5237    ) {
 5238        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5239    }
 5240
 5241    pub fn show_completions(
 5242        &mut self,
 5243        options: &ShowCompletions,
 5244        window: &mut Window,
 5245        cx: &mut Context<Self>,
 5246    ) {
 5247        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5248    }
 5249
 5250    fn open_or_update_completions_menu(
 5251        &mut self,
 5252        requested_source: Option<CompletionsMenuSource>,
 5253        trigger: Option<&str>,
 5254        window: &mut Window,
 5255        cx: &mut Context<Self>,
 5256    ) {
 5257        if self.pending_rename.is_some() {
 5258            return;
 5259        }
 5260
 5261        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5262
 5263        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5264        // inserted and selected. To handle that case, the start of the selection is used so that
 5265        // the menu starts with all choices.
 5266        let position = self
 5267            .selections
 5268            .newest_anchor()
 5269            .start
 5270            .bias_right(&multibuffer_snapshot);
 5271        if position.diff_base_anchor.is_some() {
 5272            return;
 5273        }
 5274        let (buffer, buffer_position) =
 5275            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5276                output
 5277            } else {
 5278                return;
 5279            };
 5280        let buffer_snapshot = buffer.read(cx).snapshot();
 5281
 5282        let query: Option<Arc<String>> =
 5283            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5284
 5285        drop(multibuffer_snapshot);
 5286
 5287        let provider = match requested_source {
 5288            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5289            Some(CompletionsMenuSource::Words) => None,
 5290            Some(CompletionsMenuSource::SnippetChoices) => {
 5291                log::error!("bug: SnippetChoices requested_source is not handled");
 5292                None
 5293            }
 5294        };
 5295
 5296        let sort_completions = provider
 5297            .as_ref()
 5298            .map_or(false, |provider| provider.sort_completions());
 5299
 5300        let filter_completions = provider
 5301            .as_ref()
 5302            .map_or(true, |provider| provider.filter_completions());
 5303
 5304        let trigger_kind = match trigger {
 5305            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5306                CompletionTriggerKind::TRIGGER_CHARACTER
 5307            }
 5308            _ => CompletionTriggerKind::INVOKED,
 5309        };
 5310        let completion_context = CompletionContext {
 5311            trigger_character: trigger.and_then(|trigger| {
 5312                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5313                    Some(String::from(trigger))
 5314                } else {
 5315                    None
 5316                }
 5317            }),
 5318            trigger_kind,
 5319        };
 5320
 5321        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5322        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5323        // involve trigger chars, so this is skipped in that case.
 5324        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5325        {
 5326            let menu_is_open = matches!(
 5327                self.context_menu.borrow().as_ref(),
 5328                Some(CodeContextMenu::Completions(_))
 5329            );
 5330            if menu_is_open {
 5331                self.hide_context_menu(window, cx);
 5332            }
 5333        }
 5334
 5335        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5336            if filter_completions {
 5337                menu.filter(query.clone(), provider.clone(), window, cx);
 5338            }
 5339            // When `is_incomplete` is false, no need to re-query completions when the current query
 5340            // is a suffix of the initial query.
 5341            if !menu.is_incomplete {
 5342                // If the new query is a suffix of the old query (typing more characters) and
 5343                // the previous result was complete, the existing completions can be filtered.
 5344                //
 5345                // Note that this is always true for snippet completions.
 5346                let query_matches = match (&menu.initial_query, &query) {
 5347                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5348                    (None, _) => true,
 5349                    _ => false,
 5350                };
 5351                if query_matches {
 5352                    let position_matches = if menu.initial_position == position {
 5353                        true
 5354                    } else {
 5355                        let snapshot = self.buffer.read(cx).read(cx);
 5356                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5357                    };
 5358                    if position_matches {
 5359                        return;
 5360                    }
 5361                }
 5362            }
 5363        };
 5364
 5365        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5366            buffer_snapshot.surrounding_word(buffer_position)
 5367        {
 5368            let word_to_exclude = buffer_snapshot
 5369                .text_for_range(word_range.clone())
 5370                .collect::<String>();
 5371            (
 5372                buffer_snapshot.anchor_before(word_range.start)
 5373                    ..buffer_snapshot.anchor_after(buffer_position),
 5374                Some(word_to_exclude),
 5375            )
 5376        } else {
 5377            (buffer_position..buffer_position, None)
 5378        };
 5379
 5380        let language = buffer_snapshot
 5381            .language_at(buffer_position)
 5382            .map(|language| language.name());
 5383
 5384        let completion_settings =
 5385            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5386
 5387        let show_completion_documentation = buffer_snapshot
 5388            .settings_at(buffer_position, cx)
 5389            .show_completion_documentation;
 5390
 5391        // The document can be large, so stay in reasonable bounds when searching for words,
 5392        // otherwise completion pop-up might be slow to appear.
 5393        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5394        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5395        let min_word_search = buffer_snapshot.clip_point(
 5396            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5397            Bias::Left,
 5398        );
 5399        let max_word_search = buffer_snapshot.clip_point(
 5400            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5401            Bias::Right,
 5402        );
 5403        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5404            ..buffer_snapshot.point_to_offset(max_word_search);
 5405
 5406        let skip_digits = query
 5407            .as_ref()
 5408            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5409
 5410        let (mut words, provider_responses) = match &provider {
 5411            Some(provider) => {
 5412                let provider_responses = provider.completions(
 5413                    position.excerpt_id,
 5414                    &buffer,
 5415                    buffer_position,
 5416                    completion_context,
 5417                    window,
 5418                    cx,
 5419                );
 5420
 5421                let words = match completion_settings.words {
 5422                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5423                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5424                        .background_spawn(async move {
 5425                            buffer_snapshot.words_in_range(WordsQuery {
 5426                                fuzzy_contents: None,
 5427                                range: word_search_range,
 5428                                skip_digits,
 5429                            })
 5430                        }),
 5431                };
 5432
 5433                (words, provider_responses)
 5434            }
 5435            None => (
 5436                cx.background_spawn(async move {
 5437                    buffer_snapshot.words_in_range(WordsQuery {
 5438                        fuzzy_contents: None,
 5439                        range: word_search_range,
 5440                        skip_digits,
 5441                    })
 5442                }),
 5443                Task::ready(Ok(Vec::new())),
 5444            ),
 5445        };
 5446
 5447        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5448
 5449        let id = post_inc(&mut self.next_completion_id);
 5450        let task = cx.spawn_in(window, async move |editor, cx| {
 5451            let Ok(()) = editor.update(cx, |this, _| {
 5452                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5453            }) else {
 5454                return;
 5455            };
 5456
 5457            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5458            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5459            let mut completions = Vec::new();
 5460            let mut is_incomplete = false;
 5461            if let Some(provider_responses) = provider_responses.await.log_err() {
 5462                if !provider_responses.is_empty() {
 5463                    for response in provider_responses {
 5464                        completions.extend(response.completions);
 5465                        is_incomplete = is_incomplete || response.is_incomplete;
 5466                    }
 5467                    if completion_settings.words == WordsCompletionMode::Fallback {
 5468                        words = Task::ready(BTreeMap::default());
 5469                    }
 5470                }
 5471            }
 5472
 5473            let mut words = words.await;
 5474            if let Some(word_to_exclude) = &word_to_exclude {
 5475                words.remove(word_to_exclude);
 5476            }
 5477            for lsp_completion in &completions {
 5478                words.remove(&lsp_completion.new_text);
 5479            }
 5480            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5481                replace_range: word_replace_range.clone(),
 5482                new_text: word.clone(),
 5483                label: CodeLabel::plain(word, None),
 5484                icon_path: None,
 5485                documentation: None,
 5486                source: CompletionSource::BufferWord {
 5487                    word_range,
 5488                    resolved: false,
 5489                },
 5490                insert_text_mode: Some(InsertTextMode::AS_IS),
 5491                confirm: None,
 5492            }));
 5493
 5494            let menu = if completions.is_empty() {
 5495                None
 5496            } else {
 5497                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5498                    let languages = editor
 5499                        .workspace
 5500                        .as_ref()
 5501                        .and_then(|(workspace, _)| workspace.upgrade())
 5502                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5503                    let menu = CompletionsMenu::new(
 5504                        id,
 5505                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5506                        sort_completions,
 5507                        show_completion_documentation,
 5508                        position,
 5509                        query.clone(),
 5510                        is_incomplete,
 5511                        buffer.clone(),
 5512                        completions.into(),
 5513                        snippet_sort_order,
 5514                        languages,
 5515                        language,
 5516                        cx,
 5517                    );
 5518
 5519                    let query = if filter_completions { query } else { None };
 5520                    let matches_task = if let Some(query) = query {
 5521                        menu.do_async_filtering(query, cx)
 5522                    } else {
 5523                        Task::ready(menu.unfiltered_matches())
 5524                    };
 5525                    (menu, matches_task)
 5526                }) else {
 5527                    return;
 5528                };
 5529
 5530                let matches = matches_task.await;
 5531
 5532                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5533                    // Newer menu already set, so exit.
 5534                    match editor.context_menu.borrow().as_ref() {
 5535                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5536                            if prev_menu.id > id {
 5537                                return;
 5538                            }
 5539                        }
 5540                        _ => {}
 5541                    };
 5542
 5543                    // Only valid to take prev_menu because it the new menu is immediately set
 5544                    // below, or the menu is hidden.
 5545                    match editor.context_menu.borrow_mut().take() {
 5546                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5547                            let position_matches =
 5548                                if prev_menu.initial_position == menu.initial_position {
 5549                                    true
 5550                                } else {
 5551                                    let snapshot = editor.buffer.read(cx).read(cx);
 5552                                    prev_menu.initial_position.to_offset(&snapshot)
 5553                                        == menu.initial_position.to_offset(&snapshot)
 5554                                };
 5555                            if position_matches {
 5556                                // Preserve markdown cache before `set_filter_results` because it will
 5557                                // try to populate the documentation cache.
 5558                                menu.preserve_markdown_cache(prev_menu);
 5559                            }
 5560                        }
 5561                        _ => {}
 5562                    };
 5563
 5564                    menu.set_filter_results(matches, provider, window, cx);
 5565                }) else {
 5566                    return;
 5567                };
 5568
 5569                menu.visible().then_some(menu)
 5570            };
 5571
 5572            editor
 5573                .update_in(cx, |editor, window, cx| {
 5574                    if editor.focus_handle.is_focused(window) {
 5575                        if let Some(menu) = menu {
 5576                            *editor.context_menu.borrow_mut() =
 5577                                Some(CodeContextMenu::Completions(menu));
 5578
 5579                            crate::hover_popover::hide_hover(editor, cx);
 5580                            if editor.show_edit_predictions_in_menu() {
 5581                                editor.update_visible_inline_completion(window, cx);
 5582                            } else {
 5583                                editor.discard_inline_completion(false, cx);
 5584                            }
 5585
 5586                            cx.notify();
 5587                            return;
 5588                        }
 5589                    }
 5590
 5591                    if editor.completion_tasks.len() <= 1 {
 5592                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5593                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5594                        // If it was already hidden and we don't show inline completions in the menu, we should
 5595                        // also show the inline-completion when available.
 5596                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5597                            editor.update_visible_inline_completion(window, cx);
 5598                        }
 5599                    }
 5600                })
 5601                .ok();
 5602        });
 5603
 5604        self.completion_tasks.push((id, task));
 5605    }
 5606
 5607    #[cfg(feature = "test-support")]
 5608    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5609        let menu = self.context_menu.borrow();
 5610        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5611            let completions = menu.completions.borrow();
 5612            Some(completions.to_vec())
 5613        } else {
 5614            None
 5615        }
 5616    }
 5617
 5618    pub fn with_completions_menu_matching_id<R>(
 5619        &self,
 5620        id: CompletionId,
 5621        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5622    ) -> R {
 5623        let mut context_menu = self.context_menu.borrow_mut();
 5624        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5625            return f(None);
 5626        };
 5627        if completions_menu.id != id {
 5628            return f(None);
 5629        }
 5630        f(Some(completions_menu))
 5631    }
 5632
 5633    pub fn confirm_completion(
 5634        &mut self,
 5635        action: &ConfirmCompletion,
 5636        window: &mut Window,
 5637        cx: &mut Context<Self>,
 5638    ) -> Option<Task<Result<()>>> {
 5639        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5640        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5641    }
 5642
 5643    pub fn confirm_completion_insert(
 5644        &mut self,
 5645        _: &ConfirmCompletionInsert,
 5646        window: &mut Window,
 5647        cx: &mut Context<Self>,
 5648    ) -> Option<Task<Result<()>>> {
 5649        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5650        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5651    }
 5652
 5653    pub fn confirm_completion_replace(
 5654        &mut self,
 5655        _: &ConfirmCompletionReplace,
 5656        window: &mut Window,
 5657        cx: &mut Context<Self>,
 5658    ) -> Option<Task<Result<()>>> {
 5659        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5660        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5661    }
 5662
 5663    pub fn compose_completion(
 5664        &mut self,
 5665        action: &ComposeCompletion,
 5666        window: &mut Window,
 5667        cx: &mut Context<Self>,
 5668    ) -> Option<Task<Result<()>>> {
 5669        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5670        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5671    }
 5672
 5673    fn do_completion(
 5674        &mut self,
 5675        item_ix: Option<usize>,
 5676        intent: CompletionIntent,
 5677        window: &mut Window,
 5678        cx: &mut Context<Editor>,
 5679    ) -> Option<Task<Result<()>>> {
 5680        use language::ToOffset as _;
 5681
 5682        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5683        else {
 5684            return None;
 5685        };
 5686
 5687        let candidate_id = {
 5688            let entries = completions_menu.entries.borrow();
 5689            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5690            if self.show_edit_predictions_in_menu() {
 5691                self.discard_inline_completion(true, cx);
 5692            }
 5693            mat.candidate_id
 5694        };
 5695
 5696        let completion = completions_menu
 5697            .completions
 5698            .borrow()
 5699            .get(candidate_id)?
 5700            .clone();
 5701        cx.stop_propagation();
 5702
 5703        let buffer_handle = completions_menu.buffer.clone();
 5704
 5705        let CompletionEdit {
 5706            new_text,
 5707            snippet,
 5708            replace_range,
 5709        } = process_completion_for_edit(
 5710            &completion,
 5711            intent,
 5712            &buffer_handle,
 5713            &completions_menu.initial_position.text_anchor,
 5714            cx,
 5715        );
 5716
 5717        let buffer = buffer_handle.read(cx);
 5718        let snapshot = self.buffer.read(cx).snapshot(cx);
 5719        let newest_anchor = self.selections.newest_anchor();
 5720        let replace_range_multibuffer = {
 5721            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5722            let multibuffer_anchor = snapshot
 5723                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5724                .unwrap()
 5725                ..snapshot
 5726                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5727                    .unwrap();
 5728            multibuffer_anchor.start.to_offset(&snapshot)
 5729                ..multibuffer_anchor.end.to_offset(&snapshot)
 5730        };
 5731        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5732            return None;
 5733        }
 5734
 5735        let old_text = buffer
 5736            .text_for_range(replace_range.clone())
 5737            .collect::<String>();
 5738        let lookbehind = newest_anchor
 5739            .start
 5740            .text_anchor
 5741            .to_offset(buffer)
 5742            .saturating_sub(replace_range.start);
 5743        let lookahead = replace_range
 5744            .end
 5745            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5746        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5747        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5748
 5749        let selections = self.selections.all::<usize>(cx);
 5750        let mut ranges = Vec::new();
 5751        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5752
 5753        for selection in &selections {
 5754            let range = if selection.id == newest_anchor.id {
 5755                replace_range_multibuffer.clone()
 5756            } else {
 5757                let mut range = selection.range();
 5758
 5759                // if prefix is present, don't duplicate it
 5760                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5761                    range.start = range.start.saturating_sub(lookbehind);
 5762
 5763                    // if suffix is also present, mimic the newest cursor and replace it
 5764                    if selection.id != newest_anchor.id
 5765                        && snapshot.contains_str_at(range.end, suffix)
 5766                    {
 5767                        range.end += lookahead;
 5768                    }
 5769                }
 5770                range
 5771            };
 5772
 5773            ranges.push(range.clone());
 5774
 5775            if !self.linked_edit_ranges.is_empty() {
 5776                let start_anchor = snapshot.anchor_before(range.start);
 5777                let end_anchor = snapshot.anchor_after(range.end);
 5778                if let Some(ranges) = self
 5779                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5780                {
 5781                    for (buffer, edits) in ranges {
 5782                        linked_edits
 5783                            .entry(buffer.clone())
 5784                            .or_default()
 5785                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5786                    }
 5787                }
 5788            }
 5789        }
 5790
 5791        let common_prefix_len = old_text
 5792            .chars()
 5793            .zip(new_text.chars())
 5794            .take_while(|(a, b)| a == b)
 5795            .map(|(a, _)| a.len_utf8())
 5796            .sum::<usize>();
 5797
 5798        cx.emit(EditorEvent::InputHandled {
 5799            utf16_range_to_replace: None,
 5800            text: new_text[common_prefix_len..].into(),
 5801        });
 5802
 5803        self.transact(window, cx, |this, window, cx| {
 5804            if let Some(mut snippet) = snippet {
 5805                snippet.text = new_text.to_string();
 5806                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5807            } else {
 5808                this.buffer.update(cx, |buffer, cx| {
 5809                    let auto_indent = match completion.insert_text_mode {
 5810                        Some(InsertTextMode::AS_IS) => None,
 5811                        _ => this.autoindent_mode.clone(),
 5812                    };
 5813                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5814                    buffer.edit(edits, auto_indent, cx);
 5815                });
 5816            }
 5817            for (buffer, edits) in linked_edits {
 5818                buffer.update(cx, |buffer, cx| {
 5819                    let snapshot = buffer.snapshot();
 5820                    let edits = edits
 5821                        .into_iter()
 5822                        .map(|(range, text)| {
 5823                            use text::ToPoint as TP;
 5824                            let end_point = TP::to_point(&range.end, &snapshot);
 5825                            let start_point = TP::to_point(&range.start, &snapshot);
 5826                            (start_point..end_point, text)
 5827                        })
 5828                        .sorted_by_key(|(range, _)| range.start);
 5829                    buffer.edit(edits, None, cx);
 5830                })
 5831            }
 5832
 5833            this.refresh_inline_completion(true, false, window, cx);
 5834        });
 5835
 5836        let show_new_completions_on_confirm = completion
 5837            .confirm
 5838            .as_ref()
 5839            .map_or(false, |confirm| confirm(intent, window, cx));
 5840        if show_new_completions_on_confirm {
 5841            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5842        }
 5843
 5844        let provider = self.completion_provider.as_ref()?;
 5845        drop(completion);
 5846        let apply_edits = provider.apply_additional_edits_for_completion(
 5847            buffer_handle,
 5848            completions_menu.completions.clone(),
 5849            candidate_id,
 5850            true,
 5851            cx,
 5852        );
 5853
 5854        let editor_settings = EditorSettings::get_global(cx);
 5855        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5856            // After the code completion is finished, users often want to know what signatures are needed.
 5857            // so we should automatically call signature_help
 5858            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5859        }
 5860
 5861        Some(cx.foreground_executor().spawn(async move {
 5862            apply_edits.await?;
 5863            Ok(())
 5864        }))
 5865    }
 5866
 5867    pub fn toggle_code_actions(
 5868        &mut self,
 5869        action: &ToggleCodeActions,
 5870        window: &mut Window,
 5871        cx: &mut Context<Self>,
 5872    ) {
 5873        let quick_launch = action.quick_launch;
 5874        let mut context_menu = self.context_menu.borrow_mut();
 5875        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5876            if code_actions.deployed_from == action.deployed_from {
 5877                // Toggle if we're selecting the same one
 5878                *context_menu = None;
 5879                cx.notify();
 5880                return;
 5881            } else {
 5882                // Otherwise, clear it and start a new one
 5883                *context_menu = None;
 5884                cx.notify();
 5885            }
 5886        }
 5887        drop(context_menu);
 5888        let snapshot = self.snapshot(window, cx);
 5889        let deployed_from = action.deployed_from.clone();
 5890        let action = action.clone();
 5891        self.completion_tasks.clear();
 5892        self.discard_inline_completion(false, cx);
 5893
 5894        let multibuffer_point = match &action.deployed_from {
 5895            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5896                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5897            }
 5898            _ => self.selections.newest::<Point>(cx).head(),
 5899        };
 5900        let Some((buffer, buffer_row)) = snapshot
 5901            .buffer_snapshot
 5902            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5903            .and_then(|(buffer_snapshot, range)| {
 5904                self.buffer()
 5905                    .read(cx)
 5906                    .buffer(buffer_snapshot.remote_id())
 5907                    .map(|buffer| (buffer, range.start.row))
 5908            })
 5909        else {
 5910            return;
 5911        };
 5912        let buffer_id = buffer.read(cx).remote_id();
 5913        let tasks = self
 5914            .tasks
 5915            .get(&(buffer_id, buffer_row))
 5916            .map(|t| Arc::new(t.to_owned()));
 5917
 5918        if !self.focus_handle.is_focused(window) {
 5919            return;
 5920        }
 5921        let project = self.project.clone();
 5922
 5923        let code_actions_task = match deployed_from {
 5924            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5925            _ => self.code_actions(buffer_row, window, cx),
 5926        };
 5927
 5928        let runnable_task = match deployed_from {
 5929            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5930            _ => {
 5931                let mut task_context_task = Task::ready(None);
 5932                if let Some(tasks) = &tasks {
 5933                    if let Some(project) = project {
 5934                        task_context_task =
 5935                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5936                    }
 5937                }
 5938
 5939                cx.spawn_in(window, {
 5940                    let buffer = buffer.clone();
 5941                    async move |editor, cx| {
 5942                        let task_context = task_context_task.await;
 5943
 5944                        let resolved_tasks =
 5945                            tasks
 5946                                .zip(task_context.clone())
 5947                                .map(|(tasks, task_context)| ResolvedTasks {
 5948                                    templates: tasks.resolve(&task_context).collect(),
 5949                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5950                                        multibuffer_point.row,
 5951                                        tasks.column,
 5952                                    )),
 5953                                });
 5954                        let debug_scenarios = editor
 5955                            .update(cx, |editor, cx| {
 5956                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5957                            })?
 5958                            .await;
 5959                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5960                    }
 5961                })
 5962            }
 5963        };
 5964
 5965        cx.spawn_in(window, async move |editor, cx| {
 5966            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5967            let code_actions = code_actions_task.await;
 5968            let spawn_straight_away = quick_launch
 5969                && resolved_tasks
 5970                    .as_ref()
 5971                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5972                && code_actions
 5973                    .as_ref()
 5974                    .map_or(true, |actions| actions.is_empty())
 5975                && debug_scenarios.is_empty();
 5976
 5977            editor.update_in(cx, |editor, window, cx| {
 5978                crate::hover_popover::hide_hover(editor, cx);
 5979                let actions = CodeActionContents::new(
 5980                    resolved_tasks,
 5981                    code_actions,
 5982                    debug_scenarios,
 5983                    task_context.unwrap_or_default(),
 5984                );
 5985
 5986                // Don't show the menu if there are no actions available
 5987                if actions.is_empty() {
 5988                    cx.notify();
 5989                    return Task::ready(Ok(()));
 5990                }
 5991
 5992                *editor.context_menu.borrow_mut() =
 5993                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5994                        buffer,
 5995                        actions,
 5996                        selected_item: Default::default(),
 5997                        scroll_handle: UniformListScrollHandle::default(),
 5998                        deployed_from,
 5999                    }));
 6000                cx.notify();
 6001                if spawn_straight_away {
 6002                    if let Some(task) = editor.confirm_code_action(
 6003                        &ConfirmCodeAction { item_ix: Some(0) },
 6004                        window,
 6005                        cx,
 6006                    ) {
 6007                        return task;
 6008                    }
 6009                }
 6010
 6011                Task::ready(Ok(()))
 6012            })
 6013        })
 6014        .detach_and_log_err(cx);
 6015    }
 6016
 6017    fn debug_scenarios(
 6018        &mut self,
 6019        resolved_tasks: &Option<ResolvedTasks>,
 6020        buffer: &Entity<Buffer>,
 6021        cx: &mut App,
 6022    ) -> Task<Vec<task::DebugScenario>> {
 6023        maybe!({
 6024            let project = self.project.as_ref()?;
 6025            let dap_store = project.read(cx).dap_store();
 6026            let mut scenarios = vec![];
 6027            let resolved_tasks = resolved_tasks.as_ref()?;
 6028            let buffer = buffer.read(cx);
 6029            let language = buffer.language()?;
 6030            let file = buffer.file();
 6031            let debug_adapter = language_settings(language.name().into(), file, cx)
 6032                .debuggers
 6033                .first()
 6034                .map(SharedString::from)
 6035                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6036
 6037            dap_store.update(cx, |dap_store, cx| {
 6038                for (_, task) in &resolved_tasks.templates {
 6039                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6040                        task.original_task().clone(),
 6041                        debug_adapter.clone().into(),
 6042                        task.display_label().to_owned().into(),
 6043                        cx,
 6044                    );
 6045                    scenarios.push(maybe_scenario);
 6046                }
 6047            });
 6048            Some(cx.background_spawn(async move {
 6049                let scenarios = futures::future::join_all(scenarios)
 6050                    .await
 6051                    .into_iter()
 6052                    .flatten()
 6053                    .collect::<Vec<_>>();
 6054                scenarios
 6055            }))
 6056        })
 6057        .unwrap_or_else(|| Task::ready(vec![]))
 6058    }
 6059
 6060    fn code_actions(
 6061        &mut self,
 6062        buffer_row: u32,
 6063        window: &mut Window,
 6064        cx: &mut Context<Self>,
 6065    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6066        let mut task = self.code_actions_task.take();
 6067        cx.spawn_in(window, async move |editor, cx| {
 6068            while let Some(prev_task) = task {
 6069                prev_task.await.log_err();
 6070                task = editor
 6071                    .update(cx, |this, _| this.code_actions_task.take())
 6072                    .ok()?;
 6073            }
 6074
 6075            editor
 6076                .update(cx, |editor, cx| {
 6077                    editor
 6078                        .available_code_actions
 6079                        .clone()
 6080                        .and_then(|(location, code_actions)| {
 6081                            let snapshot = location.buffer.read(cx).snapshot();
 6082                            let point_range = location.range.to_point(&snapshot);
 6083                            let point_range = point_range.start.row..=point_range.end.row;
 6084                            if point_range.contains(&buffer_row) {
 6085                                Some(code_actions)
 6086                            } else {
 6087                                None
 6088                            }
 6089                        })
 6090                })
 6091                .ok()
 6092                .flatten()
 6093        })
 6094    }
 6095
 6096    pub fn confirm_code_action(
 6097        &mut self,
 6098        action: &ConfirmCodeAction,
 6099        window: &mut Window,
 6100        cx: &mut Context<Self>,
 6101    ) -> Option<Task<Result<()>>> {
 6102        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6103
 6104        let actions_menu =
 6105            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6106                menu
 6107            } else {
 6108                return None;
 6109            };
 6110
 6111        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6112        let action = actions_menu.actions.get(action_ix)?;
 6113        let title = action.label();
 6114        let buffer = actions_menu.buffer;
 6115        let workspace = self.workspace()?;
 6116
 6117        match action {
 6118            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6119                workspace.update(cx, |workspace, cx| {
 6120                    workspace.schedule_resolved_task(
 6121                        task_source_kind,
 6122                        resolved_task,
 6123                        false,
 6124                        window,
 6125                        cx,
 6126                    );
 6127
 6128                    Some(Task::ready(Ok(())))
 6129                })
 6130            }
 6131            CodeActionsItem::CodeAction {
 6132                excerpt_id,
 6133                action,
 6134                provider,
 6135            } => {
 6136                let apply_code_action =
 6137                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6138                let workspace = workspace.downgrade();
 6139                Some(cx.spawn_in(window, async move |editor, cx| {
 6140                    let project_transaction = apply_code_action.await?;
 6141                    Self::open_project_transaction(
 6142                        &editor,
 6143                        workspace,
 6144                        project_transaction,
 6145                        title,
 6146                        cx,
 6147                    )
 6148                    .await
 6149                }))
 6150            }
 6151            CodeActionsItem::DebugScenario(scenario) => {
 6152                let context = actions_menu.actions.context.clone();
 6153
 6154                workspace.update(cx, |workspace, cx| {
 6155                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6156                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6157                });
 6158                Some(Task::ready(Ok(())))
 6159            }
 6160        }
 6161    }
 6162
 6163    pub async fn open_project_transaction(
 6164        this: &WeakEntity<Editor>,
 6165        workspace: WeakEntity<Workspace>,
 6166        transaction: ProjectTransaction,
 6167        title: String,
 6168        cx: &mut AsyncWindowContext,
 6169    ) -> Result<()> {
 6170        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6171        cx.update(|_, cx| {
 6172            entries.sort_unstable_by_key(|(buffer, _)| {
 6173                buffer.read(cx).file().map(|f| f.path().clone())
 6174            });
 6175        })?;
 6176
 6177        // If the project transaction's edits are all contained within this editor, then
 6178        // avoid opening a new editor to display them.
 6179
 6180        if let Some((buffer, transaction)) = entries.first() {
 6181            if entries.len() == 1 {
 6182                let excerpt = this.update(cx, |editor, cx| {
 6183                    editor
 6184                        .buffer()
 6185                        .read(cx)
 6186                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6187                })?;
 6188                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6189                    if excerpted_buffer == *buffer {
 6190                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6191                            let excerpt_range = excerpt_range.to_offset(buffer);
 6192                            buffer
 6193                                .edited_ranges_for_transaction::<usize>(transaction)
 6194                                .all(|range| {
 6195                                    excerpt_range.start <= range.start
 6196                                        && excerpt_range.end >= range.end
 6197                                })
 6198                        })?;
 6199
 6200                        if all_edits_within_excerpt {
 6201                            return Ok(());
 6202                        }
 6203                    }
 6204                }
 6205            }
 6206        } else {
 6207            return Ok(());
 6208        }
 6209
 6210        let mut ranges_to_highlight = Vec::new();
 6211        let excerpt_buffer = cx.new(|cx| {
 6212            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6213            for (buffer_handle, transaction) in &entries {
 6214                let edited_ranges = buffer_handle
 6215                    .read(cx)
 6216                    .edited_ranges_for_transaction::<Point>(transaction)
 6217                    .collect::<Vec<_>>();
 6218                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6219                    PathKey::for_buffer(buffer_handle, cx),
 6220                    buffer_handle.clone(),
 6221                    edited_ranges,
 6222                    DEFAULT_MULTIBUFFER_CONTEXT,
 6223                    cx,
 6224                );
 6225
 6226                ranges_to_highlight.extend(ranges);
 6227            }
 6228            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6229            multibuffer
 6230        })?;
 6231
 6232        workspace.update_in(cx, |workspace, window, cx| {
 6233            let project = workspace.project().clone();
 6234            let editor =
 6235                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6236            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6237            editor.update(cx, |editor, cx| {
 6238                editor.highlight_background::<Self>(
 6239                    &ranges_to_highlight,
 6240                    |theme| theme.colors().editor_highlighted_line_background,
 6241                    cx,
 6242                );
 6243            });
 6244        })?;
 6245
 6246        Ok(())
 6247    }
 6248
 6249    pub fn clear_code_action_providers(&mut self) {
 6250        self.code_action_providers.clear();
 6251        self.available_code_actions.take();
 6252    }
 6253
 6254    pub fn add_code_action_provider(
 6255        &mut self,
 6256        provider: Rc<dyn CodeActionProvider>,
 6257        window: &mut Window,
 6258        cx: &mut Context<Self>,
 6259    ) {
 6260        if self
 6261            .code_action_providers
 6262            .iter()
 6263            .any(|existing_provider| existing_provider.id() == provider.id())
 6264        {
 6265            return;
 6266        }
 6267
 6268        self.code_action_providers.push(provider);
 6269        self.refresh_code_actions(window, cx);
 6270    }
 6271
 6272    pub fn remove_code_action_provider(
 6273        &mut self,
 6274        id: Arc<str>,
 6275        window: &mut Window,
 6276        cx: &mut Context<Self>,
 6277    ) {
 6278        self.code_action_providers
 6279            .retain(|provider| provider.id() != id);
 6280        self.refresh_code_actions(window, cx);
 6281    }
 6282
 6283    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6284        !self.code_action_providers.is_empty()
 6285            && EditorSettings::get_global(cx).toolbar.code_actions
 6286    }
 6287
 6288    pub fn has_available_code_actions(&self) -> bool {
 6289        self.available_code_actions
 6290            .as_ref()
 6291            .is_some_and(|(_, actions)| !actions.is_empty())
 6292    }
 6293
 6294    fn render_inline_code_actions(
 6295        &self,
 6296        icon_size: ui::IconSize,
 6297        display_row: DisplayRow,
 6298        is_active: bool,
 6299        cx: &mut Context<Self>,
 6300    ) -> AnyElement {
 6301        let show_tooltip = !self.context_menu_visible();
 6302        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6303            .icon_size(icon_size)
 6304            .shape(ui::IconButtonShape::Square)
 6305            .style(ButtonStyle::Transparent)
 6306            .icon_color(ui::Color::Hidden)
 6307            .toggle_state(is_active)
 6308            .when(show_tooltip, |this| {
 6309                this.tooltip({
 6310                    let focus_handle = self.focus_handle.clone();
 6311                    move |window, cx| {
 6312                        Tooltip::for_action_in(
 6313                            "Toggle Code Actions",
 6314                            &ToggleCodeActions {
 6315                                deployed_from: None,
 6316                                quick_launch: false,
 6317                            },
 6318                            &focus_handle,
 6319                            window,
 6320                            cx,
 6321                        )
 6322                    }
 6323                })
 6324            })
 6325            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6326                window.focus(&editor.focus_handle(cx));
 6327                editor.toggle_code_actions(
 6328                    &crate::actions::ToggleCodeActions {
 6329                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6330                            display_row,
 6331                        )),
 6332                        quick_launch: false,
 6333                    },
 6334                    window,
 6335                    cx,
 6336                );
 6337            }))
 6338            .into_any_element()
 6339    }
 6340
 6341    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6342        &self.context_menu
 6343    }
 6344
 6345    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6346        let newest_selection = self.selections.newest_anchor().clone();
 6347        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6348        let buffer = self.buffer.read(cx);
 6349        if newest_selection.head().diff_base_anchor.is_some() {
 6350            return None;
 6351        }
 6352        let (start_buffer, start) =
 6353            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6354        let (end_buffer, end) =
 6355            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6356        if start_buffer != end_buffer {
 6357            return None;
 6358        }
 6359
 6360        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6361            cx.background_executor()
 6362                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6363                .await;
 6364
 6365            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6366                let providers = this.code_action_providers.clone();
 6367                let tasks = this
 6368                    .code_action_providers
 6369                    .iter()
 6370                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6371                    .collect::<Vec<_>>();
 6372                (providers, tasks)
 6373            })?;
 6374
 6375            let mut actions = Vec::new();
 6376            for (provider, provider_actions) in
 6377                providers.into_iter().zip(future::join_all(tasks).await)
 6378            {
 6379                if let Some(provider_actions) = provider_actions.log_err() {
 6380                    actions.extend(provider_actions.into_iter().map(|action| {
 6381                        AvailableCodeAction {
 6382                            excerpt_id: newest_selection.start.excerpt_id,
 6383                            action,
 6384                            provider: provider.clone(),
 6385                        }
 6386                    }));
 6387                }
 6388            }
 6389
 6390            this.update(cx, |this, cx| {
 6391                this.available_code_actions = if actions.is_empty() {
 6392                    None
 6393                } else {
 6394                    Some((
 6395                        Location {
 6396                            buffer: start_buffer,
 6397                            range: start..end,
 6398                        },
 6399                        actions.into(),
 6400                    ))
 6401                };
 6402                cx.notify();
 6403            })
 6404        }));
 6405        None
 6406    }
 6407
 6408    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6409        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6410            self.show_git_blame_inline = false;
 6411
 6412            self.show_git_blame_inline_delay_task =
 6413                Some(cx.spawn_in(window, async move |this, cx| {
 6414                    cx.background_executor().timer(delay).await;
 6415
 6416                    this.update(cx, |this, cx| {
 6417                        this.show_git_blame_inline = true;
 6418                        cx.notify();
 6419                    })
 6420                    .log_err();
 6421                }));
 6422        }
 6423    }
 6424
 6425    fn show_blame_popover(
 6426        &mut self,
 6427        blame_entry: &BlameEntry,
 6428        position: gpui::Point<Pixels>,
 6429        cx: &mut Context<Self>,
 6430    ) {
 6431        if let Some(state) = &mut self.inline_blame_popover {
 6432            state.hide_task.take();
 6433        } else {
 6434            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6435            let blame_entry = blame_entry.clone();
 6436            let show_task = cx.spawn(async move |editor, cx| {
 6437                cx.background_executor()
 6438                    .timer(std::time::Duration::from_millis(delay))
 6439                    .await;
 6440                editor
 6441                    .update(cx, |editor, cx| {
 6442                        editor.inline_blame_popover_show_task.take();
 6443                        let Some(blame) = editor.blame.as_ref() else {
 6444                            return;
 6445                        };
 6446                        let blame = blame.read(cx);
 6447                        let details = blame.details_for_entry(&blame_entry);
 6448                        let markdown = cx.new(|cx| {
 6449                            Markdown::new(
 6450                                details
 6451                                    .as_ref()
 6452                                    .map(|message| message.message.clone())
 6453                                    .unwrap_or_default(),
 6454                                None,
 6455                                None,
 6456                                cx,
 6457                            )
 6458                        });
 6459                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6460                            position,
 6461                            hide_task: None,
 6462                            popover_bounds: None,
 6463                            popover_state: InlineBlamePopoverState {
 6464                                scroll_handle: ScrollHandle::new(),
 6465                                commit_message: details,
 6466                                markdown,
 6467                            },
 6468                        });
 6469                        cx.notify();
 6470                    })
 6471                    .ok();
 6472            });
 6473            self.inline_blame_popover_show_task = Some(show_task);
 6474        }
 6475    }
 6476
 6477    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6478        self.inline_blame_popover_show_task.take();
 6479        if let Some(state) = &mut self.inline_blame_popover {
 6480            let hide_task = cx.spawn(async move |editor, cx| {
 6481                cx.background_executor()
 6482                    .timer(std::time::Duration::from_millis(100))
 6483                    .await;
 6484                editor
 6485                    .update(cx, |editor, cx| {
 6486                        editor.inline_blame_popover.take();
 6487                        cx.notify();
 6488                    })
 6489                    .ok();
 6490            });
 6491            state.hide_task = Some(hide_task);
 6492        }
 6493    }
 6494
 6495    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6496        if self.pending_rename.is_some() {
 6497            return None;
 6498        }
 6499
 6500        let provider = self.semantics_provider.clone()?;
 6501        let buffer = self.buffer.read(cx);
 6502        let newest_selection = self.selections.newest_anchor().clone();
 6503        let cursor_position = newest_selection.head();
 6504        let (cursor_buffer, cursor_buffer_position) =
 6505            buffer.text_anchor_for_position(cursor_position, cx)?;
 6506        let (tail_buffer, tail_buffer_position) =
 6507            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6508        if cursor_buffer != tail_buffer {
 6509            return None;
 6510        }
 6511
 6512        let snapshot = cursor_buffer.read(cx).snapshot();
 6513        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6514        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6515        if start_word_range != end_word_range {
 6516            self.document_highlights_task.take();
 6517            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6518            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6519            return None;
 6520        }
 6521
 6522        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6523        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6524            cx.background_executor()
 6525                .timer(Duration::from_millis(debounce))
 6526                .await;
 6527
 6528            let highlights = if let Some(highlights) = cx
 6529                .update(|cx| {
 6530                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6531                })
 6532                .ok()
 6533                .flatten()
 6534            {
 6535                highlights.await.log_err()
 6536            } else {
 6537                None
 6538            };
 6539
 6540            if let Some(highlights) = highlights {
 6541                this.update(cx, |this, cx| {
 6542                    if this.pending_rename.is_some() {
 6543                        return;
 6544                    }
 6545
 6546                    let buffer_id = cursor_position.buffer_id;
 6547                    let buffer = this.buffer.read(cx);
 6548                    if !buffer
 6549                        .text_anchor_for_position(cursor_position, cx)
 6550                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6551                    {
 6552                        return;
 6553                    }
 6554
 6555                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6556                    let mut write_ranges = Vec::new();
 6557                    let mut read_ranges = Vec::new();
 6558                    for highlight in highlights {
 6559                        for (excerpt_id, excerpt_range) in
 6560                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6561                        {
 6562                            let start = highlight
 6563                                .range
 6564                                .start
 6565                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6566                            let end = highlight
 6567                                .range
 6568                                .end
 6569                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6570                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6571                                continue;
 6572                            }
 6573
 6574                            let range = Anchor {
 6575                                buffer_id,
 6576                                excerpt_id,
 6577                                text_anchor: start,
 6578                                diff_base_anchor: None,
 6579                            }..Anchor {
 6580                                buffer_id,
 6581                                excerpt_id,
 6582                                text_anchor: end,
 6583                                diff_base_anchor: None,
 6584                            };
 6585                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6586                                write_ranges.push(range);
 6587                            } else {
 6588                                read_ranges.push(range);
 6589                            }
 6590                        }
 6591                    }
 6592
 6593                    this.highlight_background::<DocumentHighlightRead>(
 6594                        &read_ranges,
 6595                        |theme| theme.colors().editor_document_highlight_read_background,
 6596                        cx,
 6597                    );
 6598                    this.highlight_background::<DocumentHighlightWrite>(
 6599                        &write_ranges,
 6600                        |theme| theme.colors().editor_document_highlight_write_background,
 6601                        cx,
 6602                    );
 6603                    cx.notify();
 6604                })
 6605                .log_err();
 6606            }
 6607        }));
 6608        None
 6609    }
 6610
 6611    fn prepare_highlight_query_from_selection(
 6612        &mut self,
 6613        cx: &mut Context<Editor>,
 6614    ) -> Option<(String, Range<Anchor>)> {
 6615        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6616            return None;
 6617        }
 6618        if !EditorSettings::get_global(cx).selection_highlight {
 6619            return None;
 6620        }
 6621        if self.selections.count() != 1 || self.selections.line_mode {
 6622            return None;
 6623        }
 6624        let selection = self.selections.newest::<Point>(cx);
 6625        if selection.is_empty() || selection.start.row != selection.end.row {
 6626            return None;
 6627        }
 6628        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6629        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6630        let query = multi_buffer_snapshot
 6631            .text_for_range(selection_anchor_range.clone())
 6632            .collect::<String>();
 6633        if query.trim().is_empty() {
 6634            return None;
 6635        }
 6636        Some((query, selection_anchor_range))
 6637    }
 6638
 6639    fn update_selection_occurrence_highlights(
 6640        &mut self,
 6641        query_text: String,
 6642        query_range: Range<Anchor>,
 6643        multi_buffer_range_to_query: Range<Point>,
 6644        use_debounce: bool,
 6645        window: &mut Window,
 6646        cx: &mut Context<Editor>,
 6647    ) -> Task<()> {
 6648        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6649        cx.spawn_in(window, async move |editor, cx| {
 6650            if use_debounce {
 6651                cx.background_executor()
 6652                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6653                    .await;
 6654            }
 6655            let match_task = cx.background_spawn(async move {
 6656                let buffer_ranges = multi_buffer_snapshot
 6657                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6658                    .into_iter()
 6659                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6660                let mut match_ranges = Vec::new();
 6661                let Ok(regex) = project::search::SearchQuery::text(
 6662                    query_text.clone(),
 6663                    false,
 6664                    false,
 6665                    false,
 6666                    Default::default(),
 6667                    Default::default(),
 6668                    false,
 6669                    None,
 6670                ) else {
 6671                    return Vec::default();
 6672                };
 6673                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6674                    match_ranges.extend(
 6675                        regex
 6676                            .search(&buffer_snapshot, Some(search_range.clone()))
 6677                            .await
 6678                            .into_iter()
 6679                            .filter_map(|match_range| {
 6680                                let match_start = buffer_snapshot
 6681                                    .anchor_after(search_range.start + match_range.start);
 6682                                let match_end = buffer_snapshot
 6683                                    .anchor_before(search_range.start + match_range.end);
 6684                                let match_anchor_range = Anchor::range_in_buffer(
 6685                                    excerpt_id,
 6686                                    buffer_snapshot.remote_id(),
 6687                                    match_start..match_end,
 6688                                );
 6689                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6690                            }),
 6691                    );
 6692                }
 6693                match_ranges
 6694            });
 6695            let match_ranges = match_task.await;
 6696            editor
 6697                .update_in(cx, |editor, _, cx| {
 6698                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6699                    if !match_ranges.is_empty() {
 6700                        editor.highlight_background::<SelectedTextHighlight>(
 6701                            &match_ranges,
 6702                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6703                            cx,
 6704                        )
 6705                    }
 6706                })
 6707                .log_err();
 6708        })
 6709    }
 6710
 6711    fn refresh_selected_text_highlights(
 6712        &mut self,
 6713        on_buffer_edit: bool,
 6714        window: &mut Window,
 6715        cx: &mut Context<Editor>,
 6716    ) {
 6717        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6718        else {
 6719            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6720            self.quick_selection_highlight_task.take();
 6721            self.debounced_selection_highlight_task.take();
 6722            return;
 6723        };
 6724        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6725        if on_buffer_edit
 6726            || self
 6727                .quick_selection_highlight_task
 6728                .as_ref()
 6729                .map_or(true, |(prev_anchor_range, _)| {
 6730                    prev_anchor_range != &query_range
 6731                })
 6732        {
 6733            let multi_buffer_visible_start = self
 6734                .scroll_manager
 6735                .anchor()
 6736                .anchor
 6737                .to_point(&multi_buffer_snapshot);
 6738            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6739                multi_buffer_visible_start
 6740                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6741                Bias::Left,
 6742            );
 6743            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6744            self.quick_selection_highlight_task = Some((
 6745                query_range.clone(),
 6746                self.update_selection_occurrence_highlights(
 6747                    query_text.clone(),
 6748                    query_range.clone(),
 6749                    multi_buffer_visible_range,
 6750                    false,
 6751                    window,
 6752                    cx,
 6753                ),
 6754            ));
 6755        }
 6756        if on_buffer_edit
 6757            || self
 6758                .debounced_selection_highlight_task
 6759                .as_ref()
 6760                .map_or(true, |(prev_anchor_range, _)| {
 6761                    prev_anchor_range != &query_range
 6762                })
 6763        {
 6764            let multi_buffer_start = multi_buffer_snapshot
 6765                .anchor_before(0)
 6766                .to_point(&multi_buffer_snapshot);
 6767            let multi_buffer_end = multi_buffer_snapshot
 6768                .anchor_after(multi_buffer_snapshot.len())
 6769                .to_point(&multi_buffer_snapshot);
 6770            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6771            self.debounced_selection_highlight_task = Some((
 6772                query_range.clone(),
 6773                self.update_selection_occurrence_highlights(
 6774                    query_text,
 6775                    query_range,
 6776                    multi_buffer_full_range,
 6777                    true,
 6778                    window,
 6779                    cx,
 6780                ),
 6781            ));
 6782        }
 6783    }
 6784
 6785    pub fn refresh_inline_completion(
 6786        &mut self,
 6787        debounce: bool,
 6788        user_requested: bool,
 6789        window: &mut Window,
 6790        cx: &mut Context<Self>,
 6791    ) -> Option<()> {
 6792        let provider = self.edit_prediction_provider()?;
 6793        let cursor = self.selections.newest_anchor().head();
 6794        let (buffer, cursor_buffer_position) =
 6795            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6796
 6797        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6798            self.discard_inline_completion(false, cx);
 6799            return None;
 6800        }
 6801
 6802        if !user_requested
 6803            && (!self.should_show_edit_predictions()
 6804                || !self.is_focused(window)
 6805                || buffer.read(cx).is_empty())
 6806        {
 6807            self.discard_inline_completion(false, cx);
 6808            return None;
 6809        }
 6810
 6811        self.update_visible_inline_completion(window, cx);
 6812        provider.refresh(
 6813            self.project.clone(),
 6814            buffer,
 6815            cursor_buffer_position,
 6816            debounce,
 6817            cx,
 6818        );
 6819        Some(())
 6820    }
 6821
 6822    fn show_edit_predictions_in_menu(&self) -> bool {
 6823        match self.edit_prediction_settings {
 6824            EditPredictionSettings::Disabled => false,
 6825            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6826        }
 6827    }
 6828
 6829    pub fn edit_predictions_enabled(&self) -> bool {
 6830        match self.edit_prediction_settings {
 6831            EditPredictionSettings::Disabled => false,
 6832            EditPredictionSettings::Enabled { .. } => true,
 6833        }
 6834    }
 6835
 6836    fn edit_prediction_requires_modifier(&self) -> bool {
 6837        match self.edit_prediction_settings {
 6838            EditPredictionSettings::Disabled => false,
 6839            EditPredictionSettings::Enabled {
 6840                preview_requires_modifier,
 6841                ..
 6842            } => preview_requires_modifier,
 6843        }
 6844    }
 6845
 6846    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6847        if self.edit_prediction_provider.is_none() {
 6848            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6849        } else {
 6850            let selection = self.selections.newest_anchor();
 6851            let cursor = selection.head();
 6852
 6853            if let Some((buffer, cursor_buffer_position)) =
 6854                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6855            {
 6856                self.edit_prediction_settings =
 6857                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6858            }
 6859        }
 6860    }
 6861
 6862    fn edit_prediction_settings_at_position(
 6863        &self,
 6864        buffer: &Entity<Buffer>,
 6865        buffer_position: language::Anchor,
 6866        cx: &App,
 6867    ) -> EditPredictionSettings {
 6868        if !self.mode.is_full()
 6869            || !self.show_inline_completions_override.unwrap_or(true)
 6870            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6871        {
 6872            return EditPredictionSettings::Disabled;
 6873        }
 6874
 6875        let buffer = buffer.read(cx);
 6876
 6877        let file = buffer.file();
 6878
 6879        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6880            return EditPredictionSettings::Disabled;
 6881        };
 6882
 6883        let by_provider = matches!(
 6884            self.menu_inline_completions_policy,
 6885            MenuInlineCompletionsPolicy::ByProvider
 6886        );
 6887
 6888        let show_in_menu = by_provider
 6889            && self
 6890                .edit_prediction_provider
 6891                .as_ref()
 6892                .map_or(false, |provider| {
 6893                    provider.provider.show_completions_in_menu()
 6894                });
 6895
 6896        let preview_requires_modifier =
 6897            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6898
 6899        EditPredictionSettings::Enabled {
 6900            show_in_menu,
 6901            preview_requires_modifier,
 6902        }
 6903    }
 6904
 6905    fn should_show_edit_predictions(&self) -> bool {
 6906        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6907    }
 6908
 6909    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6910        matches!(
 6911            self.edit_prediction_preview,
 6912            EditPredictionPreview::Active { .. }
 6913        )
 6914    }
 6915
 6916    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6917        let cursor = self.selections.newest_anchor().head();
 6918        if let Some((buffer, cursor_position)) =
 6919            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6920        {
 6921            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6922        } else {
 6923            false
 6924        }
 6925    }
 6926
 6927    pub fn supports_minimap(&self, cx: &App) -> bool {
 6928        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6929    }
 6930
 6931    fn edit_predictions_enabled_in_buffer(
 6932        &self,
 6933        buffer: &Entity<Buffer>,
 6934        buffer_position: language::Anchor,
 6935        cx: &App,
 6936    ) -> bool {
 6937        maybe!({
 6938            if self.read_only(cx) {
 6939                return Some(false);
 6940            }
 6941            let provider = self.edit_prediction_provider()?;
 6942            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6943                return Some(false);
 6944            }
 6945            let buffer = buffer.read(cx);
 6946            let Some(file) = buffer.file() else {
 6947                return Some(true);
 6948            };
 6949            let settings = all_language_settings(Some(file), cx);
 6950            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6951        })
 6952        .unwrap_or(false)
 6953    }
 6954
 6955    fn cycle_inline_completion(
 6956        &mut self,
 6957        direction: Direction,
 6958        window: &mut Window,
 6959        cx: &mut Context<Self>,
 6960    ) -> Option<()> {
 6961        let provider = self.edit_prediction_provider()?;
 6962        let cursor = self.selections.newest_anchor().head();
 6963        let (buffer, cursor_buffer_position) =
 6964            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6965        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6966            return None;
 6967        }
 6968
 6969        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6970        self.update_visible_inline_completion(window, cx);
 6971
 6972        Some(())
 6973    }
 6974
 6975    pub fn show_inline_completion(
 6976        &mut self,
 6977        _: &ShowEditPrediction,
 6978        window: &mut Window,
 6979        cx: &mut Context<Self>,
 6980    ) {
 6981        if !self.has_active_inline_completion() {
 6982            self.refresh_inline_completion(false, true, window, cx);
 6983            return;
 6984        }
 6985
 6986        self.update_visible_inline_completion(window, cx);
 6987    }
 6988
 6989    pub fn display_cursor_names(
 6990        &mut self,
 6991        _: &DisplayCursorNames,
 6992        window: &mut Window,
 6993        cx: &mut Context<Self>,
 6994    ) {
 6995        self.show_cursor_names(window, cx);
 6996    }
 6997
 6998    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6999        self.show_cursor_names = true;
 7000        cx.notify();
 7001        cx.spawn_in(window, async move |this, cx| {
 7002            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7003            this.update(cx, |this, cx| {
 7004                this.show_cursor_names = false;
 7005                cx.notify()
 7006            })
 7007            .ok()
 7008        })
 7009        .detach();
 7010    }
 7011
 7012    pub fn next_edit_prediction(
 7013        &mut self,
 7014        _: &NextEditPrediction,
 7015        window: &mut Window,
 7016        cx: &mut Context<Self>,
 7017    ) {
 7018        if self.has_active_inline_completion() {
 7019            self.cycle_inline_completion(Direction::Next, window, cx);
 7020        } else {
 7021            let is_copilot_disabled = self
 7022                .refresh_inline_completion(false, true, window, cx)
 7023                .is_none();
 7024            if is_copilot_disabled {
 7025                cx.propagate();
 7026            }
 7027        }
 7028    }
 7029
 7030    pub fn previous_edit_prediction(
 7031        &mut self,
 7032        _: &PreviousEditPrediction,
 7033        window: &mut Window,
 7034        cx: &mut Context<Self>,
 7035    ) {
 7036        if self.has_active_inline_completion() {
 7037            self.cycle_inline_completion(Direction::Prev, window, cx);
 7038        } else {
 7039            let is_copilot_disabled = self
 7040                .refresh_inline_completion(false, true, window, cx)
 7041                .is_none();
 7042            if is_copilot_disabled {
 7043                cx.propagate();
 7044            }
 7045        }
 7046    }
 7047
 7048    pub fn accept_edit_prediction(
 7049        &mut self,
 7050        _: &AcceptEditPrediction,
 7051        window: &mut Window,
 7052        cx: &mut Context<Self>,
 7053    ) {
 7054        if self.show_edit_predictions_in_menu() {
 7055            self.hide_context_menu(window, cx);
 7056        }
 7057
 7058        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7059            return;
 7060        };
 7061
 7062        self.report_inline_completion_event(
 7063            active_inline_completion.completion_id.clone(),
 7064            true,
 7065            cx,
 7066        );
 7067
 7068        match &active_inline_completion.completion {
 7069            InlineCompletion::Move { target, .. } => {
 7070                let target = *target;
 7071
 7072                if let Some(position_map) = &self.last_position_map {
 7073                    if position_map
 7074                        .visible_row_range
 7075                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7076                        || !self.edit_prediction_requires_modifier()
 7077                    {
 7078                        self.unfold_ranges(&[target..target], true, false, cx);
 7079                        // Note that this is also done in vim's handler of the Tab action.
 7080                        self.change_selections(
 7081                            Some(Autoscroll::newest()),
 7082                            window,
 7083                            cx,
 7084                            |selections| {
 7085                                selections.select_anchor_ranges([target..target]);
 7086                            },
 7087                        );
 7088                        self.clear_row_highlights::<EditPredictionPreview>();
 7089
 7090                        self.edit_prediction_preview
 7091                            .set_previous_scroll_position(None);
 7092                    } else {
 7093                        self.edit_prediction_preview
 7094                            .set_previous_scroll_position(Some(
 7095                                position_map.snapshot.scroll_anchor,
 7096                            ));
 7097
 7098                        self.highlight_rows::<EditPredictionPreview>(
 7099                            target..target,
 7100                            cx.theme().colors().editor_highlighted_line_background,
 7101                            RowHighlightOptions {
 7102                                autoscroll: true,
 7103                                ..Default::default()
 7104                            },
 7105                            cx,
 7106                        );
 7107                        self.request_autoscroll(Autoscroll::fit(), cx);
 7108                    }
 7109                }
 7110            }
 7111            InlineCompletion::Edit { edits, .. } => {
 7112                if let Some(provider) = self.edit_prediction_provider() {
 7113                    provider.accept(cx);
 7114                }
 7115
 7116                // Store the transaction ID and selections before applying the edit
 7117                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7118
 7119                let snapshot = self.buffer.read(cx).snapshot(cx);
 7120                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7121
 7122                self.buffer.update(cx, |buffer, cx| {
 7123                    buffer.edit(edits.iter().cloned(), None, cx)
 7124                });
 7125
 7126                self.change_selections(None, window, cx, |s| {
 7127                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7128                });
 7129
 7130                let selections = self.selections.disjoint_anchors();
 7131                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7132                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7133                    if has_new_transaction {
 7134                        self.selection_history
 7135                            .insert_transaction(transaction_id_now, selections);
 7136                    }
 7137                }
 7138
 7139                self.update_visible_inline_completion(window, cx);
 7140                if self.active_inline_completion.is_none() {
 7141                    self.refresh_inline_completion(true, true, window, cx);
 7142                }
 7143
 7144                cx.notify();
 7145            }
 7146        }
 7147
 7148        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7149    }
 7150
 7151    pub fn accept_partial_inline_completion(
 7152        &mut self,
 7153        _: &AcceptPartialEditPrediction,
 7154        window: &mut Window,
 7155        cx: &mut Context<Self>,
 7156    ) {
 7157        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7158            return;
 7159        };
 7160        if self.selections.count() != 1 {
 7161            return;
 7162        }
 7163
 7164        self.report_inline_completion_event(
 7165            active_inline_completion.completion_id.clone(),
 7166            true,
 7167            cx,
 7168        );
 7169
 7170        match &active_inline_completion.completion {
 7171            InlineCompletion::Move { target, .. } => {
 7172                let target = *target;
 7173                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7174                    selections.select_anchor_ranges([target..target]);
 7175                });
 7176            }
 7177            InlineCompletion::Edit { edits, .. } => {
 7178                // Find an insertion that starts at the cursor position.
 7179                let snapshot = self.buffer.read(cx).snapshot(cx);
 7180                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7181                let insertion = edits.iter().find_map(|(range, text)| {
 7182                    let range = range.to_offset(&snapshot);
 7183                    if range.is_empty() && range.start == cursor_offset {
 7184                        Some(text)
 7185                    } else {
 7186                        None
 7187                    }
 7188                });
 7189
 7190                if let Some(text) = insertion {
 7191                    let mut partial_completion = text
 7192                        .chars()
 7193                        .by_ref()
 7194                        .take_while(|c| c.is_alphabetic())
 7195                        .collect::<String>();
 7196                    if partial_completion.is_empty() {
 7197                        partial_completion = text
 7198                            .chars()
 7199                            .by_ref()
 7200                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7201                            .collect::<String>();
 7202                    }
 7203
 7204                    cx.emit(EditorEvent::InputHandled {
 7205                        utf16_range_to_replace: None,
 7206                        text: partial_completion.clone().into(),
 7207                    });
 7208
 7209                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7210
 7211                    self.refresh_inline_completion(true, true, window, cx);
 7212                    cx.notify();
 7213                } else {
 7214                    self.accept_edit_prediction(&Default::default(), window, cx);
 7215                }
 7216            }
 7217        }
 7218    }
 7219
 7220    fn discard_inline_completion(
 7221        &mut self,
 7222        should_report_inline_completion_event: bool,
 7223        cx: &mut Context<Self>,
 7224    ) -> bool {
 7225        if should_report_inline_completion_event {
 7226            let completion_id = self
 7227                .active_inline_completion
 7228                .as_ref()
 7229                .and_then(|active_completion| active_completion.completion_id.clone());
 7230
 7231            self.report_inline_completion_event(completion_id, false, cx);
 7232        }
 7233
 7234        if let Some(provider) = self.edit_prediction_provider() {
 7235            provider.discard(cx);
 7236        }
 7237
 7238        self.take_active_inline_completion(cx)
 7239    }
 7240
 7241    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7242        let Some(provider) = self.edit_prediction_provider() else {
 7243            return;
 7244        };
 7245
 7246        let Some((_, buffer, _)) = self
 7247            .buffer
 7248            .read(cx)
 7249            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7250        else {
 7251            return;
 7252        };
 7253
 7254        let extension = buffer
 7255            .read(cx)
 7256            .file()
 7257            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7258
 7259        let event_type = match accepted {
 7260            true => "Edit Prediction Accepted",
 7261            false => "Edit Prediction Discarded",
 7262        };
 7263        telemetry::event!(
 7264            event_type,
 7265            provider = provider.name(),
 7266            prediction_id = id,
 7267            suggestion_accepted = accepted,
 7268            file_extension = extension,
 7269        );
 7270    }
 7271
 7272    pub fn has_active_inline_completion(&self) -> bool {
 7273        self.active_inline_completion.is_some()
 7274    }
 7275
 7276    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7277        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7278            return false;
 7279        };
 7280
 7281        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7282        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7283        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7284        true
 7285    }
 7286
 7287    /// Returns true when we're displaying the edit prediction popover below the cursor
 7288    /// like we are not previewing and the LSP autocomplete menu is visible
 7289    /// or we are in `when_holding_modifier` mode.
 7290    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7291        if self.edit_prediction_preview_is_active()
 7292            || !self.show_edit_predictions_in_menu()
 7293            || !self.edit_predictions_enabled()
 7294        {
 7295            return false;
 7296        }
 7297
 7298        if self.has_visible_completions_menu() {
 7299            return true;
 7300        }
 7301
 7302        has_completion && self.edit_prediction_requires_modifier()
 7303    }
 7304
 7305    fn handle_modifiers_changed(
 7306        &mut self,
 7307        modifiers: Modifiers,
 7308        position_map: &PositionMap,
 7309        window: &mut Window,
 7310        cx: &mut Context<Self>,
 7311    ) {
 7312        if self.show_edit_predictions_in_menu() {
 7313            self.update_edit_prediction_preview(&modifiers, window, cx);
 7314        }
 7315
 7316        self.update_selection_mode(&modifiers, position_map, window, cx);
 7317
 7318        let mouse_position = window.mouse_position();
 7319        if !position_map.text_hitbox.is_hovered(window) {
 7320            return;
 7321        }
 7322
 7323        self.update_hovered_link(
 7324            position_map.point_for_position(mouse_position),
 7325            &position_map.snapshot,
 7326            modifiers,
 7327            window,
 7328            cx,
 7329        )
 7330    }
 7331
 7332    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7333        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7334        if invert {
 7335            match multi_cursor_setting {
 7336                MultiCursorModifier::Alt => modifiers.alt,
 7337                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7338            }
 7339        } else {
 7340            match multi_cursor_setting {
 7341                MultiCursorModifier::Alt => modifiers.secondary(),
 7342                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7343            }
 7344        }
 7345    }
 7346
 7347    fn columnar_selection_mode(
 7348        modifiers: &Modifiers,
 7349        cx: &mut Context<Self>,
 7350    ) -> Option<ColumnarMode> {
 7351        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7352            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7353                Some(ColumnarMode::FromMouse)
 7354            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7355                Some(ColumnarMode::FromSelection)
 7356            } else {
 7357                None
 7358            }
 7359        } else {
 7360            None
 7361        }
 7362    }
 7363
 7364    fn update_selection_mode(
 7365        &mut self,
 7366        modifiers: &Modifiers,
 7367        position_map: &PositionMap,
 7368        window: &mut Window,
 7369        cx: &mut Context<Self>,
 7370    ) {
 7371        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7372            return;
 7373        };
 7374        if self.selections.pending.is_none() {
 7375            return;
 7376        }
 7377
 7378        let mouse_position = window.mouse_position();
 7379        let point_for_position = position_map.point_for_position(mouse_position);
 7380        let position = point_for_position.previous_valid;
 7381
 7382        self.select(
 7383            SelectPhase::BeginColumnar {
 7384                position,
 7385                reset: false,
 7386                mode,
 7387                goal_column: point_for_position.exact_unclipped.column(),
 7388            },
 7389            window,
 7390            cx,
 7391        );
 7392    }
 7393
 7394    fn update_edit_prediction_preview(
 7395        &mut self,
 7396        modifiers: &Modifiers,
 7397        window: &mut Window,
 7398        cx: &mut Context<Self>,
 7399    ) {
 7400        let mut modifiers_held = false;
 7401        if let Some(accept_keystroke) = self
 7402            .accept_edit_prediction_keybind(false, window, cx)
 7403            .keystroke()
 7404        {
 7405            modifiers_held = modifiers_held
 7406                || (&accept_keystroke.modifiers == modifiers
 7407                    && accept_keystroke.modifiers.modified());
 7408        };
 7409        if let Some(accept_partial_keystroke) = self
 7410            .accept_edit_prediction_keybind(true, window, cx)
 7411            .keystroke()
 7412        {
 7413            modifiers_held = modifiers_held
 7414                || (&accept_partial_keystroke.modifiers == modifiers
 7415                    && accept_partial_keystroke.modifiers.modified());
 7416        }
 7417
 7418        if modifiers_held {
 7419            if matches!(
 7420                self.edit_prediction_preview,
 7421                EditPredictionPreview::Inactive { .. }
 7422            ) {
 7423                self.edit_prediction_preview = EditPredictionPreview::Active {
 7424                    previous_scroll_position: None,
 7425                    since: Instant::now(),
 7426                };
 7427
 7428                self.update_visible_inline_completion(window, cx);
 7429                cx.notify();
 7430            }
 7431        } else if let EditPredictionPreview::Active {
 7432            previous_scroll_position,
 7433            since,
 7434        } = self.edit_prediction_preview
 7435        {
 7436            if let (Some(previous_scroll_position), Some(position_map)) =
 7437                (previous_scroll_position, self.last_position_map.as_ref())
 7438            {
 7439                self.set_scroll_position(
 7440                    previous_scroll_position
 7441                        .scroll_position(&position_map.snapshot.display_snapshot),
 7442                    window,
 7443                    cx,
 7444                );
 7445            }
 7446
 7447            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7448                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7449            };
 7450            self.clear_row_highlights::<EditPredictionPreview>();
 7451            self.update_visible_inline_completion(window, cx);
 7452            cx.notify();
 7453        }
 7454    }
 7455
 7456    fn update_visible_inline_completion(
 7457        &mut self,
 7458        _window: &mut Window,
 7459        cx: &mut Context<Self>,
 7460    ) -> Option<()> {
 7461        let selection = self.selections.newest_anchor();
 7462        let cursor = selection.head();
 7463        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7464        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7465        let excerpt_id = cursor.excerpt_id;
 7466
 7467        let show_in_menu = self.show_edit_predictions_in_menu();
 7468        let completions_menu_has_precedence = !show_in_menu
 7469            && (self.context_menu.borrow().is_some()
 7470                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7471
 7472        if completions_menu_has_precedence
 7473            || !offset_selection.is_empty()
 7474            || self
 7475                .active_inline_completion
 7476                .as_ref()
 7477                .map_or(false, |completion| {
 7478                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7479                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7480                    !invalidation_range.contains(&offset_selection.head())
 7481                })
 7482        {
 7483            self.discard_inline_completion(false, cx);
 7484            return None;
 7485        }
 7486
 7487        self.take_active_inline_completion(cx);
 7488        let Some(provider) = self.edit_prediction_provider() else {
 7489            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7490            return None;
 7491        };
 7492
 7493        let (buffer, cursor_buffer_position) =
 7494            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7495
 7496        self.edit_prediction_settings =
 7497            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7498
 7499        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7500
 7501        if self.edit_prediction_indent_conflict {
 7502            let cursor_point = cursor.to_point(&multibuffer);
 7503
 7504            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7505
 7506            if let Some((_, indent)) = indents.iter().next() {
 7507                if indent.len == cursor_point.column {
 7508                    self.edit_prediction_indent_conflict = false;
 7509                }
 7510            }
 7511        }
 7512
 7513        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7514        let edits = inline_completion
 7515            .edits
 7516            .into_iter()
 7517            .flat_map(|(range, new_text)| {
 7518                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7519                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7520                Some((start..end, new_text))
 7521            })
 7522            .collect::<Vec<_>>();
 7523        if edits.is_empty() {
 7524            return None;
 7525        }
 7526
 7527        let first_edit_start = edits.first().unwrap().0.start;
 7528        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7529        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7530
 7531        let last_edit_end = edits.last().unwrap().0.end;
 7532        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7533        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7534
 7535        let cursor_row = cursor.to_point(&multibuffer).row;
 7536
 7537        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7538
 7539        let mut inlay_ids = Vec::new();
 7540        let invalidation_row_range;
 7541        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7542            Some(cursor_row..edit_end_row)
 7543        } else if cursor_row > edit_end_row {
 7544            Some(edit_start_row..cursor_row)
 7545        } else {
 7546            None
 7547        };
 7548        let is_move =
 7549            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7550        let completion = if is_move {
 7551            invalidation_row_range =
 7552                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7553            let target = first_edit_start;
 7554            InlineCompletion::Move { target, snapshot }
 7555        } else {
 7556            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7557                && !self.inline_completions_hidden_for_vim_mode;
 7558
 7559            if show_completions_in_buffer {
 7560                if edits
 7561                    .iter()
 7562                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7563                {
 7564                    let mut inlays = Vec::new();
 7565                    for (range, new_text) in &edits {
 7566                        let inlay = Inlay::inline_completion(
 7567                            post_inc(&mut self.next_inlay_id),
 7568                            range.start,
 7569                            new_text.as_str(),
 7570                        );
 7571                        inlay_ids.push(inlay.id);
 7572                        inlays.push(inlay);
 7573                    }
 7574
 7575                    self.splice_inlays(&[], inlays, cx);
 7576                } else {
 7577                    let background_color = cx.theme().status().deleted_background;
 7578                    self.highlight_text::<InlineCompletionHighlight>(
 7579                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7580                        HighlightStyle {
 7581                            background_color: Some(background_color),
 7582                            ..Default::default()
 7583                        },
 7584                        cx,
 7585                    );
 7586                }
 7587            }
 7588
 7589            invalidation_row_range = edit_start_row..edit_end_row;
 7590
 7591            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7592                if provider.show_tab_accept_marker() {
 7593                    EditDisplayMode::TabAccept
 7594                } else {
 7595                    EditDisplayMode::Inline
 7596                }
 7597            } else {
 7598                EditDisplayMode::DiffPopover
 7599            };
 7600
 7601            InlineCompletion::Edit {
 7602                edits,
 7603                edit_preview: inline_completion.edit_preview,
 7604                display_mode,
 7605                snapshot,
 7606            }
 7607        };
 7608
 7609        let invalidation_range = multibuffer
 7610            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7611            ..multibuffer.anchor_after(Point::new(
 7612                invalidation_row_range.end,
 7613                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7614            ));
 7615
 7616        self.stale_inline_completion_in_menu = None;
 7617        self.active_inline_completion = Some(InlineCompletionState {
 7618            inlay_ids,
 7619            completion,
 7620            completion_id: inline_completion.id,
 7621            invalidation_range,
 7622        });
 7623
 7624        cx.notify();
 7625
 7626        Some(())
 7627    }
 7628
 7629    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7630        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7631    }
 7632
 7633    fn clear_tasks(&mut self) {
 7634        self.tasks.clear()
 7635    }
 7636
 7637    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7638        if self.tasks.insert(key, value).is_some() {
 7639            // This case should hopefully be rare, but just in case...
 7640            log::error!(
 7641                "multiple different run targets found on a single line, only the last target will be rendered"
 7642            )
 7643        }
 7644    }
 7645
 7646    /// Get all display points of breakpoints that will be rendered within editor
 7647    ///
 7648    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7649    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7650    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7651    fn active_breakpoints(
 7652        &self,
 7653        range: Range<DisplayRow>,
 7654        window: &mut Window,
 7655        cx: &mut Context<Self>,
 7656    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7657        let mut breakpoint_display_points = HashMap::default();
 7658
 7659        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7660            return breakpoint_display_points;
 7661        };
 7662
 7663        let snapshot = self.snapshot(window, cx);
 7664
 7665        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7666        let Some(project) = self.project.as_ref() else {
 7667            return breakpoint_display_points;
 7668        };
 7669
 7670        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7671            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7672
 7673        for (buffer_snapshot, range, excerpt_id) in
 7674            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7675        {
 7676            let Some(buffer) = project
 7677                .read(cx)
 7678                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7679            else {
 7680                continue;
 7681            };
 7682            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7683                &buffer,
 7684                Some(
 7685                    buffer_snapshot.anchor_before(range.start)
 7686                        ..buffer_snapshot.anchor_after(range.end),
 7687                ),
 7688                buffer_snapshot,
 7689                cx,
 7690            );
 7691            for (breakpoint, state) in breakpoints {
 7692                let multi_buffer_anchor =
 7693                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7694                let position = multi_buffer_anchor
 7695                    .to_point(&multi_buffer_snapshot)
 7696                    .to_display_point(&snapshot);
 7697
 7698                breakpoint_display_points.insert(
 7699                    position.row(),
 7700                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7701                );
 7702            }
 7703        }
 7704
 7705        breakpoint_display_points
 7706    }
 7707
 7708    fn breakpoint_context_menu(
 7709        &self,
 7710        anchor: Anchor,
 7711        window: &mut Window,
 7712        cx: &mut Context<Self>,
 7713    ) -> Entity<ui::ContextMenu> {
 7714        let weak_editor = cx.weak_entity();
 7715        let focus_handle = self.focus_handle(cx);
 7716
 7717        let row = self
 7718            .buffer
 7719            .read(cx)
 7720            .snapshot(cx)
 7721            .summary_for_anchor::<Point>(&anchor)
 7722            .row;
 7723
 7724        let breakpoint = self
 7725            .breakpoint_at_row(row, window, cx)
 7726            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7727
 7728        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7729            "Edit Log Breakpoint"
 7730        } else {
 7731            "Set Log Breakpoint"
 7732        };
 7733
 7734        let condition_breakpoint_msg = if breakpoint
 7735            .as_ref()
 7736            .is_some_and(|bp| bp.1.condition.is_some())
 7737        {
 7738            "Edit Condition Breakpoint"
 7739        } else {
 7740            "Set Condition Breakpoint"
 7741        };
 7742
 7743        let hit_condition_breakpoint_msg = if breakpoint
 7744            .as_ref()
 7745            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7746        {
 7747            "Edit Hit Condition Breakpoint"
 7748        } else {
 7749            "Set Hit Condition Breakpoint"
 7750        };
 7751
 7752        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7753            "Unset Breakpoint"
 7754        } else {
 7755            "Set Breakpoint"
 7756        };
 7757
 7758        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7759
 7760        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7761            BreakpointState::Enabled => Some("Disable"),
 7762            BreakpointState::Disabled => Some("Enable"),
 7763        });
 7764
 7765        let (anchor, breakpoint) =
 7766            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7767
 7768        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7769            menu.on_blur_subscription(Subscription::new(|| {}))
 7770                .context(focus_handle)
 7771                .when(run_to_cursor, |this| {
 7772                    let weak_editor = weak_editor.clone();
 7773                    this.entry("Run to cursor", None, move |window, cx| {
 7774                        weak_editor
 7775                            .update(cx, |editor, cx| {
 7776                                editor.change_selections(None, window, cx, |s| {
 7777                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7778                                });
 7779                            })
 7780                            .ok();
 7781
 7782                        window.dispatch_action(Box::new(RunToCursor), cx);
 7783                    })
 7784                    .separator()
 7785                })
 7786                .when_some(toggle_state_msg, |this, msg| {
 7787                    this.entry(msg, None, {
 7788                        let weak_editor = weak_editor.clone();
 7789                        let breakpoint = breakpoint.clone();
 7790                        move |_window, cx| {
 7791                            weak_editor
 7792                                .update(cx, |this, cx| {
 7793                                    this.edit_breakpoint_at_anchor(
 7794                                        anchor,
 7795                                        breakpoint.as_ref().clone(),
 7796                                        BreakpointEditAction::InvertState,
 7797                                        cx,
 7798                                    );
 7799                                })
 7800                                .log_err();
 7801                        }
 7802                    })
 7803                })
 7804                .entry(set_breakpoint_msg, None, {
 7805                    let weak_editor = weak_editor.clone();
 7806                    let breakpoint = breakpoint.clone();
 7807                    move |_window, cx| {
 7808                        weak_editor
 7809                            .update(cx, |this, cx| {
 7810                                this.edit_breakpoint_at_anchor(
 7811                                    anchor,
 7812                                    breakpoint.as_ref().clone(),
 7813                                    BreakpointEditAction::Toggle,
 7814                                    cx,
 7815                                );
 7816                            })
 7817                            .log_err();
 7818                    }
 7819                })
 7820                .entry(log_breakpoint_msg, None, {
 7821                    let breakpoint = breakpoint.clone();
 7822                    let weak_editor = weak_editor.clone();
 7823                    move |window, cx| {
 7824                        weak_editor
 7825                            .update(cx, |this, cx| {
 7826                                this.add_edit_breakpoint_block(
 7827                                    anchor,
 7828                                    breakpoint.as_ref(),
 7829                                    BreakpointPromptEditAction::Log,
 7830                                    window,
 7831                                    cx,
 7832                                );
 7833                            })
 7834                            .log_err();
 7835                    }
 7836                })
 7837                .entry(condition_breakpoint_msg, None, {
 7838                    let breakpoint = breakpoint.clone();
 7839                    let weak_editor = weak_editor.clone();
 7840                    move |window, cx| {
 7841                        weak_editor
 7842                            .update(cx, |this, cx| {
 7843                                this.add_edit_breakpoint_block(
 7844                                    anchor,
 7845                                    breakpoint.as_ref(),
 7846                                    BreakpointPromptEditAction::Condition,
 7847                                    window,
 7848                                    cx,
 7849                                );
 7850                            })
 7851                            .log_err();
 7852                    }
 7853                })
 7854                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7855                    weak_editor
 7856                        .update(cx, |this, cx| {
 7857                            this.add_edit_breakpoint_block(
 7858                                anchor,
 7859                                breakpoint.as_ref(),
 7860                                BreakpointPromptEditAction::HitCondition,
 7861                                window,
 7862                                cx,
 7863                            );
 7864                        })
 7865                        .log_err();
 7866                })
 7867        })
 7868    }
 7869
 7870    fn render_breakpoint(
 7871        &self,
 7872        position: Anchor,
 7873        row: DisplayRow,
 7874        breakpoint: &Breakpoint,
 7875        state: Option<BreakpointSessionState>,
 7876        cx: &mut Context<Self>,
 7877    ) -> IconButton {
 7878        let is_rejected = state.is_some_and(|s| !s.verified);
 7879        // Is it a breakpoint that shows up when hovering over gutter?
 7880        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7881            (false, false),
 7882            |PhantomBreakpointIndicator {
 7883                 is_active,
 7884                 display_row,
 7885                 collides_with_existing_breakpoint,
 7886             }| {
 7887                (
 7888                    is_active && display_row == row,
 7889                    collides_with_existing_breakpoint,
 7890                )
 7891            },
 7892        );
 7893
 7894        let (color, icon) = {
 7895            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7896                (false, false) => ui::IconName::DebugBreakpoint,
 7897                (true, false) => ui::IconName::DebugLogBreakpoint,
 7898                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7899                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7900            };
 7901
 7902            let color = if is_phantom {
 7903                Color::Hint
 7904            } else if is_rejected {
 7905                Color::Disabled
 7906            } else {
 7907                Color::Debugger
 7908            };
 7909
 7910            (color, icon)
 7911        };
 7912
 7913        let breakpoint = Arc::from(breakpoint.clone());
 7914
 7915        let alt_as_text = gpui::Keystroke {
 7916            modifiers: Modifiers::secondary_key(),
 7917            ..Default::default()
 7918        };
 7919        let primary_action_text = if breakpoint.is_disabled() {
 7920            "Enable breakpoint"
 7921        } else if is_phantom && !collides_with_existing {
 7922            "Set breakpoint"
 7923        } else {
 7924            "Unset breakpoint"
 7925        };
 7926        let focus_handle = self.focus_handle.clone();
 7927
 7928        let meta = if is_rejected {
 7929            SharedString::from("No executable code is associated with this line.")
 7930        } else if collides_with_existing && !breakpoint.is_disabled() {
 7931            SharedString::from(format!(
 7932                "{alt_as_text}-click to disable,\nright-click for more options."
 7933            ))
 7934        } else {
 7935            SharedString::from("Right-click for more options.")
 7936        };
 7937        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7938            .icon_size(IconSize::XSmall)
 7939            .size(ui::ButtonSize::None)
 7940            .when(is_rejected, |this| {
 7941                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7942            })
 7943            .icon_color(color)
 7944            .style(ButtonStyle::Transparent)
 7945            .on_click(cx.listener({
 7946                let breakpoint = breakpoint.clone();
 7947
 7948                move |editor, event: &ClickEvent, window, cx| {
 7949                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7950                        BreakpointEditAction::InvertState
 7951                    } else {
 7952                        BreakpointEditAction::Toggle
 7953                    };
 7954
 7955                    window.focus(&editor.focus_handle(cx));
 7956                    editor.edit_breakpoint_at_anchor(
 7957                        position,
 7958                        breakpoint.as_ref().clone(),
 7959                        edit_action,
 7960                        cx,
 7961                    );
 7962                }
 7963            }))
 7964            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7965                editor.set_breakpoint_context_menu(
 7966                    row,
 7967                    Some(position),
 7968                    event.down.position,
 7969                    window,
 7970                    cx,
 7971                );
 7972            }))
 7973            .tooltip(move |window, cx| {
 7974                Tooltip::with_meta_in(
 7975                    primary_action_text,
 7976                    Some(&ToggleBreakpoint),
 7977                    meta.clone(),
 7978                    &focus_handle,
 7979                    window,
 7980                    cx,
 7981                )
 7982            })
 7983    }
 7984
 7985    fn build_tasks_context(
 7986        project: &Entity<Project>,
 7987        buffer: &Entity<Buffer>,
 7988        buffer_row: u32,
 7989        tasks: &Arc<RunnableTasks>,
 7990        cx: &mut Context<Self>,
 7991    ) -> Task<Option<task::TaskContext>> {
 7992        let position = Point::new(buffer_row, tasks.column);
 7993        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7994        let location = Location {
 7995            buffer: buffer.clone(),
 7996            range: range_start..range_start,
 7997        };
 7998        // Fill in the environmental variables from the tree-sitter captures
 7999        let mut captured_task_variables = TaskVariables::default();
 8000        for (capture_name, value) in tasks.extra_variables.clone() {
 8001            captured_task_variables.insert(
 8002                task::VariableName::Custom(capture_name.into()),
 8003                value.clone(),
 8004            );
 8005        }
 8006        project.update(cx, |project, cx| {
 8007            project.task_store().update(cx, |task_store, cx| {
 8008                task_store.task_context_for_location(captured_task_variables, location, cx)
 8009            })
 8010        })
 8011    }
 8012
 8013    pub fn spawn_nearest_task(
 8014        &mut self,
 8015        action: &SpawnNearestTask,
 8016        window: &mut Window,
 8017        cx: &mut Context<Self>,
 8018    ) {
 8019        let Some((workspace, _)) = self.workspace.clone() else {
 8020            return;
 8021        };
 8022        let Some(project) = self.project.clone() else {
 8023            return;
 8024        };
 8025
 8026        // Try to find a closest, enclosing node using tree-sitter that has a
 8027        // task
 8028        let Some((buffer, buffer_row, tasks)) = self
 8029            .find_enclosing_node_task(cx)
 8030            // Or find the task that's closest in row-distance.
 8031            .or_else(|| self.find_closest_task(cx))
 8032        else {
 8033            return;
 8034        };
 8035
 8036        let reveal_strategy = action.reveal;
 8037        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8038        cx.spawn_in(window, async move |_, cx| {
 8039            let context = task_context.await?;
 8040            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8041
 8042            let resolved = &mut resolved_task.resolved;
 8043            resolved.reveal = reveal_strategy;
 8044
 8045            workspace
 8046                .update_in(cx, |workspace, window, cx| {
 8047                    workspace.schedule_resolved_task(
 8048                        task_source_kind,
 8049                        resolved_task,
 8050                        false,
 8051                        window,
 8052                        cx,
 8053                    );
 8054                })
 8055                .ok()
 8056        })
 8057        .detach();
 8058    }
 8059
 8060    fn find_closest_task(
 8061        &mut self,
 8062        cx: &mut Context<Self>,
 8063    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8064        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8065
 8066        let ((buffer_id, row), tasks) = self
 8067            .tasks
 8068            .iter()
 8069            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8070
 8071        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8072        let tasks = Arc::new(tasks.to_owned());
 8073        Some((buffer, *row, tasks))
 8074    }
 8075
 8076    fn find_enclosing_node_task(
 8077        &mut self,
 8078        cx: &mut Context<Self>,
 8079    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8080        let snapshot = self.buffer.read(cx).snapshot(cx);
 8081        let offset = self.selections.newest::<usize>(cx).head();
 8082        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8083        let buffer_id = excerpt.buffer().remote_id();
 8084
 8085        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8086        let mut cursor = layer.node().walk();
 8087
 8088        while cursor.goto_first_child_for_byte(offset).is_some() {
 8089            if cursor.node().end_byte() == offset {
 8090                cursor.goto_next_sibling();
 8091            }
 8092        }
 8093
 8094        // Ascend to the smallest ancestor that contains the range and has a task.
 8095        loop {
 8096            let node = cursor.node();
 8097            let node_range = node.byte_range();
 8098            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8099
 8100            // Check if this node contains our offset
 8101            if node_range.start <= offset && node_range.end >= offset {
 8102                // If it contains offset, check for task
 8103                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8104                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8105                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8106                }
 8107            }
 8108
 8109            if !cursor.goto_parent() {
 8110                break;
 8111            }
 8112        }
 8113        None
 8114    }
 8115
 8116    fn render_run_indicator(
 8117        &self,
 8118        _style: &EditorStyle,
 8119        is_active: bool,
 8120        row: DisplayRow,
 8121        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8122        cx: &mut Context<Self>,
 8123    ) -> IconButton {
 8124        let color = Color::Muted;
 8125        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8126
 8127        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8128            .shape(ui::IconButtonShape::Square)
 8129            .icon_size(IconSize::XSmall)
 8130            .icon_color(color)
 8131            .toggle_state(is_active)
 8132            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8133                let quick_launch = e.down.button == MouseButton::Left;
 8134                window.focus(&editor.focus_handle(cx));
 8135                editor.toggle_code_actions(
 8136                    &ToggleCodeActions {
 8137                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8138                        quick_launch,
 8139                    },
 8140                    window,
 8141                    cx,
 8142                );
 8143            }))
 8144            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8145                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8146            }))
 8147    }
 8148
 8149    pub fn context_menu_visible(&self) -> bool {
 8150        !self.edit_prediction_preview_is_active()
 8151            && self
 8152                .context_menu
 8153                .borrow()
 8154                .as_ref()
 8155                .map_or(false, |menu| menu.visible())
 8156    }
 8157
 8158    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8159        self.context_menu
 8160            .borrow()
 8161            .as_ref()
 8162            .map(|menu| menu.origin())
 8163    }
 8164
 8165    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8166        self.context_menu_options = Some(options);
 8167    }
 8168
 8169    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8170    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8171
 8172    fn render_edit_prediction_popover(
 8173        &mut self,
 8174        text_bounds: &Bounds<Pixels>,
 8175        content_origin: gpui::Point<Pixels>,
 8176        right_margin: Pixels,
 8177        editor_snapshot: &EditorSnapshot,
 8178        visible_row_range: Range<DisplayRow>,
 8179        scroll_top: f32,
 8180        scroll_bottom: f32,
 8181        line_layouts: &[LineWithInvisibles],
 8182        line_height: Pixels,
 8183        scroll_pixel_position: gpui::Point<Pixels>,
 8184        newest_selection_head: Option<DisplayPoint>,
 8185        editor_width: Pixels,
 8186        style: &EditorStyle,
 8187        window: &mut Window,
 8188        cx: &mut App,
 8189    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8190        if self.mode().is_minimap() {
 8191            return None;
 8192        }
 8193        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8194
 8195        if self.edit_prediction_visible_in_cursor_popover(true) {
 8196            return None;
 8197        }
 8198
 8199        match &active_inline_completion.completion {
 8200            InlineCompletion::Move { target, .. } => {
 8201                let target_display_point = target.to_display_point(editor_snapshot);
 8202
 8203                if self.edit_prediction_requires_modifier() {
 8204                    if !self.edit_prediction_preview_is_active() {
 8205                        return None;
 8206                    }
 8207
 8208                    self.render_edit_prediction_modifier_jump_popover(
 8209                        text_bounds,
 8210                        content_origin,
 8211                        visible_row_range,
 8212                        line_layouts,
 8213                        line_height,
 8214                        scroll_pixel_position,
 8215                        newest_selection_head,
 8216                        target_display_point,
 8217                        window,
 8218                        cx,
 8219                    )
 8220                } else {
 8221                    self.render_edit_prediction_eager_jump_popover(
 8222                        text_bounds,
 8223                        content_origin,
 8224                        editor_snapshot,
 8225                        visible_row_range,
 8226                        scroll_top,
 8227                        scroll_bottom,
 8228                        line_height,
 8229                        scroll_pixel_position,
 8230                        target_display_point,
 8231                        editor_width,
 8232                        window,
 8233                        cx,
 8234                    )
 8235                }
 8236            }
 8237            InlineCompletion::Edit {
 8238                display_mode: EditDisplayMode::Inline,
 8239                ..
 8240            } => None,
 8241            InlineCompletion::Edit {
 8242                display_mode: EditDisplayMode::TabAccept,
 8243                edits,
 8244                ..
 8245            } => {
 8246                let range = &edits.first()?.0;
 8247                let target_display_point = range.end.to_display_point(editor_snapshot);
 8248
 8249                self.render_edit_prediction_end_of_line_popover(
 8250                    "Accept",
 8251                    editor_snapshot,
 8252                    visible_row_range,
 8253                    target_display_point,
 8254                    line_height,
 8255                    scroll_pixel_position,
 8256                    content_origin,
 8257                    editor_width,
 8258                    window,
 8259                    cx,
 8260                )
 8261            }
 8262            InlineCompletion::Edit {
 8263                edits,
 8264                edit_preview,
 8265                display_mode: EditDisplayMode::DiffPopover,
 8266                snapshot,
 8267            } => self.render_edit_prediction_diff_popover(
 8268                text_bounds,
 8269                content_origin,
 8270                right_margin,
 8271                editor_snapshot,
 8272                visible_row_range,
 8273                line_layouts,
 8274                line_height,
 8275                scroll_pixel_position,
 8276                newest_selection_head,
 8277                editor_width,
 8278                style,
 8279                edits,
 8280                edit_preview,
 8281                snapshot,
 8282                window,
 8283                cx,
 8284            ),
 8285        }
 8286    }
 8287
 8288    fn render_edit_prediction_modifier_jump_popover(
 8289        &mut self,
 8290        text_bounds: &Bounds<Pixels>,
 8291        content_origin: gpui::Point<Pixels>,
 8292        visible_row_range: Range<DisplayRow>,
 8293        line_layouts: &[LineWithInvisibles],
 8294        line_height: Pixels,
 8295        scroll_pixel_position: gpui::Point<Pixels>,
 8296        newest_selection_head: Option<DisplayPoint>,
 8297        target_display_point: DisplayPoint,
 8298        window: &mut Window,
 8299        cx: &mut App,
 8300    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8301        let scrolled_content_origin =
 8302            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8303
 8304        const SCROLL_PADDING_Y: Pixels = px(12.);
 8305
 8306        if target_display_point.row() < visible_row_range.start {
 8307            return self.render_edit_prediction_scroll_popover(
 8308                |_| SCROLL_PADDING_Y,
 8309                IconName::ArrowUp,
 8310                visible_row_range,
 8311                line_layouts,
 8312                newest_selection_head,
 8313                scrolled_content_origin,
 8314                window,
 8315                cx,
 8316            );
 8317        } else if target_display_point.row() >= visible_row_range.end {
 8318            return self.render_edit_prediction_scroll_popover(
 8319                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8320                IconName::ArrowDown,
 8321                visible_row_range,
 8322                line_layouts,
 8323                newest_selection_head,
 8324                scrolled_content_origin,
 8325                window,
 8326                cx,
 8327            );
 8328        }
 8329
 8330        const POLE_WIDTH: Pixels = px(2.);
 8331
 8332        let line_layout =
 8333            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8334        let target_column = target_display_point.column() as usize;
 8335
 8336        let target_x = line_layout.x_for_index(target_column);
 8337        let target_y =
 8338            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8339
 8340        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8341
 8342        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8343        border_color.l += 0.001;
 8344
 8345        let mut element = v_flex()
 8346            .items_end()
 8347            .when(flag_on_right, |el| el.items_start())
 8348            .child(if flag_on_right {
 8349                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8350                    .rounded_bl(px(0.))
 8351                    .rounded_tl(px(0.))
 8352                    .border_l_2()
 8353                    .border_color(border_color)
 8354            } else {
 8355                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8356                    .rounded_br(px(0.))
 8357                    .rounded_tr(px(0.))
 8358                    .border_r_2()
 8359                    .border_color(border_color)
 8360            })
 8361            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8362            .into_any();
 8363
 8364        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8365
 8366        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8367            - point(
 8368                if flag_on_right {
 8369                    POLE_WIDTH
 8370                } else {
 8371                    size.width - POLE_WIDTH
 8372                },
 8373                size.height - line_height,
 8374            );
 8375
 8376        origin.x = origin.x.max(content_origin.x);
 8377
 8378        element.prepaint_at(origin, window, cx);
 8379
 8380        Some((element, origin))
 8381    }
 8382
 8383    fn render_edit_prediction_scroll_popover(
 8384        &mut self,
 8385        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8386        scroll_icon: IconName,
 8387        visible_row_range: Range<DisplayRow>,
 8388        line_layouts: &[LineWithInvisibles],
 8389        newest_selection_head: Option<DisplayPoint>,
 8390        scrolled_content_origin: gpui::Point<Pixels>,
 8391        window: &mut Window,
 8392        cx: &mut App,
 8393    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8394        let mut element = self
 8395            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8396            .into_any();
 8397
 8398        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8399
 8400        let cursor = newest_selection_head?;
 8401        let cursor_row_layout =
 8402            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8403        let cursor_column = cursor.column() as usize;
 8404
 8405        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8406
 8407        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8408
 8409        element.prepaint_at(origin, window, cx);
 8410        Some((element, origin))
 8411    }
 8412
 8413    fn render_edit_prediction_eager_jump_popover(
 8414        &mut self,
 8415        text_bounds: &Bounds<Pixels>,
 8416        content_origin: gpui::Point<Pixels>,
 8417        editor_snapshot: &EditorSnapshot,
 8418        visible_row_range: Range<DisplayRow>,
 8419        scroll_top: f32,
 8420        scroll_bottom: f32,
 8421        line_height: Pixels,
 8422        scroll_pixel_position: gpui::Point<Pixels>,
 8423        target_display_point: DisplayPoint,
 8424        editor_width: Pixels,
 8425        window: &mut Window,
 8426        cx: &mut App,
 8427    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8428        if target_display_point.row().as_f32() < scroll_top {
 8429            let mut element = self
 8430                .render_edit_prediction_line_popover(
 8431                    "Jump to Edit",
 8432                    Some(IconName::ArrowUp),
 8433                    window,
 8434                    cx,
 8435                )?
 8436                .into_any();
 8437
 8438            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8439            let offset = point(
 8440                (text_bounds.size.width - size.width) / 2.,
 8441                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8442            );
 8443
 8444            let origin = text_bounds.origin + offset;
 8445            element.prepaint_at(origin, window, cx);
 8446            Some((element, origin))
 8447        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8448            let mut element = self
 8449                .render_edit_prediction_line_popover(
 8450                    "Jump to Edit",
 8451                    Some(IconName::ArrowDown),
 8452                    window,
 8453                    cx,
 8454                )?
 8455                .into_any();
 8456
 8457            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8458            let offset = point(
 8459                (text_bounds.size.width - size.width) / 2.,
 8460                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8461            );
 8462
 8463            let origin = text_bounds.origin + offset;
 8464            element.prepaint_at(origin, window, cx);
 8465            Some((element, origin))
 8466        } else {
 8467            self.render_edit_prediction_end_of_line_popover(
 8468                "Jump to Edit",
 8469                editor_snapshot,
 8470                visible_row_range,
 8471                target_display_point,
 8472                line_height,
 8473                scroll_pixel_position,
 8474                content_origin,
 8475                editor_width,
 8476                window,
 8477                cx,
 8478            )
 8479        }
 8480    }
 8481
 8482    fn render_edit_prediction_end_of_line_popover(
 8483        self: &mut Editor,
 8484        label: &'static str,
 8485        editor_snapshot: &EditorSnapshot,
 8486        visible_row_range: Range<DisplayRow>,
 8487        target_display_point: DisplayPoint,
 8488        line_height: Pixels,
 8489        scroll_pixel_position: gpui::Point<Pixels>,
 8490        content_origin: gpui::Point<Pixels>,
 8491        editor_width: Pixels,
 8492        window: &mut Window,
 8493        cx: &mut App,
 8494    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8495        let target_line_end = DisplayPoint::new(
 8496            target_display_point.row(),
 8497            editor_snapshot.line_len(target_display_point.row()),
 8498        );
 8499
 8500        let mut element = self
 8501            .render_edit_prediction_line_popover(label, None, window, cx)?
 8502            .into_any();
 8503
 8504        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8505
 8506        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8507
 8508        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8509        let mut origin = start_point
 8510            + line_origin
 8511            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8512        origin.x = origin.x.max(content_origin.x);
 8513
 8514        let max_x = content_origin.x + editor_width - size.width;
 8515
 8516        if origin.x > max_x {
 8517            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8518
 8519            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8520                origin.y += offset;
 8521                IconName::ArrowUp
 8522            } else {
 8523                origin.y -= offset;
 8524                IconName::ArrowDown
 8525            };
 8526
 8527            element = self
 8528                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8529                .into_any();
 8530
 8531            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8532
 8533            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8534        }
 8535
 8536        element.prepaint_at(origin, window, cx);
 8537        Some((element, origin))
 8538    }
 8539
 8540    fn render_edit_prediction_diff_popover(
 8541        self: &Editor,
 8542        text_bounds: &Bounds<Pixels>,
 8543        content_origin: gpui::Point<Pixels>,
 8544        right_margin: Pixels,
 8545        editor_snapshot: &EditorSnapshot,
 8546        visible_row_range: Range<DisplayRow>,
 8547        line_layouts: &[LineWithInvisibles],
 8548        line_height: Pixels,
 8549        scroll_pixel_position: gpui::Point<Pixels>,
 8550        newest_selection_head: Option<DisplayPoint>,
 8551        editor_width: Pixels,
 8552        style: &EditorStyle,
 8553        edits: &Vec<(Range<Anchor>, String)>,
 8554        edit_preview: &Option<language::EditPreview>,
 8555        snapshot: &language::BufferSnapshot,
 8556        window: &mut Window,
 8557        cx: &mut App,
 8558    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8559        let edit_start = edits
 8560            .first()
 8561            .unwrap()
 8562            .0
 8563            .start
 8564            .to_display_point(editor_snapshot);
 8565        let edit_end = edits
 8566            .last()
 8567            .unwrap()
 8568            .0
 8569            .end
 8570            .to_display_point(editor_snapshot);
 8571
 8572        let is_visible = visible_row_range.contains(&edit_start.row())
 8573            || visible_row_range.contains(&edit_end.row());
 8574        if !is_visible {
 8575            return None;
 8576        }
 8577
 8578        let highlighted_edits =
 8579            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8580
 8581        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8582        let line_count = highlighted_edits.text.lines().count();
 8583
 8584        const BORDER_WIDTH: Pixels = px(1.);
 8585
 8586        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8587        let has_keybind = keybind.is_some();
 8588
 8589        let mut element = h_flex()
 8590            .items_start()
 8591            .child(
 8592                h_flex()
 8593                    .bg(cx.theme().colors().editor_background)
 8594                    .border(BORDER_WIDTH)
 8595                    .shadow_sm()
 8596                    .border_color(cx.theme().colors().border)
 8597                    .rounded_l_lg()
 8598                    .when(line_count > 1, |el| el.rounded_br_lg())
 8599                    .pr_1()
 8600                    .child(styled_text),
 8601            )
 8602            .child(
 8603                h_flex()
 8604                    .h(line_height + BORDER_WIDTH * 2.)
 8605                    .px_1p5()
 8606                    .gap_1()
 8607                    // Workaround: For some reason, there's a gap if we don't do this
 8608                    .ml(-BORDER_WIDTH)
 8609                    .shadow(vec![gpui::BoxShadow {
 8610                        color: gpui::black().opacity(0.05),
 8611                        offset: point(px(1.), px(1.)),
 8612                        blur_radius: px(2.),
 8613                        spread_radius: px(0.),
 8614                    }])
 8615                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8616                    .border(BORDER_WIDTH)
 8617                    .border_color(cx.theme().colors().border)
 8618                    .rounded_r_lg()
 8619                    .id("edit_prediction_diff_popover_keybind")
 8620                    .when(!has_keybind, |el| {
 8621                        let status_colors = cx.theme().status();
 8622
 8623                        el.bg(status_colors.error_background)
 8624                            .border_color(status_colors.error.opacity(0.6))
 8625                            .child(Icon::new(IconName::Info).color(Color::Error))
 8626                            .cursor_default()
 8627                            .hoverable_tooltip(move |_window, cx| {
 8628                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8629                            })
 8630                    })
 8631                    .children(keybind),
 8632            )
 8633            .into_any();
 8634
 8635        let longest_row =
 8636            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8637        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8638            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8639        } else {
 8640            layout_line(
 8641                longest_row,
 8642                editor_snapshot,
 8643                style,
 8644                editor_width,
 8645                |_| false,
 8646                window,
 8647                cx,
 8648            )
 8649            .width
 8650        };
 8651
 8652        let viewport_bounds =
 8653            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8654                right: -right_margin,
 8655                ..Default::default()
 8656            });
 8657
 8658        let x_after_longest =
 8659            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8660                - scroll_pixel_position.x;
 8661
 8662        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8663
 8664        // Fully visible if it can be displayed within the window (allow overlapping other
 8665        // panes). However, this is only allowed if the popover starts within text_bounds.
 8666        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8667            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8668
 8669        let mut origin = if can_position_to_the_right {
 8670            point(
 8671                x_after_longest,
 8672                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8673                    - scroll_pixel_position.y,
 8674            )
 8675        } else {
 8676            let cursor_row = newest_selection_head.map(|head| head.row());
 8677            let above_edit = edit_start
 8678                .row()
 8679                .0
 8680                .checked_sub(line_count as u32)
 8681                .map(DisplayRow);
 8682            let below_edit = Some(edit_end.row() + 1);
 8683            let above_cursor =
 8684                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8685            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8686
 8687            // Place the edit popover adjacent to the edit if there is a location
 8688            // available that is onscreen and does not obscure the cursor. Otherwise,
 8689            // place it adjacent to the cursor.
 8690            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8691                .into_iter()
 8692                .flatten()
 8693                .find(|&start_row| {
 8694                    let end_row = start_row + line_count as u32;
 8695                    visible_row_range.contains(&start_row)
 8696                        && visible_row_range.contains(&end_row)
 8697                        && cursor_row.map_or(true, |cursor_row| {
 8698                            !((start_row..end_row).contains(&cursor_row))
 8699                        })
 8700                })?;
 8701
 8702            content_origin
 8703                + point(
 8704                    -scroll_pixel_position.x,
 8705                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8706                )
 8707        };
 8708
 8709        origin.x -= BORDER_WIDTH;
 8710
 8711        window.defer_draw(element, origin, 1);
 8712
 8713        // Do not return an element, since it will already be drawn due to defer_draw.
 8714        None
 8715    }
 8716
 8717    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8718        px(30.)
 8719    }
 8720
 8721    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8722        if self.read_only(cx) {
 8723            cx.theme().players().read_only()
 8724        } else {
 8725            self.style.as_ref().unwrap().local_player
 8726        }
 8727    }
 8728
 8729    fn render_edit_prediction_accept_keybind(
 8730        &self,
 8731        window: &mut Window,
 8732        cx: &App,
 8733    ) -> Option<AnyElement> {
 8734        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8735        let accept_keystroke = accept_binding.keystroke()?;
 8736
 8737        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8738
 8739        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8740            Color::Accent
 8741        } else {
 8742            Color::Muted
 8743        };
 8744
 8745        h_flex()
 8746            .px_0p5()
 8747            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8748            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8749            .text_size(TextSize::XSmall.rems(cx))
 8750            .child(h_flex().children(ui::render_modifiers(
 8751                &accept_keystroke.modifiers,
 8752                PlatformStyle::platform(),
 8753                Some(modifiers_color),
 8754                Some(IconSize::XSmall.rems().into()),
 8755                true,
 8756            )))
 8757            .when(is_platform_style_mac, |parent| {
 8758                parent.child(accept_keystroke.key.clone())
 8759            })
 8760            .when(!is_platform_style_mac, |parent| {
 8761                parent.child(
 8762                    Key::new(
 8763                        util::capitalize(&accept_keystroke.key),
 8764                        Some(Color::Default),
 8765                    )
 8766                    .size(Some(IconSize::XSmall.rems().into())),
 8767                )
 8768            })
 8769            .into_any()
 8770            .into()
 8771    }
 8772
 8773    fn render_edit_prediction_line_popover(
 8774        &self,
 8775        label: impl Into<SharedString>,
 8776        icon: Option<IconName>,
 8777        window: &mut Window,
 8778        cx: &App,
 8779    ) -> Option<Stateful<Div>> {
 8780        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8781
 8782        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8783        let has_keybind = keybind.is_some();
 8784
 8785        let result = h_flex()
 8786            .id("ep-line-popover")
 8787            .py_0p5()
 8788            .pl_1()
 8789            .pr(padding_right)
 8790            .gap_1()
 8791            .rounded_md()
 8792            .border_1()
 8793            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8794            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8795            .shadow_sm()
 8796            .when(!has_keybind, |el| {
 8797                let status_colors = cx.theme().status();
 8798
 8799                el.bg(status_colors.error_background)
 8800                    .border_color(status_colors.error.opacity(0.6))
 8801                    .pl_2()
 8802                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8803                    .cursor_default()
 8804                    .hoverable_tooltip(move |_window, cx| {
 8805                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8806                    })
 8807            })
 8808            .children(keybind)
 8809            .child(
 8810                Label::new(label)
 8811                    .size(LabelSize::Small)
 8812                    .when(!has_keybind, |el| {
 8813                        el.color(cx.theme().status().error.into()).strikethrough()
 8814                    }),
 8815            )
 8816            .when(!has_keybind, |el| {
 8817                el.child(
 8818                    h_flex().ml_1().child(
 8819                        Icon::new(IconName::Info)
 8820                            .size(IconSize::Small)
 8821                            .color(cx.theme().status().error.into()),
 8822                    ),
 8823                )
 8824            })
 8825            .when_some(icon, |element, icon| {
 8826                element.child(
 8827                    div()
 8828                        .mt(px(1.5))
 8829                        .child(Icon::new(icon).size(IconSize::Small)),
 8830                )
 8831            });
 8832
 8833        Some(result)
 8834    }
 8835
 8836    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8837        let accent_color = cx.theme().colors().text_accent;
 8838        let editor_bg_color = cx.theme().colors().editor_background;
 8839        editor_bg_color.blend(accent_color.opacity(0.1))
 8840    }
 8841
 8842    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8843        let accent_color = cx.theme().colors().text_accent;
 8844        let editor_bg_color = cx.theme().colors().editor_background;
 8845        editor_bg_color.blend(accent_color.opacity(0.6))
 8846    }
 8847
 8848    fn render_edit_prediction_cursor_popover(
 8849        &self,
 8850        min_width: Pixels,
 8851        max_width: Pixels,
 8852        cursor_point: Point,
 8853        style: &EditorStyle,
 8854        accept_keystroke: Option<&gpui::Keystroke>,
 8855        _window: &Window,
 8856        cx: &mut Context<Editor>,
 8857    ) -> Option<AnyElement> {
 8858        let provider = self.edit_prediction_provider.as_ref()?;
 8859
 8860        if provider.provider.needs_terms_acceptance(cx) {
 8861            return Some(
 8862                h_flex()
 8863                    .min_w(min_width)
 8864                    .flex_1()
 8865                    .px_2()
 8866                    .py_1()
 8867                    .gap_3()
 8868                    .elevation_2(cx)
 8869                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8870                    .id("accept-terms")
 8871                    .cursor_pointer()
 8872                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8873                    .on_click(cx.listener(|this, _event, window, cx| {
 8874                        cx.stop_propagation();
 8875                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8876                        window.dispatch_action(
 8877                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8878                            cx,
 8879                        );
 8880                    }))
 8881                    .child(
 8882                        h_flex()
 8883                            .flex_1()
 8884                            .gap_2()
 8885                            .child(Icon::new(IconName::ZedPredict))
 8886                            .child(Label::new("Accept Terms of Service"))
 8887                            .child(div().w_full())
 8888                            .child(
 8889                                Icon::new(IconName::ArrowUpRight)
 8890                                    .color(Color::Muted)
 8891                                    .size(IconSize::Small),
 8892                            )
 8893                            .into_any_element(),
 8894                    )
 8895                    .into_any(),
 8896            );
 8897        }
 8898
 8899        let is_refreshing = provider.provider.is_refreshing(cx);
 8900
 8901        fn pending_completion_container() -> Div {
 8902            h_flex()
 8903                .h_full()
 8904                .flex_1()
 8905                .gap_2()
 8906                .child(Icon::new(IconName::ZedPredict))
 8907        }
 8908
 8909        let completion = match &self.active_inline_completion {
 8910            Some(prediction) => {
 8911                if !self.has_visible_completions_menu() {
 8912                    const RADIUS: Pixels = px(6.);
 8913                    const BORDER_WIDTH: Pixels = px(1.);
 8914
 8915                    return Some(
 8916                        h_flex()
 8917                            .elevation_2(cx)
 8918                            .border(BORDER_WIDTH)
 8919                            .border_color(cx.theme().colors().border)
 8920                            .when(accept_keystroke.is_none(), |el| {
 8921                                el.border_color(cx.theme().status().error)
 8922                            })
 8923                            .rounded(RADIUS)
 8924                            .rounded_tl(px(0.))
 8925                            .overflow_hidden()
 8926                            .child(div().px_1p5().child(match &prediction.completion {
 8927                                InlineCompletion::Move { target, snapshot } => {
 8928                                    use text::ToPoint as _;
 8929                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8930                                    {
 8931                                        Icon::new(IconName::ZedPredictDown)
 8932                                    } else {
 8933                                        Icon::new(IconName::ZedPredictUp)
 8934                                    }
 8935                                }
 8936                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8937                            }))
 8938                            .child(
 8939                                h_flex()
 8940                                    .gap_1()
 8941                                    .py_1()
 8942                                    .px_2()
 8943                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8944                                    .border_l_1()
 8945                                    .border_color(cx.theme().colors().border)
 8946                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8947                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8948                                        el.child(
 8949                                            Label::new("Hold")
 8950                                                .size(LabelSize::Small)
 8951                                                .when(accept_keystroke.is_none(), |el| {
 8952                                                    el.strikethrough()
 8953                                                })
 8954                                                .line_height_style(LineHeightStyle::UiLabel),
 8955                                        )
 8956                                    })
 8957                                    .id("edit_prediction_cursor_popover_keybind")
 8958                                    .when(accept_keystroke.is_none(), |el| {
 8959                                        let status_colors = cx.theme().status();
 8960
 8961                                        el.bg(status_colors.error_background)
 8962                                            .border_color(status_colors.error.opacity(0.6))
 8963                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8964                                            .cursor_default()
 8965                                            .hoverable_tooltip(move |_window, cx| {
 8966                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8967                                                    .into()
 8968                                            })
 8969                                    })
 8970                                    .when_some(
 8971                                        accept_keystroke.as_ref(),
 8972                                        |el, accept_keystroke| {
 8973                                            el.child(h_flex().children(ui::render_modifiers(
 8974                                                &accept_keystroke.modifiers,
 8975                                                PlatformStyle::platform(),
 8976                                                Some(Color::Default),
 8977                                                Some(IconSize::XSmall.rems().into()),
 8978                                                false,
 8979                                            )))
 8980                                        },
 8981                                    ),
 8982                            )
 8983                            .into_any(),
 8984                    );
 8985                }
 8986
 8987                self.render_edit_prediction_cursor_popover_preview(
 8988                    prediction,
 8989                    cursor_point,
 8990                    style,
 8991                    cx,
 8992                )?
 8993            }
 8994
 8995            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8996                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8997                    stale_completion,
 8998                    cursor_point,
 8999                    style,
 9000                    cx,
 9001                )?,
 9002
 9003                None => {
 9004                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9005                }
 9006            },
 9007
 9008            None => pending_completion_container().child(Label::new("No Prediction")),
 9009        };
 9010
 9011        let completion = if is_refreshing {
 9012            completion
 9013                .with_animation(
 9014                    "loading-completion",
 9015                    Animation::new(Duration::from_secs(2))
 9016                        .repeat()
 9017                        .with_easing(pulsating_between(0.4, 0.8)),
 9018                    |label, delta| label.opacity(delta),
 9019                )
 9020                .into_any_element()
 9021        } else {
 9022            completion.into_any_element()
 9023        };
 9024
 9025        let has_completion = self.active_inline_completion.is_some();
 9026
 9027        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9028        Some(
 9029            h_flex()
 9030                .min_w(min_width)
 9031                .max_w(max_width)
 9032                .flex_1()
 9033                .elevation_2(cx)
 9034                .border_color(cx.theme().colors().border)
 9035                .child(
 9036                    div()
 9037                        .flex_1()
 9038                        .py_1()
 9039                        .px_2()
 9040                        .overflow_hidden()
 9041                        .child(completion),
 9042                )
 9043                .when_some(accept_keystroke, |el, accept_keystroke| {
 9044                    if !accept_keystroke.modifiers.modified() {
 9045                        return el;
 9046                    }
 9047
 9048                    el.child(
 9049                        h_flex()
 9050                            .h_full()
 9051                            .border_l_1()
 9052                            .rounded_r_lg()
 9053                            .border_color(cx.theme().colors().border)
 9054                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9055                            .gap_1()
 9056                            .py_1()
 9057                            .px_2()
 9058                            .child(
 9059                                h_flex()
 9060                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9061                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9062                                    .child(h_flex().children(ui::render_modifiers(
 9063                                        &accept_keystroke.modifiers,
 9064                                        PlatformStyle::platform(),
 9065                                        Some(if !has_completion {
 9066                                            Color::Muted
 9067                                        } else {
 9068                                            Color::Default
 9069                                        }),
 9070                                        None,
 9071                                        false,
 9072                                    ))),
 9073                            )
 9074                            .child(Label::new("Preview").into_any_element())
 9075                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9076                    )
 9077                })
 9078                .into_any(),
 9079        )
 9080    }
 9081
 9082    fn render_edit_prediction_cursor_popover_preview(
 9083        &self,
 9084        completion: &InlineCompletionState,
 9085        cursor_point: Point,
 9086        style: &EditorStyle,
 9087        cx: &mut Context<Editor>,
 9088    ) -> Option<Div> {
 9089        use text::ToPoint as _;
 9090
 9091        fn render_relative_row_jump(
 9092            prefix: impl Into<String>,
 9093            current_row: u32,
 9094            target_row: u32,
 9095        ) -> Div {
 9096            let (row_diff, arrow) = if target_row < current_row {
 9097                (current_row - target_row, IconName::ArrowUp)
 9098            } else {
 9099                (target_row - current_row, IconName::ArrowDown)
 9100            };
 9101
 9102            h_flex()
 9103                .child(
 9104                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9105                        .color(Color::Muted)
 9106                        .size(LabelSize::Small),
 9107                )
 9108                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9109        }
 9110
 9111        match &completion.completion {
 9112            InlineCompletion::Move {
 9113                target, snapshot, ..
 9114            } => Some(
 9115                h_flex()
 9116                    .px_2()
 9117                    .gap_2()
 9118                    .flex_1()
 9119                    .child(
 9120                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9121                            Icon::new(IconName::ZedPredictDown)
 9122                        } else {
 9123                            Icon::new(IconName::ZedPredictUp)
 9124                        },
 9125                    )
 9126                    .child(Label::new("Jump to Edit")),
 9127            ),
 9128
 9129            InlineCompletion::Edit {
 9130                edits,
 9131                edit_preview,
 9132                snapshot,
 9133                display_mode: _,
 9134            } => {
 9135                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9136
 9137                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9138                    &snapshot,
 9139                    &edits,
 9140                    edit_preview.as_ref()?,
 9141                    true,
 9142                    cx,
 9143                )
 9144                .first_line_preview();
 9145
 9146                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9147                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9148
 9149                let preview = h_flex()
 9150                    .gap_1()
 9151                    .min_w_16()
 9152                    .child(styled_text)
 9153                    .when(has_more_lines, |parent| parent.child(""));
 9154
 9155                let left = if first_edit_row != cursor_point.row {
 9156                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9157                        .into_any_element()
 9158                } else {
 9159                    Icon::new(IconName::ZedPredict).into_any_element()
 9160                };
 9161
 9162                Some(
 9163                    h_flex()
 9164                        .h_full()
 9165                        .flex_1()
 9166                        .gap_2()
 9167                        .pr_1()
 9168                        .overflow_x_hidden()
 9169                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9170                        .child(left)
 9171                        .child(preview),
 9172                )
 9173            }
 9174        }
 9175    }
 9176
 9177    pub fn render_context_menu(
 9178        &self,
 9179        style: &EditorStyle,
 9180        max_height_in_lines: u32,
 9181        window: &mut Window,
 9182        cx: &mut Context<Editor>,
 9183    ) -> Option<AnyElement> {
 9184        let menu = self.context_menu.borrow();
 9185        let menu = menu.as_ref()?;
 9186        if !menu.visible() {
 9187            return None;
 9188        };
 9189        Some(menu.render(style, max_height_in_lines, window, cx))
 9190    }
 9191
 9192    fn render_context_menu_aside(
 9193        &mut self,
 9194        max_size: Size<Pixels>,
 9195        window: &mut Window,
 9196        cx: &mut Context<Editor>,
 9197    ) -> Option<AnyElement> {
 9198        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9199            if menu.visible() {
 9200                menu.render_aside(max_size, window, cx)
 9201            } else {
 9202                None
 9203            }
 9204        })
 9205    }
 9206
 9207    fn hide_context_menu(
 9208        &mut self,
 9209        window: &mut Window,
 9210        cx: &mut Context<Self>,
 9211    ) -> Option<CodeContextMenu> {
 9212        cx.notify();
 9213        self.completion_tasks.clear();
 9214        let context_menu = self.context_menu.borrow_mut().take();
 9215        self.stale_inline_completion_in_menu.take();
 9216        self.update_visible_inline_completion(window, cx);
 9217        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9218            if let Some(completion_provider) = &self.completion_provider {
 9219                completion_provider.selection_changed(None, window, cx);
 9220            }
 9221        }
 9222        context_menu
 9223    }
 9224
 9225    fn show_snippet_choices(
 9226        &mut self,
 9227        choices: &Vec<String>,
 9228        selection: Range<Anchor>,
 9229        cx: &mut Context<Self>,
 9230    ) {
 9231        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9232            (Some(a), Some(b)) if a == b => a,
 9233            _ => {
 9234                log::error!("expected anchor range to have matching buffer IDs");
 9235                return;
 9236            }
 9237        };
 9238        let multi_buffer = self.buffer().read(cx);
 9239        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9240            return;
 9241        };
 9242
 9243        let id = post_inc(&mut self.next_completion_id);
 9244        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9245        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9246            CompletionsMenu::new_snippet_choices(
 9247                id,
 9248                true,
 9249                choices,
 9250                selection,
 9251                buffer,
 9252                snippet_sort_order,
 9253            ),
 9254        ));
 9255    }
 9256
 9257    pub fn insert_snippet(
 9258        &mut self,
 9259        insertion_ranges: &[Range<usize>],
 9260        snippet: Snippet,
 9261        window: &mut Window,
 9262        cx: &mut Context<Self>,
 9263    ) -> Result<()> {
 9264        struct Tabstop<T> {
 9265            is_end_tabstop: bool,
 9266            ranges: Vec<Range<T>>,
 9267            choices: Option<Vec<String>>,
 9268        }
 9269
 9270        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9271            let snippet_text: Arc<str> = snippet.text.clone().into();
 9272            let edits = insertion_ranges
 9273                .iter()
 9274                .cloned()
 9275                .map(|range| (range, snippet_text.clone()));
 9276            let autoindent_mode = AutoindentMode::Block {
 9277                original_indent_columns: Vec::new(),
 9278            };
 9279            buffer.edit(edits, Some(autoindent_mode), cx);
 9280
 9281            let snapshot = &*buffer.read(cx);
 9282            let snippet = &snippet;
 9283            snippet
 9284                .tabstops
 9285                .iter()
 9286                .map(|tabstop| {
 9287                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9288                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9289                    });
 9290                    let mut tabstop_ranges = tabstop
 9291                        .ranges
 9292                        .iter()
 9293                        .flat_map(|tabstop_range| {
 9294                            let mut delta = 0_isize;
 9295                            insertion_ranges.iter().map(move |insertion_range| {
 9296                                let insertion_start = insertion_range.start as isize + delta;
 9297                                delta +=
 9298                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9299
 9300                                let start = ((insertion_start + tabstop_range.start) as usize)
 9301                                    .min(snapshot.len());
 9302                                let end = ((insertion_start + tabstop_range.end) as usize)
 9303                                    .min(snapshot.len());
 9304                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9305                            })
 9306                        })
 9307                        .collect::<Vec<_>>();
 9308                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9309
 9310                    Tabstop {
 9311                        is_end_tabstop,
 9312                        ranges: tabstop_ranges,
 9313                        choices: tabstop.choices.clone(),
 9314                    }
 9315                })
 9316                .collect::<Vec<_>>()
 9317        });
 9318        if let Some(tabstop) = tabstops.first() {
 9319            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9320                // Reverse order so that the first range is the newest created selection.
 9321                // Completions will use it and autoscroll will prioritize it.
 9322                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9323            });
 9324
 9325            if let Some(choices) = &tabstop.choices {
 9326                if let Some(selection) = tabstop.ranges.first() {
 9327                    self.show_snippet_choices(choices, selection.clone(), cx)
 9328                }
 9329            }
 9330
 9331            // If we're already at the last tabstop and it's at the end of the snippet,
 9332            // we're done, we don't need to keep the state around.
 9333            if !tabstop.is_end_tabstop {
 9334                let choices = tabstops
 9335                    .iter()
 9336                    .map(|tabstop| tabstop.choices.clone())
 9337                    .collect();
 9338
 9339                let ranges = tabstops
 9340                    .into_iter()
 9341                    .map(|tabstop| tabstop.ranges)
 9342                    .collect::<Vec<_>>();
 9343
 9344                self.snippet_stack.push(SnippetState {
 9345                    active_index: 0,
 9346                    ranges,
 9347                    choices,
 9348                });
 9349            }
 9350
 9351            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9352            if self.autoclose_regions.is_empty() {
 9353                let snapshot = self.buffer.read(cx).snapshot(cx);
 9354                for selection in &mut self.selections.all::<Point>(cx) {
 9355                    let selection_head = selection.head();
 9356                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9357                        continue;
 9358                    };
 9359
 9360                    let mut bracket_pair = None;
 9361                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9362                    let prev_chars = snapshot
 9363                        .reversed_chars_at(selection_head)
 9364                        .collect::<String>();
 9365                    for (pair, enabled) in scope.brackets() {
 9366                        if enabled
 9367                            && pair.close
 9368                            && prev_chars.starts_with(pair.start.as_str())
 9369                            && next_chars.starts_with(pair.end.as_str())
 9370                        {
 9371                            bracket_pair = Some(pair.clone());
 9372                            break;
 9373                        }
 9374                    }
 9375                    if let Some(pair) = bracket_pair {
 9376                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9377                        let autoclose_enabled =
 9378                            self.use_autoclose && snapshot_settings.use_autoclose;
 9379                        if autoclose_enabled {
 9380                            let start = snapshot.anchor_after(selection_head);
 9381                            let end = snapshot.anchor_after(selection_head);
 9382                            self.autoclose_regions.push(AutocloseRegion {
 9383                                selection_id: selection.id,
 9384                                range: start..end,
 9385                                pair,
 9386                            });
 9387                        }
 9388                    }
 9389                }
 9390            }
 9391        }
 9392        Ok(())
 9393    }
 9394
 9395    pub fn move_to_next_snippet_tabstop(
 9396        &mut self,
 9397        window: &mut Window,
 9398        cx: &mut Context<Self>,
 9399    ) -> bool {
 9400        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9401    }
 9402
 9403    pub fn move_to_prev_snippet_tabstop(
 9404        &mut self,
 9405        window: &mut Window,
 9406        cx: &mut Context<Self>,
 9407    ) -> bool {
 9408        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9409    }
 9410
 9411    pub fn move_to_snippet_tabstop(
 9412        &mut self,
 9413        bias: Bias,
 9414        window: &mut Window,
 9415        cx: &mut Context<Self>,
 9416    ) -> bool {
 9417        if let Some(mut snippet) = self.snippet_stack.pop() {
 9418            match bias {
 9419                Bias::Left => {
 9420                    if snippet.active_index > 0 {
 9421                        snippet.active_index -= 1;
 9422                    } else {
 9423                        self.snippet_stack.push(snippet);
 9424                        return false;
 9425                    }
 9426                }
 9427                Bias::Right => {
 9428                    if snippet.active_index + 1 < snippet.ranges.len() {
 9429                        snippet.active_index += 1;
 9430                    } else {
 9431                        self.snippet_stack.push(snippet);
 9432                        return false;
 9433                    }
 9434                }
 9435            }
 9436            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9437                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9438                    // Reverse order so that the first range is the newest created selection.
 9439                    // Completions will use it and autoscroll will prioritize it.
 9440                    s.select_ranges(current_ranges.iter().rev().cloned())
 9441                });
 9442
 9443                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9444                    if let Some(selection) = current_ranges.first() {
 9445                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9446                    }
 9447                }
 9448
 9449                // If snippet state is not at the last tabstop, push it back on the stack
 9450                if snippet.active_index + 1 < snippet.ranges.len() {
 9451                    self.snippet_stack.push(snippet);
 9452                }
 9453                return true;
 9454            }
 9455        }
 9456
 9457        false
 9458    }
 9459
 9460    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9461        self.transact(window, cx, |this, window, cx| {
 9462            this.select_all(&SelectAll, window, cx);
 9463            this.insert("", window, cx);
 9464        });
 9465    }
 9466
 9467    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9468        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9469        self.transact(window, cx, |this, window, cx| {
 9470            this.select_autoclose_pair(window, cx);
 9471            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9472            if !this.linked_edit_ranges.is_empty() {
 9473                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9474                let snapshot = this.buffer.read(cx).snapshot(cx);
 9475
 9476                for selection in selections.iter() {
 9477                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9478                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9479                    if selection_start.buffer_id != selection_end.buffer_id {
 9480                        continue;
 9481                    }
 9482                    if let Some(ranges) =
 9483                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9484                    {
 9485                        for (buffer, entries) in ranges {
 9486                            linked_ranges.entry(buffer).or_default().extend(entries);
 9487                        }
 9488                    }
 9489                }
 9490            }
 9491
 9492            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9493            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9494            for selection in &mut selections {
 9495                if selection.is_empty() {
 9496                    let old_head = selection.head();
 9497                    let mut new_head =
 9498                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9499                            .to_point(&display_map);
 9500                    if let Some((buffer, line_buffer_range)) = display_map
 9501                        .buffer_snapshot
 9502                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9503                    {
 9504                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9505                        let indent_len = match indent_size.kind {
 9506                            IndentKind::Space => {
 9507                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9508                            }
 9509                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9510                        };
 9511                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9512                            let indent_len = indent_len.get();
 9513                            new_head = cmp::min(
 9514                                new_head,
 9515                                MultiBufferPoint::new(
 9516                                    old_head.row,
 9517                                    ((old_head.column - 1) / indent_len) * indent_len,
 9518                                ),
 9519                            );
 9520                        }
 9521                    }
 9522
 9523                    selection.set_head(new_head, SelectionGoal::None);
 9524                }
 9525            }
 9526
 9527            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9528                s.select(selections)
 9529            });
 9530            this.insert("", window, cx);
 9531            let empty_str: Arc<str> = Arc::from("");
 9532            for (buffer, edits) in linked_ranges {
 9533                let snapshot = buffer.read(cx).snapshot();
 9534                use text::ToPoint as TP;
 9535
 9536                let edits = edits
 9537                    .into_iter()
 9538                    .map(|range| {
 9539                        let end_point = TP::to_point(&range.end, &snapshot);
 9540                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9541
 9542                        if end_point == start_point {
 9543                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9544                                .saturating_sub(1);
 9545                            start_point =
 9546                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9547                        };
 9548
 9549                        (start_point..end_point, empty_str.clone())
 9550                    })
 9551                    .sorted_by_key(|(range, _)| range.start)
 9552                    .collect::<Vec<_>>();
 9553                buffer.update(cx, |this, cx| {
 9554                    this.edit(edits, None, cx);
 9555                })
 9556            }
 9557            this.refresh_inline_completion(true, false, window, cx);
 9558            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9559        });
 9560    }
 9561
 9562    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9563        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9564        self.transact(window, cx, |this, window, cx| {
 9565            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9566                s.move_with(|map, selection| {
 9567                    if selection.is_empty() {
 9568                        let cursor = movement::right(map, selection.head());
 9569                        selection.end = cursor;
 9570                        selection.reversed = true;
 9571                        selection.goal = SelectionGoal::None;
 9572                    }
 9573                })
 9574            });
 9575            this.insert("", window, cx);
 9576            this.refresh_inline_completion(true, false, window, cx);
 9577        });
 9578    }
 9579
 9580    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9581        if self.mode.is_single_line() {
 9582            cx.propagate();
 9583            return;
 9584        }
 9585
 9586        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9587        if self.move_to_prev_snippet_tabstop(window, cx) {
 9588            return;
 9589        }
 9590        self.outdent(&Outdent, window, cx);
 9591    }
 9592
 9593    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9594        if self.mode.is_single_line() {
 9595            cx.propagate();
 9596            return;
 9597        }
 9598
 9599        if self.move_to_next_snippet_tabstop(window, cx) {
 9600            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9601            return;
 9602        }
 9603        if self.read_only(cx) {
 9604            return;
 9605        }
 9606        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9607        let mut selections = self.selections.all_adjusted(cx);
 9608        let buffer = self.buffer.read(cx);
 9609        let snapshot = buffer.snapshot(cx);
 9610        let rows_iter = selections.iter().map(|s| s.head().row);
 9611        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9612
 9613        let has_some_cursor_in_whitespace = selections
 9614            .iter()
 9615            .filter(|selection| selection.is_empty())
 9616            .any(|selection| {
 9617                let cursor = selection.head();
 9618                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9619                cursor.column < current_indent.len
 9620            });
 9621
 9622        let mut edits = Vec::new();
 9623        let mut prev_edited_row = 0;
 9624        let mut row_delta = 0;
 9625        for selection in &mut selections {
 9626            if selection.start.row != prev_edited_row {
 9627                row_delta = 0;
 9628            }
 9629            prev_edited_row = selection.end.row;
 9630
 9631            // If the selection is non-empty, then increase the indentation of the selected lines.
 9632            if !selection.is_empty() {
 9633                row_delta =
 9634                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9635                continue;
 9636            }
 9637
 9638            let cursor = selection.head();
 9639            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9640            if let Some(suggested_indent) =
 9641                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9642            {
 9643                // Don't do anything if already at suggested indent
 9644                // and there is any other cursor which is not
 9645                if has_some_cursor_in_whitespace
 9646                    && cursor.column == current_indent.len
 9647                    && current_indent.len == suggested_indent.len
 9648                {
 9649                    continue;
 9650                }
 9651
 9652                // Adjust line and move cursor to suggested indent
 9653                // if cursor is not at suggested indent
 9654                if cursor.column < suggested_indent.len
 9655                    && cursor.column <= current_indent.len
 9656                    && current_indent.len <= suggested_indent.len
 9657                {
 9658                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9659                    selection.end = selection.start;
 9660                    if row_delta == 0 {
 9661                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9662                            cursor.row,
 9663                            current_indent,
 9664                            suggested_indent,
 9665                        ));
 9666                        row_delta = suggested_indent.len - current_indent.len;
 9667                    }
 9668                    continue;
 9669                }
 9670
 9671                // If current indent is more than suggested indent
 9672                // only move cursor to current indent and skip indent
 9673                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9674                    selection.start = Point::new(cursor.row, current_indent.len);
 9675                    selection.end = selection.start;
 9676                    continue;
 9677                }
 9678            }
 9679
 9680            // Otherwise, insert a hard or soft tab.
 9681            let settings = buffer.language_settings_at(cursor, cx);
 9682            let tab_size = if settings.hard_tabs {
 9683                IndentSize::tab()
 9684            } else {
 9685                let tab_size = settings.tab_size.get();
 9686                let indent_remainder = snapshot
 9687                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9688                    .flat_map(str::chars)
 9689                    .fold(row_delta % tab_size, |counter: u32, c| {
 9690                        if c == '\t' {
 9691                            0
 9692                        } else {
 9693                            (counter + 1) % tab_size
 9694                        }
 9695                    });
 9696
 9697                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9698                IndentSize::spaces(chars_to_next_tab_stop)
 9699            };
 9700            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9701            selection.end = selection.start;
 9702            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9703            row_delta += tab_size.len;
 9704        }
 9705
 9706        self.transact(window, cx, |this, window, cx| {
 9707            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9708            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9709                s.select(selections)
 9710            });
 9711            this.refresh_inline_completion(true, false, window, cx);
 9712        });
 9713    }
 9714
 9715    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9716        if self.read_only(cx) {
 9717            return;
 9718        }
 9719        if self.mode.is_single_line() {
 9720            cx.propagate();
 9721            return;
 9722        }
 9723
 9724        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9725        let mut selections = self.selections.all::<Point>(cx);
 9726        let mut prev_edited_row = 0;
 9727        let mut row_delta = 0;
 9728        let mut edits = Vec::new();
 9729        let buffer = self.buffer.read(cx);
 9730        let snapshot = buffer.snapshot(cx);
 9731        for selection in &mut selections {
 9732            if selection.start.row != prev_edited_row {
 9733                row_delta = 0;
 9734            }
 9735            prev_edited_row = selection.end.row;
 9736
 9737            row_delta =
 9738                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9739        }
 9740
 9741        self.transact(window, cx, |this, window, cx| {
 9742            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9743            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9744                s.select(selections)
 9745            });
 9746        });
 9747    }
 9748
 9749    fn indent_selection(
 9750        buffer: &MultiBuffer,
 9751        snapshot: &MultiBufferSnapshot,
 9752        selection: &mut Selection<Point>,
 9753        edits: &mut Vec<(Range<Point>, String)>,
 9754        delta_for_start_row: u32,
 9755        cx: &App,
 9756    ) -> u32 {
 9757        let settings = buffer.language_settings_at(selection.start, cx);
 9758        let tab_size = settings.tab_size.get();
 9759        let indent_kind = if settings.hard_tabs {
 9760            IndentKind::Tab
 9761        } else {
 9762            IndentKind::Space
 9763        };
 9764        let mut start_row = selection.start.row;
 9765        let mut end_row = selection.end.row + 1;
 9766
 9767        // If a selection ends at the beginning of a line, don't indent
 9768        // that last line.
 9769        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9770            end_row -= 1;
 9771        }
 9772
 9773        // Avoid re-indenting a row that has already been indented by a
 9774        // previous selection, but still update this selection's column
 9775        // to reflect that indentation.
 9776        if delta_for_start_row > 0 {
 9777            start_row += 1;
 9778            selection.start.column += delta_for_start_row;
 9779            if selection.end.row == selection.start.row {
 9780                selection.end.column += delta_for_start_row;
 9781            }
 9782        }
 9783
 9784        let mut delta_for_end_row = 0;
 9785        let has_multiple_rows = start_row + 1 != end_row;
 9786        for row in start_row..end_row {
 9787            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9788            let indent_delta = match (current_indent.kind, indent_kind) {
 9789                (IndentKind::Space, IndentKind::Space) => {
 9790                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9791                    IndentSize::spaces(columns_to_next_tab_stop)
 9792                }
 9793                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9794                (_, IndentKind::Tab) => IndentSize::tab(),
 9795            };
 9796
 9797            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9798                0
 9799            } else {
 9800                selection.start.column
 9801            };
 9802            let row_start = Point::new(row, start);
 9803            edits.push((
 9804                row_start..row_start,
 9805                indent_delta.chars().collect::<String>(),
 9806            ));
 9807
 9808            // Update this selection's endpoints to reflect the indentation.
 9809            if row == selection.start.row {
 9810                selection.start.column += indent_delta.len;
 9811            }
 9812            if row == selection.end.row {
 9813                selection.end.column += indent_delta.len;
 9814                delta_for_end_row = indent_delta.len;
 9815            }
 9816        }
 9817
 9818        if selection.start.row == selection.end.row {
 9819            delta_for_start_row + delta_for_end_row
 9820        } else {
 9821            delta_for_end_row
 9822        }
 9823    }
 9824
 9825    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9826        if self.read_only(cx) {
 9827            return;
 9828        }
 9829        if self.mode.is_single_line() {
 9830            cx.propagate();
 9831            return;
 9832        }
 9833
 9834        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9835        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9836        let selections = self.selections.all::<Point>(cx);
 9837        let mut deletion_ranges = Vec::new();
 9838        let mut last_outdent = None;
 9839        {
 9840            let buffer = self.buffer.read(cx);
 9841            let snapshot = buffer.snapshot(cx);
 9842            for selection in &selections {
 9843                let settings = buffer.language_settings_at(selection.start, cx);
 9844                let tab_size = settings.tab_size.get();
 9845                let mut rows = selection.spanned_rows(false, &display_map);
 9846
 9847                // Avoid re-outdenting a row that has already been outdented by a
 9848                // previous selection.
 9849                if let Some(last_row) = last_outdent {
 9850                    if last_row == rows.start {
 9851                        rows.start = rows.start.next_row();
 9852                    }
 9853                }
 9854                let has_multiple_rows = rows.len() > 1;
 9855                for row in rows.iter_rows() {
 9856                    let indent_size = snapshot.indent_size_for_line(row);
 9857                    if indent_size.len > 0 {
 9858                        let deletion_len = match indent_size.kind {
 9859                            IndentKind::Space => {
 9860                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9861                                if columns_to_prev_tab_stop == 0 {
 9862                                    tab_size
 9863                                } else {
 9864                                    columns_to_prev_tab_stop
 9865                                }
 9866                            }
 9867                            IndentKind::Tab => 1,
 9868                        };
 9869                        let start = if has_multiple_rows
 9870                            || deletion_len > selection.start.column
 9871                            || indent_size.len < selection.start.column
 9872                        {
 9873                            0
 9874                        } else {
 9875                            selection.start.column - deletion_len
 9876                        };
 9877                        deletion_ranges.push(
 9878                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9879                        );
 9880                        last_outdent = Some(row);
 9881                    }
 9882                }
 9883            }
 9884        }
 9885
 9886        self.transact(window, cx, |this, window, cx| {
 9887            this.buffer.update(cx, |buffer, cx| {
 9888                let empty_str: Arc<str> = Arc::default();
 9889                buffer.edit(
 9890                    deletion_ranges
 9891                        .into_iter()
 9892                        .map(|range| (range, empty_str.clone())),
 9893                    None,
 9894                    cx,
 9895                );
 9896            });
 9897            let selections = this.selections.all::<usize>(cx);
 9898            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9899                s.select(selections)
 9900            });
 9901        });
 9902    }
 9903
 9904    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9905        if self.read_only(cx) {
 9906            return;
 9907        }
 9908        if self.mode.is_single_line() {
 9909            cx.propagate();
 9910            return;
 9911        }
 9912
 9913        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9914        let selections = self
 9915            .selections
 9916            .all::<usize>(cx)
 9917            .into_iter()
 9918            .map(|s| s.range());
 9919
 9920        self.transact(window, cx, |this, window, cx| {
 9921            this.buffer.update(cx, |buffer, cx| {
 9922                buffer.autoindent_ranges(selections, cx);
 9923            });
 9924            let selections = this.selections.all::<usize>(cx);
 9925            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9926                s.select(selections)
 9927            });
 9928        });
 9929    }
 9930
 9931    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9933        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9934        let selections = self.selections.all::<Point>(cx);
 9935
 9936        let mut new_cursors = Vec::new();
 9937        let mut edit_ranges = Vec::new();
 9938        let mut selections = selections.iter().peekable();
 9939        while let Some(selection) = selections.next() {
 9940            let mut rows = selection.spanned_rows(false, &display_map);
 9941            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9942
 9943            // Accumulate contiguous regions of rows that we want to delete.
 9944            while let Some(next_selection) = selections.peek() {
 9945                let next_rows = next_selection.spanned_rows(false, &display_map);
 9946                if next_rows.start <= rows.end {
 9947                    rows.end = next_rows.end;
 9948                    selections.next().unwrap();
 9949                } else {
 9950                    break;
 9951                }
 9952            }
 9953
 9954            let buffer = &display_map.buffer_snapshot;
 9955            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9956            let edit_end;
 9957            let cursor_buffer_row;
 9958            if buffer.max_point().row >= rows.end.0 {
 9959                // If there's a line after the range, delete the \n from the end of the row range
 9960                // and position the cursor on the next line.
 9961                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9962                cursor_buffer_row = rows.end;
 9963            } else {
 9964                // If there isn't a line after the range, delete the \n from the line before the
 9965                // start of the row range and position the cursor there.
 9966                edit_start = edit_start.saturating_sub(1);
 9967                edit_end = buffer.len();
 9968                cursor_buffer_row = rows.start.previous_row();
 9969            }
 9970
 9971            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9972            *cursor.column_mut() =
 9973                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9974
 9975            new_cursors.push((
 9976                selection.id,
 9977                buffer.anchor_after(cursor.to_point(&display_map)),
 9978            ));
 9979            edit_ranges.push(edit_start..edit_end);
 9980        }
 9981
 9982        self.transact(window, cx, |this, window, cx| {
 9983            let buffer = this.buffer.update(cx, |buffer, cx| {
 9984                let empty_str: Arc<str> = Arc::default();
 9985                buffer.edit(
 9986                    edit_ranges
 9987                        .into_iter()
 9988                        .map(|range| (range, empty_str.clone())),
 9989                    None,
 9990                    cx,
 9991                );
 9992                buffer.snapshot(cx)
 9993            });
 9994            let new_selections = new_cursors
 9995                .into_iter()
 9996                .map(|(id, cursor)| {
 9997                    let cursor = cursor.to_point(&buffer);
 9998                    Selection {
 9999                        id,
10000                        start: cursor,
10001                        end: cursor,
10002                        reversed: false,
10003                        goal: SelectionGoal::None,
10004                    }
10005                })
10006                .collect();
10007
10008            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10009                s.select(new_selections);
10010            });
10011        });
10012    }
10013
10014    pub fn join_lines_impl(
10015        &mut self,
10016        insert_whitespace: bool,
10017        window: &mut Window,
10018        cx: &mut Context<Self>,
10019    ) {
10020        if self.read_only(cx) {
10021            return;
10022        }
10023        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10024        for selection in self.selections.all::<Point>(cx) {
10025            let start = MultiBufferRow(selection.start.row);
10026            // Treat single line selections as if they include the next line. Otherwise this action
10027            // would do nothing for single line selections individual cursors.
10028            let end = if selection.start.row == selection.end.row {
10029                MultiBufferRow(selection.start.row + 1)
10030            } else {
10031                MultiBufferRow(selection.end.row)
10032            };
10033
10034            if let Some(last_row_range) = row_ranges.last_mut() {
10035                if start <= last_row_range.end {
10036                    last_row_range.end = end;
10037                    continue;
10038                }
10039            }
10040            row_ranges.push(start..end);
10041        }
10042
10043        let snapshot = self.buffer.read(cx).snapshot(cx);
10044        let mut cursor_positions = Vec::new();
10045        for row_range in &row_ranges {
10046            let anchor = snapshot.anchor_before(Point::new(
10047                row_range.end.previous_row().0,
10048                snapshot.line_len(row_range.end.previous_row()),
10049            ));
10050            cursor_positions.push(anchor..anchor);
10051        }
10052
10053        self.transact(window, cx, |this, window, cx| {
10054            for row_range in row_ranges.into_iter().rev() {
10055                for row in row_range.iter_rows().rev() {
10056                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10057                    let next_line_row = row.next_row();
10058                    let indent = snapshot.indent_size_for_line(next_line_row);
10059                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10060
10061                    let replace =
10062                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10063                            " "
10064                        } else {
10065                            ""
10066                        };
10067
10068                    this.buffer.update(cx, |buffer, cx| {
10069                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10070                    });
10071                }
10072            }
10073
10074            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10075                s.select_anchor_ranges(cursor_positions)
10076            });
10077        });
10078    }
10079
10080    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10081        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10082        self.join_lines_impl(true, window, cx);
10083    }
10084
10085    pub fn sort_lines_case_sensitive(
10086        &mut self,
10087        _: &SortLinesCaseSensitive,
10088        window: &mut Window,
10089        cx: &mut Context<Self>,
10090    ) {
10091        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10092    }
10093
10094    pub fn sort_lines_case_insensitive(
10095        &mut self,
10096        _: &SortLinesCaseInsensitive,
10097        window: &mut Window,
10098        cx: &mut Context<Self>,
10099    ) {
10100        self.manipulate_immutable_lines(window, cx, |lines| {
10101            lines.sort_by_key(|line| line.to_lowercase())
10102        })
10103    }
10104
10105    pub fn unique_lines_case_insensitive(
10106        &mut self,
10107        _: &UniqueLinesCaseInsensitive,
10108        window: &mut Window,
10109        cx: &mut Context<Self>,
10110    ) {
10111        self.manipulate_immutable_lines(window, cx, |lines| {
10112            let mut seen = HashSet::default();
10113            lines.retain(|line| seen.insert(line.to_lowercase()));
10114        })
10115    }
10116
10117    pub fn unique_lines_case_sensitive(
10118        &mut self,
10119        _: &UniqueLinesCaseSensitive,
10120        window: &mut Window,
10121        cx: &mut Context<Self>,
10122    ) {
10123        self.manipulate_immutable_lines(window, cx, |lines| {
10124            let mut seen = HashSet::default();
10125            lines.retain(|line| seen.insert(*line));
10126        })
10127    }
10128
10129    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10130        let Some(project) = self.project.clone() else {
10131            return;
10132        };
10133        self.reload(project, window, cx)
10134            .detach_and_notify_err(window, cx);
10135    }
10136
10137    pub fn restore_file(
10138        &mut self,
10139        _: &::git::RestoreFile,
10140        window: &mut Window,
10141        cx: &mut Context<Self>,
10142    ) {
10143        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10144        let mut buffer_ids = HashSet::default();
10145        let snapshot = self.buffer().read(cx).snapshot(cx);
10146        for selection in self.selections.all::<usize>(cx) {
10147            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10148        }
10149
10150        let buffer = self.buffer().read(cx);
10151        let ranges = buffer_ids
10152            .into_iter()
10153            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10154            .collect::<Vec<_>>();
10155
10156        self.restore_hunks_in_ranges(ranges, window, cx);
10157    }
10158
10159    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10160        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10161        let selections = self
10162            .selections
10163            .all(cx)
10164            .into_iter()
10165            .map(|s| s.range())
10166            .collect();
10167        self.restore_hunks_in_ranges(selections, window, cx);
10168    }
10169
10170    pub fn restore_hunks_in_ranges(
10171        &mut self,
10172        ranges: Vec<Range<Point>>,
10173        window: &mut Window,
10174        cx: &mut Context<Editor>,
10175    ) {
10176        let mut revert_changes = HashMap::default();
10177        let chunk_by = self
10178            .snapshot(window, cx)
10179            .hunks_for_ranges(ranges)
10180            .into_iter()
10181            .chunk_by(|hunk| hunk.buffer_id);
10182        for (buffer_id, hunks) in &chunk_by {
10183            let hunks = hunks.collect::<Vec<_>>();
10184            for hunk in &hunks {
10185                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10186            }
10187            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10188        }
10189        drop(chunk_by);
10190        if !revert_changes.is_empty() {
10191            self.transact(window, cx, |editor, window, cx| {
10192                editor.restore(revert_changes, window, cx);
10193            });
10194        }
10195    }
10196
10197    pub fn open_active_item_in_terminal(
10198        &mut self,
10199        _: &OpenInTerminal,
10200        window: &mut Window,
10201        cx: &mut Context<Self>,
10202    ) {
10203        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10204            let project_path = buffer.read(cx).project_path(cx)?;
10205            let project = self.project.as_ref()?.read(cx);
10206            let entry = project.entry_for_path(&project_path, cx)?;
10207            let parent = match &entry.canonical_path {
10208                Some(canonical_path) => canonical_path.to_path_buf(),
10209                None => project.absolute_path(&project_path, cx)?,
10210            }
10211            .parent()?
10212            .to_path_buf();
10213            Some(parent)
10214        }) {
10215            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10216        }
10217    }
10218
10219    fn set_breakpoint_context_menu(
10220        &mut self,
10221        display_row: DisplayRow,
10222        position: Option<Anchor>,
10223        clicked_point: gpui::Point<Pixels>,
10224        window: &mut Window,
10225        cx: &mut Context<Self>,
10226    ) {
10227        let source = self
10228            .buffer
10229            .read(cx)
10230            .snapshot(cx)
10231            .anchor_before(Point::new(display_row.0, 0u32));
10232
10233        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10234
10235        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10236            self,
10237            source,
10238            clicked_point,
10239            context_menu,
10240            window,
10241            cx,
10242        );
10243    }
10244
10245    fn add_edit_breakpoint_block(
10246        &mut self,
10247        anchor: Anchor,
10248        breakpoint: &Breakpoint,
10249        edit_action: BreakpointPromptEditAction,
10250        window: &mut Window,
10251        cx: &mut Context<Self>,
10252    ) {
10253        let weak_editor = cx.weak_entity();
10254        let bp_prompt = cx.new(|cx| {
10255            BreakpointPromptEditor::new(
10256                weak_editor,
10257                anchor,
10258                breakpoint.clone(),
10259                edit_action,
10260                window,
10261                cx,
10262            )
10263        });
10264
10265        let height = bp_prompt.update(cx, |this, cx| {
10266            this.prompt
10267                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10268        });
10269        let cloned_prompt = bp_prompt.clone();
10270        let blocks = vec![BlockProperties {
10271            style: BlockStyle::Sticky,
10272            placement: BlockPlacement::Above(anchor),
10273            height: Some(height),
10274            render: Arc::new(move |cx| {
10275                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10276                cloned_prompt.clone().into_any_element()
10277            }),
10278            priority: 0,
10279            render_in_minimap: true,
10280        }];
10281
10282        let focus_handle = bp_prompt.focus_handle(cx);
10283        window.focus(&focus_handle);
10284
10285        let block_ids = self.insert_blocks(blocks, None, cx);
10286        bp_prompt.update(cx, |prompt, _| {
10287            prompt.add_block_ids(block_ids);
10288        });
10289    }
10290
10291    pub(crate) fn breakpoint_at_row(
10292        &self,
10293        row: u32,
10294        window: &mut Window,
10295        cx: &mut Context<Self>,
10296    ) -> Option<(Anchor, Breakpoint)> {
10297        let snapshot = self.snapshot(window, cx);
10298        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10299
10300        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10301    }
10302
10303    pub(crate) fn breakpoint_at_anchor(
10304        &self,
10305        breakpoint_position: Anchor,
10306        snapshot: &EditorSnapshot,
10307        cx: &mut Context<Self>,
10308    ) -> Option<(Anchor, Breakpoint)> {
10309        let project = self.project.clone()?;
10310
10311        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10312            snapshot
10313                .buffer_snapshot
10314                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10315        })?;
10316
10317        let enclosing_excerpt = breakpoint_position.excerpt_id;
10318        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10319        let buffer_snapshot = buffer.read(cx).snapshot();
10320
10321        let row = buffer_snapshot
10322            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10323            .row;
10324
10325        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10326        let anchor_end = snapshot
10327            .buffer_snapshot
10328            .anchor_after(Point::new(row, line_len));
10329
10330        let bp = self
10331            .breakpoint_store
10332            .as_ref()?
10333            .read_with(cx, |breakpoint_store, cx| {
10334                breakpoint_store
10335                    .breakpoints(
10336                        &buffer,
10337                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10338                        &buffer_snapshot,
10339                        cx,
10340                    )
10341                    .next()
10342                    .and_then(|(bp, _)| {
10343                        let breakpoint_row = buffer_snapshot
10344                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10345                            .row;
10346
10347                        if breakpoint_row == row {
10348                            snapshot
10349                                .buffer_snapshot
10350                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10351                                .map(|position| (position, bp.bp.clone()))
10352                        } else {
10353                            None
10354                        }
10355                    })
10356            });
10357        bp
10358    }
10359
10360    pub fn edit_log_breakpoint(
10361        &mut self,
10362        _: &EditLogBreakpoint,
10363        window: &mut Window,
10364        cx: &mut Context<Self>,
10365    ) {
10366        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10367            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10368                message: None,
10369                state: BreakpointState::Enabled,
10370                condition: None,
10371                hit_condition: None,
10372            });
10373
10374            self.add_edit_breakpoint_block(
10375                anchor,
10376                &breakpoint,
10377                BreakpointPromptEditAction::Log,
10378                window,
10379                cx,
10380            );
10381        }
10382    }
10383
10384    fn breakpoints_at_cursors(
10385        &self,
10386        window: &mut Window,
10387        cx: &mut Context<Self>,
10388    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10389        let snapshot = self.snapshot(window, cx);
10390        let cursors = self
10391            .selections
10392            .disjoint_anchors()
10393            .into_iter()
10394            .map(|selection| {
10395                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10396
10397                let breakpoint_position = self
10398                    .breakpoint_at_row(cursor_position.row, window, cx)
10399                    .map(|bp| bp.0)
10400                    .unwrap_or_else(|| {
10401                        snapshot
10402                            .display_snapshot
10403                            .buffer_snapshot
10404                            .anchor_after(Point::new(cursor_position.row, 0))
10405                    });
10406
10407                let breakpoint = self
10408                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10409                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10410
10411                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10412            })
10413            // 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.
10414            .collect::<HashMap<Anchor, _>>();
10415
10416        cursors.into_iter().collect()
10417    }
10418
10419    pub fn enable_breakpoint(
10420        &mut self,
10421        _: &crate::actions::EnableBreakpoint,
10422        window: &mut Window,
10423        cx: &mut Context<Self>,
10424    ) {
10425        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10426            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10427                continue;
10428            };
10429            self.edit_breakpoint_at_anchor(
10430                anchor,
10431                breakpoint,
10432                BreakpointEditAction::InvertState,
10433                cx,
10434            );
10435        }
10436    }
10437
10438    pub fn disable_breakpoint(
10439        &mut self,
10440        _: &crate::actions::DisableBreakpoint,
10441        window: &mut Window,
10442        cx: &mut Context<Self>,
10443    ) {
10444        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10445            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10446                continue;
10447            };
10448            self.edit_breakpoint_at_anchor(
10449                anchor,
10450                breakpoint,
10451                BreakpointEditAction::InvertState,
10452                cx,
10453            );
10454        }
10455    }
10456
10457    pub fn toggle_breakpoint(
10458        &mut self,
10459        _: &crate::actions::ToggleBreakpoint,
10460        window: &mut Window,
10461        cx: &mut Context<Self>,
10462    ) {
10463        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10464            if let Some(breakpoint) = breakpoint {
10465                self.edit_breakpoint_at_anchor(
10466                    anchor,
10467                    breakpoint,
10468                    BreakpointEditAction::Toggle,
10469                    cx,
10470                );
10471            } else {
10472                self.edit_breakpoint_at_anchor(
10473                    anchor,
10474                    Breakpoint::new_standard(),
10475                    BreakpointEditAction::Toggle,
10476                    cx,
10477                );
10478            }
10479        }
10480    }
10481
10482    pub fn edit_breakpoint_at_anchor(
10483        &mut self,
10484        breakpoint_position: Anchor,
10485        breakpoint: Breakpoint,
10486        edit_action: BreakpointEditAction,
10487        cx: &mut Context<Self>,
10488    ) {
10489        let Some(breakpoint_store) = &self.breakpoint_store else {
10490            return;
10491        };
10492
10493        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10494            if breakpoint_position == Anchor::min() {
10495                self.buffer()
10496                    .read(cx)
10497                    .excerpt_buffer_ids()
10498                    .into_iter()
10499                    .next()
10500            } else {
10501                None
10502            }
10503        }) else {
10504            return;
10505        };
10506
10507        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10508            return;
10509        };
10510
10511        breakpoint_store.update(cx, |breakpoint_store, cx| {
10512            breakpoint_store.toggle_breakpoint(
10513                buffer,
10514                BreakpointWithPosition {
10515                    position: breakpoint_position.text_anchor,
10516                    bp: breakpoint,
10517                },
10518                edit_action,
10519                cx,
10520            );
10521        });
10522
10523        cx.notify();
10524    }
10525
10526    #[cfg(any(test, feature = "test-support"))]
10527    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10528        self.breakpoint_store.clone()
10529    }
10530
10531    pub fn prepare_restore_change(
10532        &self,
10533        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10534        hunk: &MultiBufferDiffHunk,
10535        cx: &mut App,
10536    ) -> Option<()> {
10537        if hunk.is_created_file() {
10538            return None;
10539        }
10540        let buffer = self.buffer.read(cx);
10541        let diff = buffer.diff_for(hunk.buffer_id)?;
10542        let buffer = buffer.buffer(hunk.buffer_id)?;
10543        let buffer = buffer.read(cx);
10544        let original_text = diff
10545            .read(cx)
10546            .base_text()
10547            .as_rope()
10548            .slice(hunk.diff_base_byte_range.clone());
10549        let buffer_snapshot = buffer.snapshot();
10550        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10551        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10552            probe
10553                .0
10554                .start
10555                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10556                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10557        }) {
10558            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10559            Some(())
10560        } else {
10561            None
10562        }
10563    }
10564
10565    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10566        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10567    }
10568
10569    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10570        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10571    }
10572
10573    fn manipulate_lines<M>(
10574        &mut self,
10575        window: &mut Window,
10576        cx: &mut Context<Self>,
10577        mut manipulate: M,
10578    ) where
10579        M: FnMut(&str) -> LineManipulationResult,
10580    {
10581        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10582
10583        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10584        let buffer = self.buffer.read(cx).snapshot(cx);
10585
10586        let mut edits = Vec::new();
10587
10588        let selections = self.selections.all::<Point>(cx);
10589        let mut selections = selections.iter().peekable();
10590        let mut contiguous_row_selections = Vec::new();
10591        let mut new_selections = Vec::new();
10592        let mut added_lines = 0;
10593        let mut removed_lines = 0;
10594
10595        while let Some(selection) = selections.next() {
10596            let (start_row, end_row) = consume_contiguous_rows(
10597                &mut contiguous_row_selections,
10598                selection,
10599                &display_map,
10600                &mut selections,
10601            );
10602
10603            let start_point = Point::new(start_row.0, 0);
10604            let end_point = Point::new(
10605                end_row.previous_row().0,
10606                buffer.line_len(end_row.previous_row()),
10607            );
10608            let text = buffer
10609                .text_for_range(start_point..end_point)
10610                .collect::<String>();
10611
10612            let LineManipulationResult {
10613                new_text,
10614                line_count_before,
10615                line_count_after,
10616            } = manipulate(&text);
10617
10618            edits.push((start_point..end_point, new_text));
10619
10620            // Selections must change based on added and removed line count
10621            let start_row =
10622                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10623            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10624            new_selections.push(Selection {
10625                id: selection.id,
10626                start: start_row,
10627                end: end_row,
10628                goal: SelectionGoal::None,
10629                reversed: selection.reversed,
10630            });
10631
10632            if line_count_after > line_count_before {
10633                added_lines += line_count_after - line_count_before;
10634            } else if line_count_before > line_count_after {
10635                removed_lines += line_count_before - line_count_after;
10636            }
10637        }
10638
10639        self.transact(window, cx, |this, window, cx| {
10640            let buffer = this.buffer.update(cx, |buffer, cx| {
10641                buffer.edit(edits, None, cx);
10642                buffer.snapshot(cx)
10643            });
10644
10645            // Recalculate offsets on newly edited buffer
10646            let new_selections = new_selections
10647                .iter()
10648                .map(|s| {
10649                    let start_point = Point::new(s.start.0, 0);
10650                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10651                    Selection {
10652                        id: s.id,
10653                        start: buffer.point_to_offset(start_point),
10654                        end: buffer.point_to_offset(end_point),
10655                        goal: s.goal,
10656                        reversed: s.reversed,
10657                    }
10658                })
10659                .collect();
10660
10661            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10662                s.select(new_selections);
10663            });
10664
10665            this.request_autoscroll(Autoscroll::fit(), cx);
10666        });
10667    }
10668
10669    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10670        self.manipulate_text(window, cx, |text| {
10671            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10672            if has_upper_case_characters {
10673                text.to_lowercase()
10674            } else {
10675                text.to_uppercase()
10676            }
10677        })
10678    }
10679
10680    fn manipulate_immutable_lines<Fn>(
10681        &mut self,
10682        window: &mut Window,
10683        cx: &mut Context<Self>,
10684        mut callback: Fn,
10685    ) where
10686        Fn: FnMut(&mut Vec<&str>),
10687    {
10688        self.manipulate_lines(window, cx, |text| {
10689            let mut lines: Vec<&str> = text.split('\n').collect();
10690            let line_count_before = lines.len();
10691
10692            callback(&mut lines);
10693
10694            LineManipulationResult {
10695                new_text: lines.join("\n"),
10696                line_count_before,
10697                line_count_after: lines.len(),
10698            }
10699        });
10700    }
10701
10702    fn manipulate_mutable_lines<Fn>(
10703        &mut self,
10704        window: &mut Window,
10705        cx: &mut Context<Self>,
10706        mut callback: Fn,
10707    ) where
10708        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10709    {
10710        self.manipulate_lines(window, cx, |text| {
10711            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10712            let line_count_before = lines.len();
10713
10714            callback(&mut lines);
10715
10716            LineManipulationResult {
10717                new_text: lines.join("\n"),
10718                line_count_before,
10719                line_count_after: lines.len(),
10720            }
10721        });
10722    }
10723
10724    pub fn convert_indentation_to_spaces(
10725        &mut self,
10726        _: &ConvertIndentationToSpaces,
10727        window: &mut Window,
10728        cx: &mut Context<Self>,
10729    ) {
10730        let settings = self.buffer.read(cx).language_settings(cx);
10731        let tab_size = settings.tab_size.get() as usize;
10732
10733        self.manipulate_mutable_lines(window, cx, |lines| {
10734            // Allocates a reasonably sized scratch buffer once for the whole loop
10735            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10736            // Avoids recomputing spaces that could be inserted many times
10737            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10738                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10739                .collect();
10740
10741            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10742                let mut chars = line.as_ref().chars();
10743                let mut col = 0;
10744                let mut changed = false;
10745
10746                while let Some(ch) = chars.next() {
10747                    match ch {
10748                        ' ' => {
10749                            reindented_line.push(' ');
10750                            col += 1;
10751                        }
10752                        '\t' => {
10753                            // \t are converted to spaces depending on the current column
10754                            let spaces_len = tab_size - (col % tab_size);
10755                            reindented_line.extend(&space_cache[spaces_len - 1]);
10756                            col += spaces_len;
10757                            changed = true;
10758                        }
10759                        _ => {
10760                            // If we dont append before break, the character is consumed
10761                            reindented_line.push(ch);
10762                            break;
10763                        }
10764                    }
10765                }
10766
10767                if !changed {
10768                    reindented_line.clear();
10769                    continue;
10770                }
10771                // Append the rest of the line and replace old reference with new one
10772                reindented_line.extend(chars);
10773                *line = Cow::Owned(reindented_line.clone());
10774                reindented_line.clear();
10775            }
10776        });
10777    }
10778
10779    pub fn convert_indentation_to_tabs(
10780        &mut self,
10781        _: &ConvertIndentationToTabs,
10782        window: &mut Window,
10783        cx: &mut Context<Self>,
10784    ) {
10785        let settings = self.buffer.read(cx).language_settings(cx);
10786        let tab_size = settings.tab_size.get() as usize;
10787
10788        self.manipulate_mutable_lines(window, cx, |lines| {
10789            // Allocates a reasonably sized buffer once for the whole loop
10790            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10791            // Avoids recomputing spaces that could be inserted many times
10792            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10793                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10794                .collect();
10795
10796            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10797                let mut chars = line.chars();
10798                let mut spaces_count = 0;
10799                let mut first_non_indent_char = None;
10800                let mut changed = false;
10801
10802                while let Some(ch) = chars.next() {
10803                    match ch {
10804                        ' ' => {
10805                            // Keep track of spaces. Append \t when we reach tab_size
10806                            spaces_count += 1;
10807                            changed = true;
10808                            if spaces_count == tab_size {
10809                                reindented_line.push('\t');
10810                                spaces_count = 0;
10811                            }
10812                        }
10813                        '\t' => {
10814                            reindented_line.push('\t');
10815                            spaces_count = 0;
10816                        }
10817                        _ => {
10818                            // Dont append it yet, we might have remaining spaces
10819                            first_non_indent_char = Some(ch);
10820                            break;
10821                        }
10822                    }
10823                }
10824
10825                if !changed {
10826                    reindented_line.clear();
10827                    continue;
10828                }
10829                // Remaining spaces that didn't make a full tab stop
10830                if spaces_count > 0 {
10831                    reindented_line.extend(&space_cache[spaces_count - 1]);
10832                }
10833                // If we consume an extra character that was not indentation, add it back
10834                if let Some(extra_char) = first_non_indent_char {
10835                    reindented_line.push(extra_char);
10836                }
10837                // Append the rest of the line and replace old reference with new one
10838                reindented_line.extend(chars);
10839                *line = Cow::Owned(reindented_line.clone());
10840                reindented_line.clear();
10841            }
10842        });
10843    }
10844
10845    pub fn convert_to_upper_case(
10846        &mut self,
10847        _: &ConvertToUpperCase,
10848        window: &mut Window,
10849        cx: &mut Context<Self>,
10850    ) {
10851        self.manipulate_text(window, cx, |text| text.to_uppercase())
10852    }
10853
10854    pub fn convert_to_lower_case(
10855        &mut self,
10856        _: &ConvertToLowerCase,
10857        window: &mut Window,
10858        cx: &mut Context<Self>,
10859    ) {
10860        self.manipulate_text(window, cx, |text| text.to_lowercase())
10861    }
10862
10863    pub fn convert_to_title_case(
10864        &mut self,
10865        _: &ConvertToTitleCase,
10866        window: &mut Window,
10867        cx: &mut Context<Self>,
10868    ) {
10869        self.manipulate_text(window, cx, |text| {
10870            text.split('\n')
10871                .map(|line| line.to_case(Case::Title))
10872                .join("\n")
10873        })
10874    }
10875
10876    pub fn convert_to_snake_case(
10877        &mut self,
10878        _: &ConvertToSnakeCase,
10879        window: &mut Window,
10880        cx: &mut Context<Self>,
10881    ) {
10882        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10883    }
10884
10885    pub fn convert_to_kebab_case(
10886        &mut self,
10887        _: &ConvertToKebabCase,
10888        window: &mut Window,
10889        cx: &mut Context<Self>,
10890    ) {
10891        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10892    }
10893
10894    pub fn convert_to_upper_camel_case(
10895        &mut self,
10896        _: &ConvertToUpperCamelCase,
10897        window: &mut Window,
10898        cx: &mut Context<Self>,
10899    ) {
10900        self.manipulate_text(window, cx, |text| {
10901            text.split('\n')
10902                .map(|line| line.to_case(Case::UpperCamel))
10903                .join("\n")
10904        })
10905    }
10906
10907    pub fn convert_to_lower_camel_case(
10908        &mut self,
10909        _: &ConvertToLowerCamelCase,
10910        window: &mut Window,
10911        cx: &mut Context<Self>,
10912    ) {
10913        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10914    }
10915
10916    pub fn convert_to_opposite_case(
10917        &mut self,
10918        _: &ConvertToOppositeCase,
10919        window: &mut Window,
10920        cx: &mut Context<Self>,
10921    ) {
10922        self.manipulate_text(window, cx, |text| {
10923            text.chars()
10924                .fold(String::with_capacity(text.len()), |mut t, c| {
10925                    if c.is_uppercase() {
10926                        t.extend(c.to_lowercase());
10927                    } else {
10928                        t.extend(c.to_uppercase());
10929                    }
10930                    t
10931                })
10932        })
10933    }
10934
10935    pub fn convert_to_rot13(
10936        &mut self,
10937        _: &ConvertToRot13,
10938        window: &mut Window,
10939        cx: &mut Context<Self>,
10940    ) {
10941        self.manipulate_text(window, cx, |text| {
10942            text.chars()
10943                .map(|c| match c {
10944                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10945                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10946                    _ => c,
10947                })
10948                .collect()
10949        })
10950    }
10951
10952    pub fn convert_to_rot47(
10953        &mut self,
10954        _: &ConvertToRot47,
10955        window: &mut Window,
10956        cx: &mut Context<Self>,
10957    ) {
10958        self.manipulate_text(window, cx, |text| {
10959            text.chars()
10960                .map(|c| {
10961                    let code_point = c as u32;
10962                    if code_point >= 33 && code_point <= 126 {
10963                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10964                    }
10965                    c
10966                })
10967                .collect()
10968        })
10969    }
10970
10971    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10972    where
10973        Fn: FnMut(&str) -> String,
10974    {
10975        let buffer = self.buffer.read(cx).snapshot(cx);
10976
10977        let mut new_selections = Vec::new();
10978        let mut edits = Vec::new();
10979        let mut selection_adjustment = 0i32;
10980
10981        for selection in self.selections.all::<usize>(cx) {
10982            let selection_is_empty = selection.is_empty();
10983
10984            let (start, end) = if selection_is_empty {
10985                let (word_range, _) = buffer.surrounding_word(selection.start, false);
10986                (word_range.start, word_range.end)
10987            } else {
10988                (selection.start, selection.end)
10989            };
10990
10991            let text = buffer.text_for_range(start..end).collect::<String>();
10992            let old_length = text.len() as i32;
10993            let text = callback(&text);
10994
10995            new_selections.push(Selection {
10996                start: (start as i32 - selection_adjustment) as usize,
10997                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10998                goal: SelectionGoal::None,
10999                ..selection
11000            });
11001
11002            selection_adjustment += old_length - text.len() as i32;
11003
11004            edits.push((start..end, text));
11005        }
11006
11007        self.transact(window, cx, |this, window, cx| {
11008            this.buffer.update(cx, |buffer, cx| {
11009                buffer.edit(edits, None, cx);
11010            });
11011
11012            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11013                s.select(new_selections);
11014            });
11015
11016            this.request_autoscroll(Autoscroll::fit(), cx);
11017        });
11018    }
11019
11020    pub fn move_selection_on_drop(
11021        &mut self,
11022        selection: &Selection<Anchor>,
11023        target: DisplayPoint,
11024        is_cut: bool,
11025        window: &mut Window,
11026        cx: &mut Context<Self>,
11027    ) {
11028        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11029        let buffer = &display_map.buffer_snapshot;
11030        let mut edits = Vec::new();
11031        let insert_point = display_map
11032            .clip_point(target, Bias::Left)
11033            .to_point(&display_map);
11034        let text = buffer
11035            .text_for_range(selection.start..selection.end)
11036            .collect::<String>();
11037        if is_cut {
11038            edits.push(((selection.start..selection.end), String::new()));
11039        }
11040        let insert_anchor = buffer.anchor_before(insert_point);
11041        edits.push(((insert_anchor..insert_anchor), text));
11042        let last_edit_start = insert_anchor.bias_left(buffer);
11043        let last_edit_end = insert_anchor.bias_right(buffer);
11044        self.transact(window, cx, |this, window, cx| {
11045            this.buffer.update(cx, |buffer, cx| {
11046                buffer.edit(edits, None, cx);
11047            });
11048            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11049                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11050            });
11051        });
11052    }
11053
11054    pub fn clear_selection_drag_state(&mut self) {
11055        self.selection_drag_state = SelectionDragState::None;
11056    }
11057
11058    pub fn duplicate(
11059        &mut self,
11060        upwards: bool,
11061        whole_lines: bool,
11062        window: &mut Window,
11063        cx: &mut Context<Self>,
11064    ) {
11065        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11066
11067        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11068        let buffer = &display_map.buffer_snapshot;
11069        let selections = self.selections.all::<Point>(cx);
11070
11071        let mut edits = Vec::new();
11072        let mut selections_iter = selections.iter().peekable();
11073        while let Some(selection) = selections_iter.next() {
11074            let mut rows = selection.spanned_rows(false, &display_map);
11075            // duplicate line-wise
11076            if whole_lines || selection.start == selection.end {
11077                // Avoid duplicating the same lines twice.
11078                while let Some(next_selection) = selections_iter.peek() {
11079                    let next_rows = next_selection.spanned_rows(false, &display_map);
11080                    if next_rows.start < rows.end {
11081                        rows.end = next_rows.end;
11082                        selections_iter.next().unwrap();
11083                    } else {
11084                        break;
11085                    }
11086                }
11087
11088                // Copy the text from the selected row region and splice it either at the start
11089                // or end of the region.
11090                let start = Point::new(rows.start.0, 0);
11091                let end = Point::new(
11092                    rows.end.previous_row().0,
11093                    buffer.line_len(rows.end.previous_row()),
11094                );
11095                let text = buffer
11096                    .text_for_range(start..end)
11097                    .chain(Some("\n"))
11098                    .collect::<String>();
11099                let insert_location = if upwards {
11100                    Point::new(rows.end.0, 0)
11101                } else {
11102                    start
11103                };
11104                edits.push((insert_location..insert_location, text));
11105            } else {
11106                // duplicate character-wise
11107                let start = selection.start;
11108                let end = selection.end;
11109                let text = buffer.text_for_range(start..end).collect::<String>();
11110                edits.push((selection.end..selection.end, text));
11111            }
11112        }
11113
11114        self.transact(window, cx, |this, _, cx| {
11115            this.buffer.update(cx, |buffer, cx| {
11116                buffer.edit(edits, None, cx);
11117            });
11118
11119            this.request_autoscroll(Autoscroll::fit(), cx);
11120        });
11121    }
11122
11123    pub fn duplicate_line_up(
11124        &mut self,
11125        _: &DuplicateLineUp,
11126        window: &mut Window,
11127        cx: &mut Context<Self>,
11128    ) {
11129        self.duplicate(true, true, window, cx);
11130    }
11131
11132    pub fn duplicate_line_down(
11133        &mut self,
11134        _: &DuplicateLineDown,
11135        window: &mut Window,
11136        cx: &mut Context<Self>,
11137    ) {
11138        self.duplicate(false, true, window, cx);
11139    }
11140
11141    pub fn duplicate_selection(
11142        &mut self,
11143        _: &DuplicateSelection,
11144        window: &mut Window,
11145        cx: &mut Context<Self>,
11146    ) {
11147        self.duplicate(false, false, window, cx);
11148    }
11149
11150    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11151        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11152        if self.mode.is_single_line() {
11153            cx.propagate();
11154            return;
11155        }
11156
11157        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11158        let buffer = self.buffer.read(cx).snapshot(cx);
11159
11160        let mut edits = Vec::new();
11161        let mut unfold_ranges = Vec::new();
11162        let mut refold_creases = Vec::new();
11163
11164        let selections = self.selections.all::<Point>(cx);
11165        let mut selections = selections.iter().peekable();
11166        let mut contiguous_row_selections = Vec::new();
11167        let mut new_selections = Vec::new();
11168
11169        while let Some(selection) = selections.next() {
11170            // Find all the selections that span a contiguous row range
11171            let (start_row, end_row) = consume_contiguous_rows(
11172                &mut contiguous_row_selections,
11173                selection,
11174                &display_map,
11175                &mut selections,
11176            );
11177
11178            // Move the text spanned by the row range to be before the line preceding the row range
11179            if start_row.0 > 0 {
11180                let range_to_move = Point::new(
11181                    start_row.previous_row().0,
11182                    buffer.line_len(start_row.previous_row()),
11183                )
11184                    ..Point::new(
11185                        end_row.previous_row().0,
11186                        buffer.line_len(end_row.previous_row()),
11187                    );
11188                let insertion_point = display_map
11189                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11190                    .0;
11191
11192                // Don't move lines across excerpts
11193                if buffer
11194                    .excerpt_containing(insertion_point..range_to_move.end)
11195                    .is_some()
11196                {
11197                    let text = buffer
11198                        .text_for_range(range_to_move.clone())
11199                        .flat_map(|s| s.chars())
11200                        .skip(1)
11201                        .chain(['\n'])
11202                        .collect::<String>();
11203
11204                    edits.push((
11205                        buffer.anchor_after(range_to_move.start)
11206                            ..buffer.anchor_before(range_to_move.end),
11207                        String::new(),
11208                    ));
11209                    let insertion_anchor = buffer.anchor_after(insertion_point);
11210                    edits.push((insertion_anchor..insertion_anchor, text));
11211
11212                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11213
11214                    // Move selections up
11215                    new_selections.extend(contiguous_row_selections.drain(..).map(
11216                        |mut selection| {
11217                            selection.start.row -= row_delta;
11218                            selection.end.row -= row_delta;
11219                            selection
11220                        },
11221                    ));
11222
11223                    // Move folds up
11224                    unfold_ranges.push(range_to_move.clone());
11225                    for fold in display_map.folds_in_range(
11226                        buffer.anchor_before(range_to_move.start)
11227                            ..buffer.anchor_after(range_to_move.end),
11228                    ) {
11229                        let mut start = fold.range.start.to_point(&buffer);
11230                        let mut end = fold.range.end.to_point(&buffer);
11231                        start.row -= row_delta;
11232                        end.row -= row_delta;
11233                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11234                    }
11235                }
11236            }
11237
11238            // If we didn't move line(s), preserve the existing selections
11239            new_selections.append(&mut contiguous_row_selections);
11240        }
11241
11242        self.transact(window, cx, |this, window, cx| {
11243            this.unfold_ranges(&unfold_ranges, true, true, cx);
11244            this.buffer.update(cx, |buffer, cx| {
11245                for (range, text) in edits {
11246                    buffer.edit([(range, text)], None, cx);
11247                }
11248            });
11249            this.fold_creases(refold_creases, true, window, cx);
11250            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11251                s.select(new_selections);
11252            })
11253        });
11254    }
11255
11256    pub fn move_line_down(
11257        &mut self,
11258        _: &MoveLineDown,
11259        window: &mut Window,
11260        cx: &mut Context<Self>,
11261    ) {
11262        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11263        if self.mode.is_single_line() {
11264            cx.propagate();
11265            return;
11266        }
11267
11268        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11269        let buffer = self.buffer.read(cx).snapshot(cx);
11270
11271        let mut edits = Vec::new();
11272        let mut unfold_ranges = Vec::new();
11273        let mut refold_creases = Vec::new();
11274
11275        let selections = self.selections.all::<Point>(cx);
11276        let mut selections = selections.iter().peekable();
11277        let mut contiguous_row_selections = Vec::new();
11278        let mut new_selections = Vec::new();
11279
11280        while let Some(selection) = selections.next() {
11281            // Find all the selections that span a contiguous row range
11282            let (start_row, end_row) = consume_contiguous_rows(
11283                &mut contiguous_row_selections,
11284                selection,
11285                &display_map,
11286                &mut selections,
11287            );
11288
11289            // Move the text spanned by the row range to be after the last line of the row range
11290            if end_row.0 <= buffer.max_point().row {
11291                let range_to_move =
11292                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11293                let insertion_point = display_map
11294                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11295                    .0;
11296
11297                // Don't move lines across excerpt boundaries
11298                if buffer
11299                    .excerpt_containing(range_to_move.start..insertion_point)
11300                    .is_some()
11301                {
11302                    let mut text = String::from("\n");
11303                    text.extend(buffer.text_for_range(range_to_move.clone()));
11304                    text.pop(); // Drop trailing newline
11305                    edits.push((
11306                        buffer.anchor_after(range_to_move.start)
11307                            ..buffer.anchor_before(range_to_move.end),
11308                        String::new(),
11309                    ));
11310                    let insertion_anchor = buffer.anchor_after(insertion_point);
11311                    edits.push((insertion_anchor..insertion_anchor, text));
11312
11313                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11314
11315                    // Move selections down
11316                    new_selections.extend(contiguous_row_selections.drain(..).map(
11317                        |mut selection| {
11318                            selection.start.row += row_delta;
11319                            selection.end.row += row_delta;
11320                            selection
11321                        },
11322                    ));
11323
11324                    // Move folds down
11325                    unfold_ranges.push(range_to_move.clone());
11326                    for fold in display_map.folds_in_range(
11327                        buffer.anchor_before(range_to_move.start)
11328                            ..buffer.anchor_after(range_to_move.end),
11329                    ) {
11330                        let mut start = fold.range.start.to_point(&buffer);
11331                        let mut end = fold.range.end.to_point(&buffer);
11332                        start.row += row_delta;
11333                        end.row += row_delta;
11334                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11335                    }
11336                }
11337            }
11338
11339            // If we didn't move line(s), preserve the existing selections
11340            new_selections.append(&mut contiguous_row_selections);
11341        }
11342
11343        self.transact(window, cx, |this, window, cx| {
11344            this.unfold_ranges(&unfold_ranges, true, true, cx);
11345            this.buffer.update(cx, |buffer, cx| {
11346                for (range, text) in edits {
11347                    buffer.edit([(range, text)], None, cx);
11348                }
11349            });
11350            this.fold_creases(refold_creases, true, window, cx);
11351            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11352                s.select(new_selections)
11353            });
11354        });
11355    }
11356
11357    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11358        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11359        let text_layout_details = &self.text_layout_details(window);
11360        self.transact(window, cx, |this, window, cx| {
11361            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11362                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11363                s.move_with(|display_map, selection| {
11364                    if !selection.is_empty() {
11365                        return;
11366                    }
11367
11368                    let mut head = selection.head();
11369                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11370                    if head.column() == display_map.line_len(head.row()) {
11371                        transpose_offset = display_map
11372                            .buffer_snapshot
11373                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11374                    }
11375
11376                    if transpose_offset == 0 {
11377                        return;
11378                    }
11379
11380                    *head.column_mut() += 1;
11381                    head = display_map.clip_point(head, Bias::Right);
11382                    let goal = SelectionGoal::HorizontalPosition(
11383                        display_map
11384                            .x_for_display_point(head, text_layout_details)
11385                            .into(),
11386                    );
11387                    selection.collapse_to(head, goal);
11388
11389                    let transpose_start = display_map
11390                        .buffer_snapshot
11391                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11392                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11393                        let transpose_end = display_map
11394                            .buffer_snapshot
11395                            .clip_offset(transpose_offset + 1, Bias::Right);
11396                        if let Some(ch) =
11397                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11398                        {
11399                            edits.push((transpose_start..transpose_offset, String::new()));
11400                            edits.push((transpose_end..transpose_end, ch.to_string()));
11401                        }
11402                    }
11403                });
11404                edits
11405            });
11406            this.buffer
11407                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11408            let selections = this.selections.all::<usize>(cx);
11409            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11410                s.select(selections);
11411            });
11412        });
11413    }
11414
11415    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11416        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11417        if self.mode.is_single_line() {
11418            cx.propagate();
11419            return;
11420        }
11421
11422        self.rewrap_impl(RewrapOptions::default(), cx)
11423    }
11424
11425    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11426        let buffer = self.buffer.read(cx).snapshot(cx);
11427        let selections = self.selections.all::<Point>(cx);
11428
11429        // Shrink and split selections to respect paragraph boundaries.
11430        let ranges = selections.into_iter().flat_map(|selection| {
11431            let language_settings = buffer.language_settings_at(selection.head(), cx);
11432            let language_scope = buffer.language_scope_at(selection.head());
11433
11434            let Some(start_row) = (selection.start.row..=selection.end.row)
11435                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11436            else {
11437                return vec![];
11438            };
11439            let Some(end_row) = (selection.start.row..=selection.end.row)
11440                .rev()
11441                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11442            else {
11443                return vec![];
11444            };
11445
11446            let mut row = start_row;
11447            let mut ranges = Vec::new();
11448            while let Some(blank_row) =
11449                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11450            {
11451                let next_paragraph_start = (blank_row + 1..=end_row)
11452                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11453                    .unwrap();
11454                ranges.push((
11455                    language_settings.clone(),
11456                    language_scope.clone(),
11457                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11458                ));
11459                row = next_paragraph_start;
11460            }
11461            ranges.push((
11462                language_settings.clone(),
11463                language_scope.clone(),
11464                Point::new(row, 0)..Point::new(end_row, 0),
11465            ));
11466
11467            ranges
11468        });
11469
11470        let mut edits = Vec::new();
11471        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11472
11473        for (language_settings, language_scope, range) in ranges {
11474            let mut start_row = range.start.row;
11475            let mut end_row = range.end.row;
11476
11477            // Skip selections that overlap with a range that has already been rewrapped.
11478            let selection_range = start_row..end_row;
11479            if rewrapped_row_ranges
11480                .iter()
11481                .any(|range| range.overlaps(&selection_range))
11482            {
11483                continue;
11484            }
11485
11486            let tab_size = language_settings.tab_size;
11487
11488            // Since not all lines in the selection may be at the same indent
11489            // level, choose the indent size that is the most common between all
11490            // of the lines.
11491            //
11492            // If there is a tie, we use the deepest indent.
11493            let (indent_size, indent_end) = {
11494                let mut indent_size_occurrences = HashMap::default();
11495                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11496
11497                for row in start_row..=end_row {
11498                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11499                    rows_by_indent_size.entry(indent).or_default().push(row);
11500                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11501                }
11502
11503                let indent_size = indent_size_occurrences
11504                    .into_iter()
11505                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11506                    .map(|(indent, _)| indent)
11507                    .unwrap_or_default();
11508                let row = rows_by_indent_size[&indent_size][0];
11509                let indent_end = Point::new(row, indent_size.len);
11510
11511                (indent_size, indent_end)
11512            };
11513
11514            let mut line_prefix = indent_size.chars().collect::<String>();
11515
11516            let mut inside_comment = false;
11517            if let Some(comment_prefix) = language_scope.and_then(|language| {
11518                language
11519                    .line_comment_prefixes()
11520                    .iter()
11521                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11522                    .cloned()
11523            }) {
11524                line_prefix.push_str(&comment_prefix);
11525                inside_comment = true;
11526            }
11527
11528            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11529                RewrapBehavior::InComments => inside_comment,
11530                RewrapBehavior::InSelections => !range.is_empty(),
11531                RewrapBehavior::Anywhere => true,
11532            };
11533
11534            let should_rewrap = options.override_language_settings
11535                || allow_rewrap_based_on_language
11536                || self.hard_wrap.is_some();
11537            if !should_rewrap {
11538                continue;
11539            }
11540
11541            if range.is_empty() {
11542                'expand_upwards: while start_row > 0 {
11543                    let prev_row = start_row - 1;
11544                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11545                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11546                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11547                    {
11548                        start_row = prev_row;
11549                    } else {
11550                        break 'expand_upwards;
11551                    }
11552                }
11553
11554                'expand_downwards: while end_row < buffer.max_point().row {
11555                    let next_row = end_row + 1;
11556                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11557                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11558                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11559                    {
11560                        end_row = next_row;
11561                    } else {
11562                        break 'expand_downwards;
11563                    }
11564                }
11565            }
11566
11567            let start = Point::new(start_row, 0);
11568            let start_offset = start.to_offset(&buffer);
11569            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11570            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11571            let Some(lines_without_prefixes) = selection_text
11572                .lines()
11573                .map(|line| {
11574                    line.strip_prefix(&line_prefix)
11575                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11576                        .with_context(|| {
11577                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11578                        })
11579                })
11580                .collect::<Result<Vec<_>, _>>()
11581                .log_err()
11582            else {
11583                continue;
11584            };
11585
11586            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11587                buffer
11588                    .language_settings_at(Point::new(start_row, 0), cx)
11589                    .preferred_line_length as usize
11590            });
11591            let wrapped_text = wrap_with_prefix(
11592                line_prefix,
11593                lines_without_prefixes.join("\n"),
11594                wrap_column,
11595                tab_size,
11596                options.preserve_existing_whitespace,
11597            );
11598
11599            // TODO: should always use char-based diff while still supporting cursor behavior that
11600            // matches vim.
11601            let mut diff_options = DiffOptions::default();
11602            if options.override_language_settings {
11603                diff_options.max_word_diff_len = 0;
11604                diff_options.max_word_diff_line_count = 0;
11605            } else {
11606                diff_options.max_word_diff_len = usize::MAX;
11607                diff_options.max_word_diff_line_count = usize::MAX;
11608            }
11609
11610            for (old_range, new_text) in
11611                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11612            {
11613                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11614                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11615                edits.push((edit_start..edit_end, new_text));
11616            }
11617
11618            rewrapped_row_ranges.push(start_row..=end_row);
11619        }
11620
11621        self.buffer
11622            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11623    }
11624
11625    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11626        let mut text = String::new();
11627        let buffer = self.buffer.read(cx).snapshot(cx);
11628        let mut selections = self.selections.all::<Point>(cx);
11629        let mut clipboard_selections = Vec::with_capacity(selections.len());
11630        {
11631            let max_point = buffer.max_point();
11632            let mut is_first = true;
11633            for selection in &mut selections {
11634                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11635                if is_entire_line {
11636                    selection.start = Point::new(selection.start.row, 0);
11637                    if !selection.is_empty() && selection.end.column == 0 {
11638                        selection.end = cmp::min(max_point, selection.end);
11639                    } else {
11640                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11641                    }
11642                    selection.goal = SelectionGoal::None;
11643                }
11644                if is_first {
11645                    is_first = false;
11646                } else {
11647                    text += "\n";
11648                }
11649                let mut len = 0;
11650                for chunk in buffer.text_for_range(selection.start..selection.end) {
11651                    text.push_str(chunk);
11652                    len += chunk.len();
11653                }
11654                clipboard_selections.push(ClipboardSelection {
11655                    len,
11656                    is_entire_line,
11657                    first_line_indent: buffer
11658                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11659                        .len,
11660                });
11661            }
11662        }
11663
11664        self.transact(window, cx, |this, window, cx| {
11665            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11666                s.select(selections);
11667            });
11668            this.insert("", window, cx);
11669        });
11670        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11671    }
11672
11673    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11674        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11675        let item = self.cut_common(window, cx);
11676        cx.write_to_clipboard(item);
11677    }
11678
11679    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11680        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11681        self.change_selections(None, window, cx, |s| {
11682            s.move_with(|snapshot, sel| {
11683                if sel.is_empty() {
11684                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11685                }
11686            });
11687        });
11688        let item = self.cut_common(window, cx);
11689        cx.set_global(KillRing(item))
11690    }
11691
11692    pub fn kill_ring_yank(
11693        &mut self,
11694        _: &KillRingYank,
11695        window: &mut Window,
11696        cx: &mut Context<Self>,
11697    ) {
11698        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11699        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11700            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11701                (kill_ring.text().to_string(), kill_ring.metadata_json())
11702            } else {
11703                return;
11704            }
11705        } else {
11706            return;
11707        };
11708        self.do_paste(&text, metadata, false, window, cx);
11709    }
11710
11711    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11712        self.do_copy(true, cx);
11713    }
11714
11715    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11716        self.do_copy(false, cx);
11717    }
11718
11719    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11720        let selections = self.selections.all::<Point>(cx);
11721        let buffer = self.buffer.read(cx).read(cx);
11722        let mut text = String::new();
11723
11724        let mut clipboard_selections = Vec::with_capacity(selections.len());
11725        {
11726            let max_point = buffer.max_point();
11727            let mut is_first = true;
11728            for selection in &selections {
11729                let mut start = selection.start;
11730                let mut end = selection.end;
11731                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11732                if is_entire_line {
11733                    start = Point::new(start.row, 0);
11734                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11735                }
11736
11737                let mut trimmed_selections = Vec::new();
11738                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11739                    let row = MultiBufferRow(start.row);
11740                    let first_indent = buffer.indent_size_for_line(row);
11741                    if first_indent.len == 0 || start.column > first_indent.len {
11742                        trimmed_selections.push(start..end);
11743                    } else {
11744                        trimmed_selections.push(
11745                            Point::new(row.0, first_indent.len)
11746                                ..Point::new(row.0, buffer.line_len(row)),
11747                        );
11748                        for row in start.row + 1..=end.row {
11749                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11750                            if row == end.row {
11751                                line_len = end.column;
11752                            }
11753                            if line_len == 0 {
11754                                trimmed_selections
11755                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11756                                continue;
11757                            }
11758                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11759                            if row_indent_size.len >= first_indent.len {
11760                                trimmed_selections.push(
11761                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11762                                );
11763                            } else {
11764                                trimmed_selections.clear();
11765                                trimmed_selections.push(start..end);
11766                                break;
11767                            }
11768                        }
11769                    }
11770                } else {
11771                    trimmed_selections.push(start..end);
11772                }
11773
11774                for trimmed_range in trimmed_selections {
11775                    if is_first {
11776                        is_first = false;
11777                    } else {
11778                        text += "\n";
11779                    }
11780                    let mut len = 0;
11781                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11782                        text.push_str(chunk);
11783                        len += chunk.len();
11784                    }
11785                    clipboard_selections.push(ClipboardSelection {
11786                        len,
11787                        is_entire_line,
11788                        first_line_indent: buffer
11789                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11790                            .len,
11791                    });
11792                }
11793            }
11794        }
11795
11796        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11797            text,
11798            clipboard_selections,
11799        ));
11800    }
11801
11802    pub fn do_paste(
11803        &mut self,
11804        text: &String,
11805        clipboard_selections: Option<Vec<ClipboardSelection>>,
11806        handle_entire_lines: bool,
11807        window: &mut Window,
11808        cx: &mut Context<Self>,
11809    ) {
11810        if self.read_only(cx) {
11811            return;
11812        }
11813
11814        let clipboard_text = Cow::Borrowed(text);
11815
11816        self.transact(window, cx, |this, window, cx| {
11817            if let Some(mut clipboard_selections) = clipboard_selections {
11818                let old_selections = this.selections.all::<usize>(cx);
11819                let all_selections_were_entire_line =
11820                    clipboard_selections.iter().all(|s| s.is_entire_line);
11821                let first_selection_indent_column =
11822                    clipboard_selections.first().map(|s| s.first_line_indent);
11823                if clipboard_selections.len() != old_selections.len() {
11824                    clipboard_selections.drain(..);
11825                }
11826                let cursor_offset = this.selections.last::<usize>(cx).head();
11827                let mut auto_indent_on_paste = true;
11828
11829                this.buffer.update(cx, |buffer, cx| {
11830                    let snapshot = buffer.read(cx);
11831                    auto_indent_on_paste = snapshot
11832                        .language_settings_at(cursor_offset, cx)
11833                        .auto_indent_on_paste;
11834
11835                    let mut start_offset = 0;
11836                    let mut edits = Vec::new();
11837                    let mut original_indent_columns = Vec::new();
11838                    for (ix, selection) in old_selections.iter().enumerate() {
11839                        let to_insert;
11840                        let entire_line;
11841                        let original_indent_column;
11842                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11843                            let end_offset = start_offset + clipboard_selection.len;
11844                            to_insert = &clipboard_text[start_offset..end_offset];
11845                            entire_line = clipboard_selection.is_entire_line;
11846                            start_offset = end_offset + 1;
11847                            original_indent_column = Some(clipboard_selection.first_line_indent);
11848                        } else {
11849                            to_insert = clipboard_text.as_str();
11850                            entire_line = all_selections_were_entire_line;
11851                            original_indent_column = first_selection_indent_column
11852                        }
11853
11854                        // If the corresponding selection was empty when this slice of the
11855                        // clipboard text was written, then the entire line containing the
11856                        // selection was copied. If this selection is also currently empty,
11857                        // then paste the line before the current line of the buffer.
11858                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11859                            let column = selection.start.to_point(&snapshot).column as usize;
11860                            let line_start = selection.start - column;
11861                            line_start..line_start
11862                        } else {
11863                            selection.range()
11864                        };
11865
11866                        edits.push((range, to_insert));
11867                        original_indent_columns.push(original_indent_column);
11868                    }
11869                    drop(snapshot);
11870
11871                    buffer.edit(
11872                        edits,
11873                        if auto_indent_on_paste {
11874                            Some(AutoindentMode::Block {
11875                                original_indent_columns,
11876                            })
11877                        } else {
11878                            None
11879                        },
11880                        cx,
11881                    );
11882                });
11883
11884                let selections = this.selections.all::<usize>(cx);
11885                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11886                    s.select(selections)
11887                });
11888            } else {
11889                this.insert(&clipboard_text, window, cx);
11890            }
11891        });
11892    }
11893
11894    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11895        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11896        if let Some(item) = cx.read_from_clipboard() {
11897            let entries = item.entries();
11898
11899            match entries.first() {
11900                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11901                // of all the pasted entries.
11902                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11903                    .do_paste(
11904                        clipboard_string.text(),
11905                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11906                        true,
11907                        window,
11908                        cx,
11909                    ),
11910                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11911            }
11912        }
11913    }
11914
11915    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11916        if self.read_only(cx) {
11917            return;
11918        }
11919
11920        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11921
11922        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11923            if let Some((selections, _)) =
11924                self.selection_history.transaction(transaction_id).cloned()
11925            {
11926                self.change_selections(None, window, cx, |s| {
11927                    s.select_anchors(selections.to_vec());
11928                });
11929            } else {
11930                log::error!(
11931                    "No entry in selection_history found for undo. \
11932                     This may correspond to a bug where undo does not update the selection. \
11933                     If this is occurring, please add details to \
11934                     https://github.com/zed-industries/zed/issues/22692"
11935                );
11936            }
11937            self.request_autoscroll(Autoscroll::fit(), cx);
11938            self.unmark_text(window, cx);
11939            self.refresh_inline_completion(true, false, window, cx);
11940            cx.emit(EditorEvent::Edited { transaction_id });
11941            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11942        }
11943    }
11944
11945    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11946        if self.read_only(cx) {
11947            return;
11948        }
11949
11950        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11951
11952        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11953            if let Some((_, Some(selections))) =
11954                self.selection_history.transaction(transaction_id).cloned()
11955            {
11956                self.change_selections(None, window, cx, |s| {
11957                    s.select_anchors(selections.to_vec());
11958                });
11959            } else {
11960                log::error!(
11961                    "No entry in selection_history found for redo. \
11962                     This may correspond to a bug where undo does not update the selection. \
11963                     If this is occurring, please add details to \
11964                     https://github.com/zed-industries/zed/issues/22692"
11965                );
11966            }
11967            self.request_autoscroll(Autoscroll::fit(), cx);
11968            self.unmark_text(window, cx);
11969            self.refresh_inline_completion(true, false, window, cx);
11970            cx.emit(EditorEvent::Edited { transaction_id });
11971        }
11972    }
11973
11974    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11975        self.buffer
11976            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11977    }
11978
11979    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11980        self.buffer
11981            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11982    }
11983
11984    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11985        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11986        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11987            s.move_with(|map, selection| {
11988                let cursor = if selection.is_empty() {
11989                    movement::left(map, selection.start)
11990                } else {
11991                    selection.start
11992                };
11993                selection.collapse_to(cursor, SelectionGoal::None);
11994            });
11995        })
11996    }
11997
11998    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12000        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12001            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12002        })
12003    }
12004
12005    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12006        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12007        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12008            s.move_with(|map, selection| {
12009                let cursor = if selection.is_empty() {
12010                    movement::right(map, selection.end)
12011                } else {
12012                    selection.end
12013                };
12014                selection.collapse_to(cursor, SelectionGoal::None)
12015            });
12016        })
12017    }
12018
12019    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12020        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12021        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12022            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12023        })
12024    }
12025
12026    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12027        if self.take_rename(true, window, cx).is_some() {
12028            return;
12029        }
12030
12031        if self.mode.is_single_line() {
12032            cx.propagate();
12033            return;
12034        }
12035
12036        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12037
12038        let text_layout_details = &self.text_layout_details(window);
12039        let selection_count = self.selections.count();
12040        let first_selection = self.selections.first_anchor();
12041
12042        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12043            s.move_with(|map, selection| {
12044                if !selection.is_empty() {
12045                    selection.goal = SelectionGoal::None;
12046                }
12047                let (cursor, goal) = movement::up(
12048                    map,
12049                    selection.start,
12050                    selection.goal,
12051                    false,
12052                    text_layout_details,
12053                );
12054                selection.collapse_to(cursor, goal);
12055            });
12056        });
12057
12058        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12059        {
12060            cx.propagate();
12061        }
12062    }
12063
12064    pub fn move_up_by_lines(
12065        &mut self,
12066        action: &MoveUpByLines,
12067        window: &mut Window,
12068        cx: &mut Context<Self>,
12069    ) {
12070        if self.take_rename(true, window, cx).is_some() {
12071            return;
12072        }
12073
12074        if self.mode.is_single_line() {
12075            cx.propagate();
12076            return;
12077        }
12078
12079        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12080
12081        let text_layout_details = &self.text_layout_details(window);
12082
12083        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12084            s.move_with(|map, selection| {
12085                if !selection.is_empty() {
12086                    selection.goal = SelectionGoal::None;
12087                }
12088                let (cursor, goal) = movement::up_by_rows(
12089                    map,
12090                    selection.start,
12091                    action.lines,
12092                    selection.goal,
12093                    false,
12094                    text_layout_details,
12095                );
12096                selection.collapse_to(cursor, goal);
12097            });
12098        })
12099    }
12100
12101    pub fn move_down_by_lines(
12102        &mut self,
12103        action: &MoveDownByLines,
12104        window: &mut Window,
12105        cx: &mut Context<Self>,
12106    ) {
12107        if self.take_rename(true, window, cx).is_some() {
12108            return;
12109        }
12110
12111        if self.mode.is_single_line() {
12112            cx.propagate();
12113            return;
12114        }
12115
12116        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12117
12118        let text_layout_details = &self.text_layout_details(window);
12119
12120        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12121            s.move_with(|map, selection| {
12122                if !selection.is_empty() {
12123                    selection.goal = SelectionGoal::None;
12124                }
12125                let (cursor, goal) = movement::down_by_rows(
12126                    map,
12127                    selection.start,
12128                    action.lines,
12129                    selection.goal,
12130                    false,
12131                    text_layout_details,
12132                );
12133                selection.collapse_to(cursor, goal);
12134            });
12135        })
12136    }
12137
12138    pub fn select_down_by_lines(
12139        &mut self,
12140        action: &SelectDownByLines,
12141        window: &mut Window,
12142        cx: &mut Context<Self>,
12143    ) {
12144        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12145        let text_layout_details = &self.text_layout_details(window);
12146        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12147            s.move_heads_with(|map, head, goal| {
12148                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12149            })
12150        })
12151    }
12152
12153    pub fn select_up_by_lines(
12154        &mut self,
12155        action: &SelectUpByLines,
12156        window: &mut Window,
12157        cx: &mut Context<Self>,
12158    ) {
12159        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12160        let text_layout_details = &self.text_layout_details(window);
12161        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12162            s.move_heads_with(|map, head, goal| {
12163                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12164            })
12165        })
12166    }
12167
12168    pub fn select_page_up(
12169        &mut self,
12170        _: &SelectPageUp,
12171        window: &mut Window,
12172        cx: &mut Context<Self>,
12173    ) {
12174        let Some(row_count) = self.visible_row_count() else {
12175            return;
12176        };
12177
12178        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12179
12180        let text_layout_details = &self.text_layout_details(window);
12181
12182        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12183            s.move_heads_with(|map, head, goal| {
12184                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12185            })
12186        })
12187    }
12188
12189    pub fn move_page_up(
12190        &mut self,
12191        action: &MovePageUp,
12192        window: &mut Window,
12193        cx: &mut Context<Self>,
12194    ) {
12195        if self.take_rename(true, window, cx).is_some() {
12196            return;
12197        }
12198
12199        if self
12200            .context_menu
12201            .borrow_mut()
12202            .as_mut()
12203            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12204            .unwrap_or(false)
12205        {
12206            return;
12207        }
12208
12209        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12210            cx.propagate();
12211            return;
12212        }
12213
12214        let Some(row_count) = self.visible_row_count() else {
12215            return;
12216        };
12217
12218        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12219
12220        let autoscroll = if action.center_cursor {
12221            Autoscroll::center()
12222        } else {
12223            Autoscroll::fit()
12224        };
12225
12226        let text_layout_details = &self.text_layout_details(window);
12227
12228        self.change_selections(Some(autoscroll), window, cx, |s| {
12229            s.move_with(|map, selection| {
12230                if !selection.is_empty() {
12231                    selection.goal = SelectionGoal::None;
12232                }
12233                let (cursor, goal) = movement::up_by_rows(
12234                    map,
12235                    selection.end,
12236                    row_count,
12237                    selection.goal,
12238                    false,
12239                    text_layout_details,
12240                );
12241                selection.collapse_to(cursor, goal);
12242            });
12243        });
12244    }
12245
12246    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12247        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12248        let text_layout_details = &self.text_layout_details(window);
12249        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12250            s.move_heads_with(|map, head, goal| {
12251                movement::up(map, head, goal, false, text_layout_details)
12252            })
12253        })
12254    }
12255
12256    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12257        self.take_rename(true, window, cx);
12258
12259        if self.mode.is_single_line() {
12260            cx.propagate();
12261            return;
12262        }
12263
12264        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12265
12266        let text_layout_details = &self.text_layout_details(window);
12267        let selection_count = self.selections.count();
12268        let first_selection = self.selections.first_anchor();
12269
12270        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12271            s.move_with(|map, selection| {
12272                if !selection.is_empty() {
12273                    selection.goal = SelectionGoal::None;
12274                }
12275                let (cursor, goal) = movement::down(
12276                    map,
12277                    selection.end,
12278                    selection.goal,
12279                    false,
12280                    text_layout_details,
12281                );
12282                selection.collapse_to(cursor, goal);
12283            });
12284        });
12285
12286        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12287        {
12288            cx.propagate();
12289        }
12290    }
12291
12292    pub fn select_page_down(
12293        &mut self,
12294        _: &SelectPageDown,
12295        window: &mut Window,
12296        cx: &mut Context<Self>,
12297    ) {
12298        let Some(row_count) = self.visible_row_count() else {
12299            return;
12300        };
12301
12302        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12303
12304        let text_layout_details = &self.text_layout_details(window);
12305
12306        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12307            s.move_heads_with(|map, head, goal| {
12308                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12309            })
12310        })
12311    }
12312
12313    pub fn move_page_down(
12314        &mut self,
12315        action: &MovePageDown,
12316        window: &mut Window,
12317        cx: &mut Context<Self>,
12318    ) {
12319        if self.take_rename(true, window, cx).is_some() {
12320            return;
12321        }
12322
12323        if self
12324            .context_menu
12325            .borrow_mut()
12326            .as_mut()
12327            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12328            .unwrap_or(false)
12329        {
12330            return;
12331        }
12332
12333        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12334            cx.propagate();
12335            return;
12336        }
12337
12338        let Some(row_count) = self.visible_row_count() else {
12339            return;
12340        };
12341
12342        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12343
12344        let autoscroll = if action.center_cursor {
12345            Autoscroll::center()
12346        } else {
12347            Autoscroll::fit()
12348        };
12349
12350        let text_layout_details = &self.text_layout_details(window);
12351        self.change_selections(Some(autoscroll), window, cx, |s| {
12352            s.move_with(|map, selection| {
12353                if !selection.is_empty() {
12354                    selection.goal = SelectionGoal::None;
12355                }
12356                let (cursor, goal) = movement::down_by_rows(
12357                    map,
12358                    selection.end,
12359                    row_count,
12360                    selection.goal,
12361                    false,
12362                    text_layout_details,
12363                );
12364                selection.collapse_to(cursor, goal);
12365            });
12366        });
12367    }
12368
12369    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12370        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12371        let text_layout_details = &self.text_layout_details(window);
12372        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12373            s.move_heads_with(|map, head, goal| {
12374                movement::down(map, head, goal, false, text_layout_details)
12375            })
12376        });
12377    }
12378
12379    pub fn context_menu_first(
12380        &mut self,
12381        _: &ContextMenuFirst,
12382        window: &mut Window,
12383        cx: &mut Context<Self>,
12384    ) {
12385        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12386            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12387        }
12388    }
12389
12390    pub fn context_menu_prev(
12391        &mut self,
12392        _: &ContextMenuPrevious,
12393        window: &mut Window,
12394        cx: &mut Context<Self>,
12395    ) {
12396        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12397            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12398        }
12399    }
12400
12401    pub fn context_menu_next(
12402        &mut self,
12403        _: &ContextMenuNext,
12404        window: &mut Window,
12405        cx: &mut Context<Self>,
12406    ) {
12407        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12408            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12409        }
12410    }
12411
12412    pub fn context_menu_last(
12413        &mut self,
12414        _: &ContextMenuLast,
12415        window: &mut Window,
12416        cx: &mut Context<Self>,
12417    ) {
12418        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12419            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12420        }
12421    }
12422
12423    pub fn move_to_previous_word_start(
12424        &mut self,
12425        _: &MoveToPreviousWordStart,
12426        window: &mut Window,
12427        cx: &mut Context<Self>,
12428    ) {
12429        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12430        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12431            s.move_cursors_with(|map, head, _| {
12432                (
12433                    movement::previous_word_start(map, head),
12434                    SelectionGoal::None,
12435                )
12436            });
12437        })
12438    }
12439
12440    pub fn move_to_previous_subword_start(
12441        &mut self,
12442        _: &MoveToPreviousSubwordStart,
12443        window: &mut Window,
12444        cx: &mut Context<Self>,
12445    ) {
12446        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12447        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12448            s.move_cursors_with(|map, head, _| {
12449                (
12450                    movement::previous_subword_start(map, head),
12451                    SelectionGoal::None,
12452                )
12453            });
12454        })
12455    }
12456
12457    pub fn select_to_previous_word_start(
12458        &mut self,
12459        _: &SelectToPreviousWordStart,
12460        window: &mut Window,
12461        cx: &mut Context<Self>,
12462    ) {
12463        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12464        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12465            s.move_heads_with(|map, head, _| {
12466                (
12467                    movement::previous_word_start(map, head),
12468                    SelectionGoal::None,
12469                )
12470            });
12471        })
12472    }
12473
12474    pub fn select_to_previous_subword_start(
12475        &mut self,
12476        _: &SelectToPreviousSubwordStart,
12477        window: &mut Window,
12478        cx: &mut Context<Self>,
12479    ) {
12480        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12481        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12482            s.move_heads_with(|map, head, _| {
12483                (
12484                    movement::previous_subword_start(map, head),
12485                    SelectionGoal::None,
12486                )
12487            });
12488        })
12489    }
12490
12491    pub fn delete_to_previous_word_start(
12492        &mut self,
12493        action: &DeleteToPreviousWordStart,
12494        window: &mut Window,
12495        cx: &mut Context<Self>,
12496    ) {
12497        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12498        self.transact(window, cx, |this, window, cx| {
12499            this.select_autoclose_pair(window, cx);
12500            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12501                s.move_with(|map, selection| {
12502                    if selection.is_empty() {
12503                        let cursor = if action.ignore_newlines {
12504                            movement::previous_word_start(map, selection.head())
12505                        } else {
12506                            movement::previous_word_start_or_newline(map, selection.head())
12507                        };
12508                        selection.set_head(cursor, SelectionGoal::None);
12509                    }
12510                });
12511            });
12512            this.insert("", window, cx);
12513        });
12514    }
12515
12516    pub fn delete_to_previous_subword_start(
12517        &mut self,
12518        _: &DeleteToPreviousSubwordStart,
12519        window: &mut Window,
12520        cx: &mut Context<Self>,
12521    ) {
12522        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12523        self.transact(window, cx, |this, window, cx| {
12524            this.select_autoclose_pair(window, cx);
12525            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12526                s.move_with(|map, selection| {
12527                    if selection.is_empty() {
12528                        let cursor = movement::previous_subword_start(map, selection.head());
12529                        selection.set_head(cursor, SelectionGoal::None);
12530                    }
12531                });
12532            });
12533            this.insert("", window, cx);
12534        });
12535    }
12536
12537    pub fn move_to_next_word_end(
12538        &mut self,
12539        _: &MoveToNextWordEnd,
12540        window: &mut Window,
12541        cx: &mut Context<Self>,
12542    ) {
12543        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12544        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12545            s.move_cursors_with(|map, head, _| {
12546                (movement::next_word_end(map, head), SelectionGoal::None)
12547            });
12548        })
12549    }
12550
12551    pub fn move_to_next_subword_end(
12552        &mut self,
12553        _: &MoveToNextSubwordEnd,
12554        window: &mut Window,
12555        cx: &mut Context<Self>,
12556    ) {
12557        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12558        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12559            s.move_cursors_with(|map, head, _| {
12560                (movement::next_subword_end(map, head), SelectionGoal::None)
12561            });
12562        })
12563    }
12564
12565    pub fn select_to_next_word_end(
12566        &mut self,
12567        _: &SelectToNextWordEnd,
12568        window: &mut Window,
12569        cx: &mut Context<Self>,
12570    ) {
12571        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12572        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12573            s.move_heads_with(|map, head, _| {
12574                (movement::next_word_end(map, head), SelectionGoal::None)
12575            });
12576        })
12577    }
12578
12579    pub fn select_to_next_subword_end(
12580        &mut self,
12581        _: &SelectToNextSubwordEnd,
12582        window: &mut Window,
12583        cx: &mut Context<Self>,
12584    ) {
12585        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12586        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12587            s.move_heads_with(|map, head, _| {
12588                (movement::next_subword_end(map, head), SelectionGoal::None)
12589            });
12590        })
12591    }
12592
12593    pub fn delete_to_next_word_end(
12594        &mut self,
12595        action: &DeleteToNextWordEnd,
12596        window: &mut Window,
12597        cx: &mut Context<Self>,
12598    ) {
12599        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12600        self.transact(window, cx, |this, window, cx| {
12601            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12602                s.move_with(|map, selection| {
12603                    if selection.is_empty() {
12604                        let cursor = if action.ignore_newlines {
12605                            movement::next_word_end(map, selection.head())
12606                        } else {
12607                            movement::next_word_end_or_newline(map, selection.head())
12608                        };
12609                        selection.set_head(cursor, SelectionGoal::None);
12610                    }
12611                });
12612            });
12613            this.insert("", window, cx);
12614        });
12615    }
12616
12617    pub fn delete_to_next_subword_end(
12618        &mut self,
12619        _: &DeleteToNextSubwordEnd,
12620        window: &mut Window,
12621        cx: &mut Context<Self>,
12622    ) {
12623        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12624        self.transact(window, cx, |this, window, cx| {
12625            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12626                s.move_with(|map, selection| {
12627                    if selection.is_empty() {
12628                        let cursor = movement::next_subword_end(map, selection.head());
12629                        selection.set_head(cursor, SelectionGoal::None);
12630                    }
12631                });
12632            });
12633            this.insert("", window, cx);
12634        });
12635    }
12636
12637    pub fn move_to_beginning_of_line(
12638        &mut self,
12639        action: &MoveToBeginningOfLine,
12640        window: &mut Window,
12641        cx: &mut Context<Self>,
12642    ) {
12643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12644        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12645            s.move_cursors_with(|map, head, _| {
12646                (
12647                    movement::indented_line_beginning(
12648                        map,
12649                        head,
12650                        action.stop_at_soft_wraps,
12651                        action.stop_at_indent,
12652                    ),
12653                    SelectionGoal::None,
12654                )
12655            });
12656        })
12657    }
12658
12659    pub fn select_to_beginning_of_line(
12660        &mut self,
12661        action: &SelectToBeginningOfLine,
12662        window: &mut Window,
12663        cx: &mut Context<Self>,
12664    ) {
12665        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12666        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12667            s.move_heads_with(|map, head, _| {
12668                (
12669                    movement::indented_line_beginning(
12670                        map,
12671                        head,
12672                        action.stop_at_soft_wraps,
12673                        action.stop_at_indent,
12674                    ),
12675                    SelectionGoal::None,
12676                )
12677            });
12678        });
12679    }
12680
12681    pub fn delete_to_beginning_of_line(
12682        &mut self,
12683        action: &DeleteToBeginningOfLine,
12684        window: &mut Window,
12685        cx: &mut Context<Self>,
12686    ) {
12687        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12688        self.transact(window, cx, |this, window, cx| {
12689            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12690                s.move_with(|_, selection| {
12691                    selection.reversed = true;
12692                });
12693            });
12694
12695            this.select_to_beginning_of_line(
12696                &SelectToBeginningOfLine {
12697                    stop_at_soft_wraps: false,
12698                    stop_at_indent: action.stop_at_indent,
12699                },
12700                window,
12701                cx,
12702            );
12703            this.backspace(&Backspace, window, cx);
12704        });
12705    }
12706
12707    pub fn move_to_end_of_line(
12708        &mut self,
12709        action: &MoveToEndOfLine,
12710        window: &mut Window,
12711        cx: &mut Context<Self>,
12712    ) {
12713        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12714        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12715            s.move_cursors_with(|map, head, _| {
12716                (
12717                    movement::line_end(map, head, action.stop_at_soft_wraps),
12718                    SelectionGoal::None,
12719                )
12720            });
12721        })
12722    }
12723
12724    pub fn select_to_end_of_line(
12725        &mut self,
12726        action: &SelectToEndOfLine,
12727        window: &mut Window,
12728        cx: &mut Context<Self>,
12729    ) {
12730        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12731        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12732            s.move_heads_with(|map, head, _| {
12733                (
12734                    movement::line_end(map, head, action.stop_at_soft_wraps),
12735                    SelectionGoal::None,
12736                )
12737            });
12738        })
12739    }
12740
12741    pub fn delete_to_end_of_line(
12742        &mut self,
12743        _: &DeleteToEndOfLine,
12744        window: &mut Window,
12745        cx: &mut Context<Self>,
12746    ) {
12747        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12748        self.transact(window, cx, |this, window, cx| {
12749            this.select_to_end_of_line(
12750                &SelectToEndOfLine {
12751                    stop_at_soft_wraps: false,
12752                },
12753                window,
12754                cx,
12755            );
12756            this.delete(&Delete, window, cx);
12757        });
12758    }
12759
12760    pub fn cut_to_end_of_line(
12761        &mut self,
12762        _: &CutToEndOfLine,
12763        window: &mut Window,
12764        cx: &mut Context<Self>,
12765    ) {
12766        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12767        self.transact(window, cx, |this, window, cx| {
12768            this.select_to_end_of_line(
12769                &SelectToEndOfLine {
12770                    stop_at_soft_wraps: false,
12771                },
12772                window,
12773                cx,
12774            );
12775            this.cut(&Cut, window, cx);
12776        });
12777    }
12778
12779    pub fn move_to_start_of_paragraph(
12780        &mut self,
12781        _: &MoveToStartOfParagraph,
12782        window: &mut Window,
12783        cx: &mut Context<Self>,
12784    ) {
12785        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12786            cx.propagate();
12787            return;
12788        }
12789        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12790        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12791            s.move_with(|map, selection| {
12792                selection.collapse_to(
12793                    movement::start_of_paragraph(map, selection.head(), 1),
12794                    SelectionGoal::None,
12795                )
12796            });
12797        })
12798    }
12799
12800    pub fn move_to_end_of_paragraph(
12801        &mut self,
12802        _: &MoveToEndOfParagraph,
12803        window: &mut Window,
12804        cx: &mut Context<Self>,
12805    ) {
12806        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12807            cx.propagate();
12808            return;
12809        }
12810        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12811        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12812            s.move_with(|map, selection| {
12813                selection.collapse_to(
12814                    movement::end_of_paragraph(map, selection.head(), 1),
12815                    SelectionGoal::None,
12816                )
12817            });
12818        })
12819    }
12820
12821    pub fn select_to_start_of_paragraph(
12822        &mut self,
12823        _: &SelectToStartOfParagraph,
12824        window: &mut Window,
12825        cx: &mut Context<Self>,
12826    ) {
12827        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12828            cx.propagate();
12829            return;
12830        }
12831        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12832        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12833            s.move_heads_with(|map, head, _| {
12834                (
12835                    movement::start_of_paragraph(map, head, 1),
12836                    SelectionGoal::None,
12837                )
12838            });
12839        })
12840    }
12841
12842    pub fn select_to_end_of_paragraph(
12843        &mut self,
12844        _: &SelectToEndOfParagraph,
12845        window: &mut Window,
12846        cx: &mut Context<Self>,
12847    ) {
12848        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12849            cx.propagate();
12850            return;
12851        }
12852        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12853        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12854            s.move_heads_with(|map, head, _| {
12855                (
12856                    movement::end_of_paragraph(map, head, 1),
12857                    SelectionGoal::None,
12858                )
12859            });
12860        })
12861    }
12862
12863    pub fn move_to_start_of_excerpt(
12864        &mut self,
12865        _: &MoveToStartOfExcerpt,
12866        window: &mut Window,
12867        cx: &mut Context<Self>,
12868    ) {
12869        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12870            cx.propagate();
12871            return;
12872        }
12873        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12874        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12875            s.move_with(|map, selection| {
12876                selection.collapse_to(
12877                    movement::start_of_excerpt(
12878                        map,
12879                        selection.head(),
12880                        workspace::searchable::Direction::Prev,
12881                    ),
12882                    SelectionGoal::None,
12883                )
12884            });
12885        })
12886    }
12887
12888    pub fn move_to_start_of_next_excerpt(
12889        &mut self,
12890        _: &MoveToStartOfNextExcerpt,
12891        window: &mut Window,
12892        cx: &mut Context<Self>,
12893    ) {
12894        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12895            cx.propagate();
12896            return;
12897        }
12898
12899        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12900            s.move_with(|map, selection| {
12901                selection.collapse_to(
12902                    movement::start_of_excerpt(
12903                        map,
12904                        selection.head(),
12905                        workspace::searchable::Direction::Next,
12906                    ),
12907                    SelectionGoal::None,
12908                )
12909            });
12910        })
12911    }
12912
12913    pub fn move_to_end_of_excerpt(
12914        &mut self,
12915        _: &MoveToEndOfExcerpt,
12916        window: &mut Window,
12917        cx: &mut Context<Self>,
12918    ) {
12919        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12920            cx.propagate();
12921            return;
12922        }
12923        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12924        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12925            s.move_with(|map, selection| {
12926                selection.collapse_to(
12927                    movement::end_of_excerpt(
12928                        map,
12929                        selection.head(),
12930                        workspace::searchable::Direction::Next,
12931                    ),
12932                    SelectionGoal::None,
12933                )
12934            });
12935        })
12936    }
12937
12938    pub fn move_to_end_of_previous_excerpt(
12939        &mut self,
12940        _: &MoveToEndOfPreviousExcerpt,
12941        window: &mut Window,
12942        cx: &mut Context<Self>,
12943    ) {
12944        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12945            cx.propagate();
12946            return;
12947        }
12948        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12949        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12950            s.move_with(|map, selection| {
12951                selection.collapse_to(
12952                    movement::end_of_excerpt(
12953                        map,
12954                        selection.head(),
12955                        workspace::searchable::Direction::Prev,
12956                    ),
12957                    SelectionGoal::None,
12958                )
12959            });
12960        })
12961    }
12962
12963    pub fn select_to_start_of_excerpt(
12964        &mut self,
12965        _: &SelectToStartOfExcerpt,
12966        window: &mut Window,
12967        cx: &mut Context<Self>,
12968    ) {
12969        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12970            cx.propagate();
12971            return;
12972        }
12973        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12974        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12975            s.move_heads_with(|map, head, _| {
12976                (
12977                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12978                    SelectionGoal::None,
12979                )
12980            });
12981        })
12982    }
12983
12984    pub fn select_to_start_of_next_excerpt(
12985        &mut self,
12986        _: &SelectToStartOfNextExcerpt,
12987        window: &mut Window,
12988        cx: &mut Context<Self>,
12989    ) {
12990        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12991            cx.propagate();
12992            return;
12993        }
12994        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12995        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12996            s.move_heads_with(|map, head, _| {
12997                (
12998                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12999                    SelectionGoal::None,
13000                )
13001            });
13002        })
13003    }
13004
13005    pub fn select_to_end_of_excerpt(
13006        &mut self,
13007        _: &SelectToEndOfExcerpt,
13008        window: &mut Window,
13009        cx: &mut Context<Self>,
13010    ) {
13011        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13012            cx.propagate();
13013            return;
13014        }
13015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13016        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13017            s.move_heads_with(|map, head, _| {
13018                (
13019                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13020                    SelectionGoal::None,
13021                )
13022            });
13023        })
13024    }
13025
13026    pub fn select_to_end_of_previous_excerpt(
13027        &mut self,
13028        _: &SelectToEndOfPreviousExcerpt,
13029        window: &mut Window,
13030        cx: &mut Context<Self>,
13031    ) {
13032        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13033            cx.propagate();
13034            return;
13035        }
13036        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13037        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13038            s.move_heads_with(|map, head, _| {
13039                (
13040                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13041                    SelectionGoal::None,
13042                )
13043            });
13044        })
13045    }
13046
13047    pub fn move_to_beginning(
13048        &mut self,
13049        _: &MoveToBeginning,
13050        window: &mut Window,
13051        cx: &mut Context<Self>,
13052    ) {
13053        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13054            cx.propagate();
13055            return;
13056        }
13057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13058        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13059            s.select_ranges(vec![0..0]);
13060        });
13061    }
13062
13063    pub fn select_to_beginning(
13064        &mut self,
13065        _: &SelectToBeginning,
13066        window: &mut Window,
13067        cx: &mut Context<Self>,
13068    ) {
13069        let mut selection = self.selections.last::<Point>(cx);
13070        selection.set_head(Point::zero(), SelectionGoal::None);
13071        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13072        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13073            s.select(vec![selection]);
13074        });
13075    }
13076
13077    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13078        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13079            cx.propagate();
13080            return;
13081        }
13082        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13083        let cursor = self.buffer.read(cx).read(cx).len();
13084        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13085            s.select_ranges(vec![cursor..cursor])
13086        });
13087    }
13088
13089    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13090        self.nav_history = nav_history;
13091    }
13092
13093    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13094        self.nav_history.as_ref()
13095    }
13096
13097    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13098        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
13099    }
13100
13101    fn push_to_nav_history(
13102        &mut self,
13103        cursor_anchor: Anchor,
13104        new_position: Option<Point>,
13105        is_deactivate: bool,
13106        cx: &mut Context<Self>,
13107    ) {
13108        if let Some(nav_history) = self.nav_history.as_mut() {
13109            let buffer = self.buffer.read(cx).read(cx);
13110            let cursor_position = cursor_anchor.to_point(&buffer);
13111            let scroll_state = self.scroll_manager.anchor();
13112            let scroll_top_row = scroll_state.top_row(&buffer);
13113            drop(buffer);
13114
13115            if let Some(new_position) = new_position {
13116                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13117                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
13118                    return;
13119                }
13120            }
13121
13122            nav_history.push(
13123                Some(NavigationData {
13124                    cursor_anchor,
13125                    cursor_position,
13126                    scroll_anchor: scroll_state,
13127                    scroll_top_row,
13128                }),
13129                cx,
13130            );
13131            cx.emit(EditorEvent::PushedToNavHistory {
13132                anchor: cursor_anchor,
13133                is_deactivate,
13134            })
13135        }
13136    }
13137
13138    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13140        let buffer = self.buffer.read(cx).snapshot(cx);
13141        let mut selection = self.selections.first::<usize>(cx);
13142        selection.set_head(buffer.len(), SelectionGoal::None);
13143        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13144            s.select(vec![selection]);
13145        });
13146    }
13147
13148    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13149        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13150        let end = self.buffer.read(cx).read(cx).len();
13151        self.change_selections(None, window, cx, |s| {
13152            s.select_ranges(vec![0..end]);
13153        });
13154    }
13155
13156    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13157        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13158        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13159        let mut selections = self.selections.all::<Point>(cx);
13160        let max_point = display_map.buffer_snapshot.max_point();
13161        for selection in &mut selections {
13162            let rows = selection.spanned_rows(true, &display_map);
13163            selection.start = Point::new(rows.start.0, 0);
13164            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13165            selection.reversed = false;
13166        }
13167        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13168            s.select(selections);
13169        });
13170    }
13171
13172    pub fn split_selection_into_lines(
13173        &mut self,
13174        _: &SplitSelectionIntoLines,
13175        window: &mut Window,
13176        cx: &mut Context<Self>,
13177    ) {
13178        let selections = self
13179            .selections
13180            .all::<Point>(cx)
13181            .into_iter()
13182            .map(|selection| selection.start..selection.end)
13183            .collect::<Vec<_>>();
13184        self.unfold_ranges(&selections, true, true, cx);
13185
13186        let mut new_selection_ranges = Vec::new();
13187        {
13188            let buffer = self.buffer.read(cx).read(cx);
13189            for selection in selections {
13190                for row in selection.start.row..selection.end.row {
13191                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13192                    new_selection_ranges.push(cursor..cursor);
13193                }
13194
13195                let is_multiline_selection = selection.start.row != selection.end.row;
13196                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13197                // so this action feels more ergonomic when paired with other selection operations
13198                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13199                if !should_skip_last {
13200                    new_selection_ranges.push(selection.end..selection.end);
13201                }
13202            }
13203        }
13204        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13205            s.select_ranges(new_selection_ranges);
13206        });
13207    }
13208
13209    pub fn add_selection_above(
13210        &mut self,
13211        _: &AddSelectionAbove,
13212        window: &mut Window,
13213        cx: &mut Context<Self>,
13214    ) {
13215        self.add_selection(true, window, cx);
13216    }
13217
13218    pub fn add_selection_below(
13219        &mut self,
13220        _: &AddSelectionBelow,
13221        window: &mut Window,
13222        cx: &mut Context<Self>,
13223    ) {
13224        self.add_selection(false, window, cx);
13225    }
13226
13227    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13228        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13229
13230        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13231        let all_selections = self.selections.all::<Point>(cx);
13232        let text_layout_details = self.text_layout_details(window);
13233
13234        let (mut columnar_selections, new_selections_to_columnarize) = {
13235            if let Some(state) = self.add_selections_state.as_ref() {
13236                let columnar_selection_ids: HashSet<_> = state
13237                    .groups
13238                    .iter()
13239                    .flat_map(|group| group.stack.iter())
13240                    .copied()
13241                    .collect();
13242
13243                all_selections
13244                    .into_iter()
13245                    .partition(|s| columnar_selection_ids.contains(&s.id))
13246            } else {
13247                (Vec::new(), all_selections)
13248            }
13249        };
13250
13251        let mut state = self
13252            .add_selections_state
13253            .take()
13254            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13255
13256        for selection in new_selections_to_columnarize {
13257            let range = selection.display_range(&display_map).sorted();
13258            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13259            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13260            let positions = start_x.min(end_x)..start_x.max(end_x);
13261            let mut stack = Vec::new();
13262            for row in range.start.row().0..=range.end.row().0 {
13263                if let Some(selection) = self.selections.build_columnar_selection(
13264                    &display_map,
13265                    DisplayRow(row),
13266                    &positions,
13267                    selection.reversed,
13268                    &text_layout_details,
13269                ) {
13270                    stack.push(selection.id);
13271                    columnar_selections.push(selection);
13272                }
13273            }
13274            if !stack.is_empty() {
13275                if above {
13276                    stack.reverse();
13277                }
13278                state.groups.push(AddSelectionsGroup { above, stack });
13279            }
13280        }
13281
13282        let mut final_selections = Vec::new();
13283        let end_row = if above {
13284            DisplayRow(0)
13285        } else {
13286            display_map.max_point().row()
13287        };
13288
13289        let mut last_added_item_per_group = HashMap::default();
13290        for group in state.groups.iter_mut() {
13291            if let Some(last_id) = group.stack.last() {
13292                last_added_item_per_group.insert(*last_id, group);
13293            }
13294        }
13295
13296        for selection in columnar_selections {
13297            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13298                if above == group.above {
13299                    let range = selection.display_range(&display_map).sorted();
13300                    debug_assert_eq!(range.start.row(), range.end.row());
13301                    let mut row = range.start.row();
13302                    let positions =
13303                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13304                            px(start)..px(end)
13305                        } else {
13306                            let start_x =
13307                                display_map.x_for_display_point(range.start, &text_layout_details);
13308                            let end_x =
13309                                display_map.x_for_display_point(range.end, &text_layout_details);
13310                            start_x.min(end_x)..start_x.max(end_x)
13311                        };
13312
13313                    let mut maybe_new_selection = None;
13314                    while row != end_row {
13315                        if above {
13316                            row.0 -= 1;
13317                        } else {
13318                            row.0 += 1;
13319                        }
13320                        if let Some(new_selection) = self.selections.build_columnar_selection(
13321                            &display_map,
13322                            row,
13323                            &positions,
13324                            selection.reversed,
13325                            &text_layout_details,
13326                        ) {
13327                            maybe_new_selection = Some(new_selection);
13328                            break;
13329                        }
13330                    }
13331
13332                    if let Some(new_selection) = maybe_new_selection {
13333                        group.stack.push(new_selection.id);
13334                        if above {
13335                            final_selections.push(new_selection);
13336                            final_selections.push(selection);
13337                        } else {
13338                            final_selections.push(selection);
13339                            final_selections.push(new_selection);
13340                        }
13341                    } else {
13342                        final_selections.push(selection);
13343                    }
13344                } else {
13345                    group.stack.pop();
13346                }
13347            } else {
13348                final_selections.push(selection);
13349            }
13350        }
13351
13352        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13353            s.select(final_selections);
13354        });
13355
13356        let final_selection_ids: HashSet<_> = self
13357            .selections
13358            .all::<Point>(cx)
13359            .iter()
13360            .map(|s| s.id)
13361            .collect();
13362        state.groups.retain_mut(|group| {
13363            // selections might get merged above so we remove invalid items from stacks
13364            group.stack.retain(|id| final_selection_ids.contains(id));
13365
13366            // single selection in stack can be treated as initial state
13367            group.stack.len() > 1
13368        });
13369
13370        if !state.groups.is_empty() {
13371            self.add_selections_state = Some(state);
13372        }
13373    }
13374
13375    fn select_match_ranges(
13376        &mut self,
13377        range: Range<usize>,
13378        reversed: bool,
13379        replace_newest: bool,
13380        auto_scroll: Option<Autoscroll>,
13381        window: &mut Window,
13382        cx: &mut Context<Editor>,
13383    ) {
13384        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13385        self.change_selections(auto_scroll, window, cx, |s| {
13386            if replace_newest {
13387                s.delete(s.newest_anchor().id);
13388            }
13389            if reversed {
13390                s.insert_range(range.end..range.start);
13391            } else {
13392                s.insert_range(range);
13393            }
13394        });
13395    }
13396
13397    pub fn select_next_match_internal(
13398        &mut self,
13399        display_map: &DisplaySnapshot,
13400        replace_newest: bool,
13401        autoscroll: Option<Autoscroll>,
13402        window: &mut Window,
13403        cx: &mut Context<Self>,
13404    ) -> Result<()> {
13405        let buffer = &display_map.buffer_snapshot;
13406        let mut selections = self.selections.all::<usize>(cx);
13407        if let Some(mut select_next_state) = self.select_next_state.take() {
13408            let query = &select_next_state.query;
13409            if !select_next_state.done {
13410                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13411                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13412                let mut next_selected_range = None;
13413
13414                let bytes_after_last_selection =
13415                    buffer.bytes_in_range(last_selection.end..buffer.len());
13416                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13417                let query_matches = query
13418                    .stream_find_iter(bytes_after_last_selection)
13419                    .map(|result| (last_selection.end, result))
13420                    .chain(
13421                        query
13422                            .stream_find_iter(bytes_before_first_selection)
13423                            .map(|result| (0, result)),
13424                    );
13425
13426                for (start_offset, query_match) in query_matches {
13427                    let query_match = query_match.unwrap(); // can only fail due to I/O
13428                    let offset_range =
13429                        start_offset + query_match.start()..start_offset + query_match.end();
13430
13431                    if !select_next_state.wordwise
13432                        || (!buffer.is_inside_word(offset_range.start, false)
13433                            && !buffer.is_inside_word(offset_range.end, false))
13434                    {
13435                        // TODO: This is n^2, because we might check all the selections
13436                        if !selections
13437                            .iter()
13438                            .any(|selection| selection.range().overlaps(&offset_range))
13439                        {
13440                            next_selected_range = Some(offset_range);
13441                            break;
13442                        }
13443                    }
13444                }
13445
13446                if let Some(next_selected_range) = next_selected_range {
13447                    self.select_match_ranges(
13448                        next_selected_range,
13449                        last_selection.reversed,
13450                        replace_newest,
13451                        autoscroll,
13452                        window,
13453                        cx,
13454                    );
13455                } else {
13456                    select_next_state.done = true;
13457                }
13458            }
13459
13460            self.select_next_state = Some(select_next_state);
13461        } else {
13462            let mut only_carets = true;
13463            let mut same_text_selected = true;
13464            let mut selected_text = None;
13465
13466            let mut selections_iter = selections.iter().peekable();
13467            while let Some(selection) = selections_iter.next() {
13468                if selection.start != selection.end {
13469                    only_carets = false;
13470                }
13471
13472                if same_text_selected {
13473                    if selected_text.is_none() {
13474                        selected_text =
13475                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13476                    }
13477
13478                    if let Some(next_selection) = selections_iter.peek() {
13479                        if next_selection.range().len() == selection.range().len() {
13480                            let next_selected_text = buffer
13481                                .text_for_range(next_selection.range())
13482                                .collect::<String>();
13483                            if Some(next_selected_text) != selected_text {
13484                                same_text_selected = false;
13485                                selected_text = None;
13486                            }
13487                        } else {
13488                            same_text_selected = false;
13489                            selected_text = None;
13490                        }
13491                    }
13492                }
13493            }
13494
13495            if only_carets {
13496                for selection in &mut selections {
13497                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13498                    selection.start = word_range.start;
13499                    selection.end = word_range.end;
13500                    selection.goal = SelectionGoal::None;
13501                    selection.reversed = false;
13502                    self.select_match_ranges(
13503                        selection.start..selection.end,
13504                        selection.reversed,
13505                        replace_newest,
13506                        autoscroll,
13507                        window,
13508                        cx,
13509                    );
13510                }
13511
13512                if selections.len() == 1 {
13513                    let selection = selections
13514                        .last()
13515                        .expect("ensured that there's only one selection");
13516                    let query = buffer
13517                        .text_for_range(selection.start..selection.end)
13518                        .collect::<String>();
13519                    let is_empty = query.is_empty();
13520                    let select_state = SelectNextState {
13521                        query: AhoCorasick::new(&[query])?,
13522                        wordwise: true,
13523                        done: is_empty,
13524                    };
13525                    self.select_next_state = Some(select_state);
13526                } else {
13527                    self.select_next_state = None;
13528                }
13529            } else if let Some(selected_text) = selected_text {
13530                self.select_next_state = Some(SelectNextState {
13531                    query: AhoCorasick::new(&[selected_text])?,
13532                    wordwise: false,
13533                    done: false,
13534                });
13535                self.select_next_match_internal(
13536                    display_map,
13537                    replace_newest,
13538                    autoscroll,
13539                    window,
13540                    cx,
13541                )?;
13542            }
13543        }
13544        Ok(())
13545    }
13546
13547    pub fn select_all_matches(
13548        &mut self,
13549        _action: &SelectAllMatches,
13550        window: &mut Window,
13551        cx: &mut Context<Self>,
13552    ) -> Result<()> {
13553        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13554
13555        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13556
13557        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13558        let Some(select_next_state) = self.select_next_state.as_mut() else {
13559            return Ok(());
13560        };
13561        if select_next_state.done {
13562            return Ok(());
13563        }
13564
13565        let mut new_selections = Vec::new();
13566
13567        let reversed = self.selections.oldest::<usize>(cx).reversed;
13568        let buffer = &display_map.buffer_snapshot;
13569        let query_matches = select_next_state
13570            .query
13571            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13572
13573        for query_match in query_matches.into_iter() {
13574            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13575            let offset_range = if reversed {
13576                query_match.end()..query_match.start()
13577            } else {
13578                query_match.start()..query_match.end()
13579            };
13580
13581            if !select_next_state.wordwise
13582                || (!buffer.is_inside_word(offset_range.start, false)
13583                    && !buffer.is_inside_word(offset_range.end, false))
13584            {
13585                new_selections.push(offset_range.start..offset_range.end);
13586            }
13587        }
13588
13589        select_next_state.done = true;
13590
13591        if new_selections.is_empty() {
13592            log::error!("bug: new_selections is empty in select_all_matches");
13593            return Ok(());
13594        }
13595
13596        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13597        self.change_selections(None, window, cx, |selections| {
13598            selections.select_ranges(new_selections)
13599        });
13600
13601        Ok(())
13602    }
13603
13604    pub fn select_next(
13605        &mut self,
13606        action: &SelectNext,
13607        window: &mut Window,
13608        cx: &mut Context<Self>,
13609    ) -> Result<()> {
13610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13611        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13612        self.select_next_match_internal(
13613            &display_map,
13614            action.replace_newest,
13615            Some(Autoscroll::newest()),
13616            window,
13617            cx,
13618        )?;
13619        Ok(())
13620    }
13621
13622    pub fn select_previous(
13623        &mut self,
13624        action: &SelectPrevious,
13625        window: &mut Window,
13626        cx: &mut Context<Self>,
13627    ) -> Result<()> {
13628        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13629        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13630        let buffer = &display_map.buffer_snapshot;
13631        let mut selections = self.selections.all::<usize>(cx);
13632        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13633            let query = &select_prev_state.query;
13634            if !select_prev_state.done {
13635                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13636                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13637                let mut next_selected_range = None;
13638                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13639                let bytes_before_last_selection =
13640                    buffer.reversed_bytes_in_range(0..last_selection.start);
13641                let bytes_after_first_selection =
13642                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13643                let query_matches = query
13644                    .stream_find_iter(bytes_before_last_selection)
13645                    .map(|result| (last_selection.start, result))
13646                    .chain(
13647                        query
13648                            .stream_find_iter(bytes_after_first_selection)
13649                            .map(|result| (buffer.len(), result)),
13650                    );
13651                for (end_offset, query_match) in query_matches {
13652                    let query_match = query_match.unwrap(); // can only fail due to I/O
13653                    let offset_range =
13654                        end_offset - query_match.end()..end_offset - query_match.start();
13655
13656                    if !select_prev_state.wordwise
13657                        || (!buffer.is_inside_word(offset_range.start, false)
13658                            && !buffer.is_inside_word(offset_range.end, false))
13659                    {
13660                        next_selected_range = Some(offset_range);
13661                        break;
13662                    }
13663                }
13664
13665                if let Some(next_selected_range) = next_selected_range {
13666                    self.select_match_ranges(
13667                        next_selected_range,
13668                        last_selection.reversed,
13669                        action.replace_newest,
13670                        Some(Autoscroll::newest()),
13671                        window,
13672                        cx,
13673                    );
13674                } else {
13675                    select_prev_state.done = true;
13676                }
13677            }
13678
13679            self.select_prev_state = Some(select_prev_state);
13680        } else {
13681            let mut only_carets = true;
13682            let mut same_text_selected = true;
13683            let mut selected_text = None;
13684
13685            let mut selections_iter = selections.iter().peekable();
13686            while let Some(selection) = selections_iter.next() {
13687                if selection.start != selection.end {
13688                    only_carets = false;
13689                }
13690
13691                if same_text_selected {
13692                    if selected_text.is_none() {
13693                        selected_text =
13694                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13695                    }
13696
13697                    if let Some(next_selection) = selections_iter.peek() {
13698                        if next_selection.range().len() == selection.range().len() {
13699                            let next_selected_text = buffer
13700                                .text_for_range(next_selection.range())
13701                                .collect::<String>();
13702                            if Some(next_selected_text) != selected_text {
13703                                same_text_selected = false;
13704                                selected_text = None;
13705                            }
13706                        } else {
13707                            same_text_selected = false;
13708                            selected_text = None;
13709                        }
13710                    }
13711                }
13712            }
13713
13714            if only_carets {
13715                for selection in &mut selections {
13716                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13717                    selection.start = word_range.start;
13718                    selection.end = word_range.end;
13719                    selection.goal = SelectionGoal::None;
13720                    selection.reversed = false;
13721                    self.select_match_ranges(
13722                        selection.start..selection.end,
13723                        selection.reversed,
13724                        action.replace_newest,
13725                        Some(Autoscroll::newest()),
13726                        window,
13727                        cx,
13728                    );
13729                }
13730                if selections.len() == 1 {
13731                    let selection = selections
13732                        .last()
13733                        .expect("ensured that there's only one selection");
13734                    let query = buffer
13735                        .text_for_range(selection.start..selection.end)
13736                        .collect::<String>();
13737                    let is_empty = query.is_empty();
13738                    let select_state = SelectNextState {
13739                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13740                        wordwise: true,
13741                        done: is_empty,
13742                    };
13743                    self.select_prev_state = Some(select_state);
13744                } else {
13745                    self.select_prev_state = None;
13746                }
13747            } else if let Some(selected_text) = selected_text {
13748                self.select_prev_state = Some(SelectNextState {
13749                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13750                    wordwise: false,
13751                    done: false,
13752                });
13753                self.select_previous(action, window, cx)?;
13754            }
13755        }
13756        Ok(())
13757    }
13758
13759    pub fn find_next_match(
13760        &mut self,
13761        _: &FindNextMatch,
13762        window: &mut Window,
13763        cx: &mut Context<Self>,
13764    ) -> Result<()> {
13765        let selections = self.selections.disjoint_anchors();
13766        match selections.first() {
13767            Some(first) if selections.len() >= 2 => {
13768                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13769                    s.select_ranges([first.range()]);
13770                });
13771            }
13772            _ => self.select_next(
13773                &SelectNext {
13774                    replace_newest: true,
13775                },
13776                window,
13777                cx,
13778            )?,
13779        }
13780        Ok(())
13781    }
13782
13783    pub fn find_previous_match(
13784        &mut self,
13785        _: &FindPreviousMatch,
13786        window: &mut Window,
13787        cx: &mut Context<Self>,
13788    ) -> Result<()> {
13789        let selections = self.selections.disjoint_anchors();
13790        match selections.last() {
13791            Some(last) if selections.len() >= 2 => {
13792                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13793                    s.select_ranges([last.range()]);
13794                });
13795            }
13796            _ => self.select_previous(
13797                &SelectPrevious {
13798                    replace_newest: true,
13799                },
13800                window,
13801                cx,
13802            )?,
13803        }
13804        Ok(())
13805    }
13806
13807    pub fn toggle_comments(
13808        &mut self,
13809        action: &ToggleComments,
13810        window: &mut Window,
13811        cx: &mut Context<Self>,
13812    ) {
13813        if self.read_only(cx) {
13814            return;
13815        }
13816        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13817        let text_layout_details = &self.text_layout_details(window);
13818        self.transact(window, cx, |this, window, cx| {
13819            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13820            let mut edits = Vec::new();
13821            let mut selection_edit_ranges = Vec::new();
13822            let mut last_toggled_row = None;
13823            let snapshot = this.buffer.read(cx).read(cx);
13824            let empty_str: Arc<str> = Arc::default();
13825            let mut suffixes_inserted = Vec::new();
13826            let ignore_indent = action.ignore_indent;
13827
13828            fn comment_prefix_range(
13829                snapshot: &MultiBufferSnapshot,
13830                row: MultiBufferRow,
13831                comment_prefix: &str,
13832                comment_prefix_whitespace: &str,
13833                ignore_indent: bool,
13834            ) -> Range<Point> {
13835                let indent_size = if ignore_indent {
13836                    0
13837                } else {
13838                    snapshot.indent_size_for_line(row).len
13839                };
13840
13841                let start = Point::new(row.0, indent_size);
13842
13843                let mut line_bytes = snapshot
13844                    .bytes_in_range(start..snapshot.max_point())
13845                    .flatten()
13846                    .copied();
13847
13848                // If this line currently begins with the line comment prefix, then record
13849                // the range containing the prefix.
13850                if line_bytes
13851                    .by_ref()
13852                    .take(comment_prefix.len())
13853                    .eq(comment_prefix.bytes())
13854                {
13855                    // Include any whitespace that matches the comment prefix.
13856                    let matching_whitespace_len = line_bytes
13857                        .zip(comment_prefix_whitespace.bytes())
13858                        .take_while(|(a, b)| a == b)
13859                        .count() as u32;
13860                    let end = Point::new(
13861                        start.row,
13862                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13863                    );
13864                    start..end
13865                } else {
13866                    start..start
13867                }
13868            }
13869
13870            fn comment_suffix_range(
13871                snapshot: &MultiBufferSnapshot,
13872                row: MultiBufferRow,
13873                comment_suffix: &str,
13874                comment_suffix_has_leading_space: bool,
13875            ) -> Range<Point> {
13876                let end = Point::new(row.0, snapshot.line_len(row));
13877                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13878
13879                let mut line_end_bytes = snapshot
13880                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13881                    .flatten()
13882                    .copied();
13883
13884                let leading_space_len = if suffix_start_column > 0
13885                    && line_end_bytes.next() == Some(b' ')
13886                    && comment_suffix_has_leading_space
13887                {
13888                    1
13889                } else {
13890                    0
13891                };
13892
13893                // If this line currently begins with the line comment prefix, then record
13894                // the range containing the prefix.
13895                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13896                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13897                    start..end
13898                } else {
13899                    end..end
13900                }
13901            }
13902
13903            // TODO: Handle selections that cross excerpts
13904            for selection in &mut selections {
13905                let start_column = snapshot
13906                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13907                    .len;
13908                let language = if let Some(language) =
13909                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13910                {
13911                    language
13912                } else {
13913                    continue;
13914                };
13915
13916                selection_edit_ranges.clear();
13917
13918                // If multiple selections contain a given row, avoid processing that
13919                // row more than once.
13920                let mut start_row = MultiBufferRow(selection.start.row);
13921                if last_toggled_row == Some(start_row) {
13922                    start_row = start_row.next_row();
13923                }
13924                let end_row =
13925                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13926                        MultiBufferRow(selection.end.row - 1)
13927                    } else {
13928                        MultiBufferRow(selection.end.row)
13929                    };
13930                last_toggled_row = Some(end_row);
13931
13932                if start_row > end_row {
13933                    continue;
13934                }
13935
13936                // If the language has line comments, toggle those.
13937                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13938
13939                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13940                if ignore_indent {
13941                    full_comment_prefixes = full_comment_prefixes
13942                        .into_iter()
13943                        .map(|s| Arc::from(s.trim_end()))
13944                        .collect();
13945                }
13946
13947                if !full_comment_prefixes.is_empty() {
13948                    let first_prefix = full_comment_prefixes
13949                        .first()
13950                        .expect("prefixes is non-empty");
13951                    let prefix_trimmed_lengths = full_comment_prefixes
13952                        .iter()
13953                        .map(|p| p.trim_end_matches(' ').len())
13954                        .collect::<SmallVec<[usize; 4]>>();
13955
13956                    let mut all_selection_lines_are_comments = true;
13957
13958                    for row in start_row.0..=end_row.0 {
13959                        let row = MultiBufferRow(row);
13960                        if start_row < end_row && snapshot.is_line_blank(row) {
13961                            continue;
13962                        }
13963
13964                        let prefix_range = full_comment_prefixes
13965                            .iter()
13966                            .zip(prefix_trimmed_lengths.iter().copied())
13967                            .map(|(prefix, trimmed_prefix_len)| {
13968                                comment_prefix_range(
13969                                    snapshot.deref(),
13970                                    row,
13971                                    &prefix[..trimmed_prefix_len],
13972                                    &prefix[trimmed_prefix_len..],
13973                                    ignore_indent,
13974                                )
13975                            })
13976                            .max_by_key(|range| range.end.column - range.start.column)
13977                            .expect("prefixes is non-empty");
13978
13979                        if prefix_range.is_empty() {
13980                            all_selection_lines_are_comments = false;
13981                        }
13982
13983                        selection_edit_ranges.push(prefix_range);
13984                    }
13985
13986                    if all_selection_lines_are_comments {
13987                        edits.extend(
13988                            selection_edit_ranges
13989                                .iter()
13990                                .cloned()
13991                                .map(|range| (range, empty_str.clone())),
13992                        );
13993                    } else {
13994                        let min_column = selection_edit_ranges
13995                            .iter()
13996                            .map(|range| range.start.column)
13997                            .min()
13998                            .unwrap_or(0);
13999                        edits.extend(selection_edit_ranges.iter().map(|range| {
14000                            let position = Point::new(range.start.row, min_column);
14001                            (position..position, first_prefix.clone())
14002                        }));
14003                    }
14004                } else if let Some((full_comment_prefix, comment_suffix)) =
14005                    language.block_comment_delimiters()
14006                {
14007                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14008                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14009                    let prefix_range = comment_prefix_range(
14010                        snapshot.deref(),
14011                        start_row,
14012                        comment_prefix,
14013                        comment_prefix_whitespace,
14014                        ignore_indent,
14015                    );
14016                    let suffix_range = comment_suffix_range(
14017                        snapshot.deref(),
14018                        end_row,
14019                        comment_suffix.trim_start_matches(' '),
14020                        comment_suffix.starts_with(' '),
14021                    );
14022
14023                    if prefix_range.is_empty() || suffix_range.is_empty() {
14024                        edits.push((
14025                            prefix_range.start..prefix_range.start,
14026                            full_comment_prefix.clone(),
14027                        ));
14028                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14029                        suffixes_inserted.push((end_row, comment_suffix.len()));
14030                    } else {
14031                        edits.push((prefix_range, empty_str.clone()));
14032                        edits.push((suffix_range, empty_str.clone()));
14033                    }
14034                } else {
14035                    continue;
14036                }
14037            }
14038
14039            drop(snapshot);
14040            this.buffer.update(cx, |buffer, cx| {
14041                buffer.edit(edits, None, cx);
14042            });
14043
14044            // Adjust selections so that they end before any comment suffixes that
14045            // were inserted.
14046            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14047            let mut selections = this.selections.all::<Point>(cx);
14048            let snapshot = this.buffer.read(cx).read(cx);
14049            for selection in &mut selections {
14050                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14051                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14052                        Ordering::Less => {
14053                            suffixes_inserted.next();
14054                            continue;
14055                        }
14056                        Ordering::Greater => break,
14057                        Ordering::Equal => {
14058                            if selection.end.column == snapshot.line_len(row) {
14059                                if selection.is_empty() {
14060                                    selection.start.column -= suffix_len as u32;
14061                                }
14062                                selection.end.column -= suffix_len as u32;
14063                            }
14064                            break;
14065                        }
14066                    }
14067                }
14068            }
14069
14070            drop(snapshot);
14071            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14072                s.select(selections)
14073            });
14074
14075            let selections = this.selections.all::<Point>(cx);
14076            let selections_on_single_row = selections.windows(2).all(|selections| {
14077                selections[0].start.row == selections[1].start.row
14078                    && selections[0].end.row == selections[1].end.row
14079                    && selections[0].start.row == selections[0].end.row
14080            });
14081            let selections_selecting = selections
14082                .iter()
14083                .any(|selection| selection.start != selection.end);
14084            let advance_downwards = action.advance_downwards
14085                && selections_on_single_row
14086                && !selections_selecting
14087                && !matches!(this.mode, EditorMode::SingleLine { .. });
14088
14089            if advance_downwards {
14090                let snapshot = this.buffer.read(cx).snapshot(cx);
14091
14092                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14093                    s.move_cursors_with(|display_snapshot, display_point, _| {
14094                        let mut point = display_point.to_point(display_snapshot);
14095                        point.row += 1;
14096                        point = snapshot.clip_point(point, Bias::Left);
14097                        let display_point = point.to_display_point(display_snapshot);
14098                        let goal = SelectionGoal::HorizontalPosition(
14099                            display_snapshot
14100                                .x_for_display_point(display_point, text_layout_details)
14101                                .into(),
14102                        );
14103                        (display_point, goal)
14104                    })
14105                });
14106            }
14107        });
14108    }
14109
14110    pub fn select_enclosing_symbol(
14111        &mut self,
14112        _: &SelectEnclosingSymbol,
14113        window: &mut Window,
14114        cx: &mut Context<Self>,
14115    ) {
14116        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14117
14118        let buffer = self.buffer.read(cx).snapshot(cx);
14119        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14120
14121        fn update_selection(
14122            selection: &Selection<usize>,
14123            buffer_snap: &MultiBufferSnapshot,
14124        ) -> Option<Selection<usize>> {
14125            let cursor = selection.head();
14126            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14127            for symbol in symbols.iter().rev() {
14128                let start = symbol.range.start.to_offset(buffer_snap);
14129                let end = symbol.range.end.to_offset(buffer_snap);
14130                let new_range = start..end;
14131                if start < selection.start || end > selection.end {
14132                    return Some(Selection {
14133                        id: selection.id,
14134                        start: new_range.start,
14135                        end: new_range.end,
14136                        goal: SelectionGoal::None,
14137                        reversed: selection.reversed,
14138                    });
14139                }
14140            }
14141            None
14142        }
14143
14144        let mut selected_larger_symbol = false;
14145        let new_selections = old_selections
14146            .iter()
14147            .map(|selection| match update_selection(selection, &buffer) {
14148                Some(new_selection) => {
14149                    if new_selection.range() != selection.range() {
14150                        selected_larger_symbol = true;
14151                    }
14152                    new_selection
14153                }
14154                None => selection.clone(),
14155            })
14156            .collect::<Vec<_>>();
14157
14158        if selected_larger_symbol {
14159            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14160                s.select(new_selections);
14161            });
14162        }
14163    }
14164
14165    pub fn select_larger_syntax_node(
14166        &mut self,
14167        _: &SelectLargerSyntaxNode,
14168        window: &mut Window,
14169        cx: &mut Context<Self>,
14170    ) {
14171        let Some(visible_row_count) = self.visible_row_count() else {
14172            return;
14173        };
14174        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14175        if old_selections.is_empty() {
14176            return;
14177        }
14178
14179        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14180
14181        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14182        let buffer = self.buffer.read(cx).snapshot(cx);
14183
14184        let mut selected_larger_node = false;
14185        let mut new_selections = old_selections
14186            .iter()
14187            .map(|selection| {
14188                let old_range = selection.start..selection.end;
14189
14190                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14191                    // manually select word at selection
14192                    if ["string_content", "inline"].contains(&node.kind()) {
14193                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14194                        // ignore if word is already selected
14195                        if !word_range.is_empty() && old_range != word_range {
14196                            let (last_word_range, _) =
14197                                buffer.surrounding_word(old_range.end, false);
14198                            // only select word if start and end point belongs to same word
14199                            if word_range == last_word_range {
14200                                selected_larger_node = true;
14201                                return Selection {
14202                                    id: selection.id,
14203                                    start: word_range.start,
14204                                    end: word_range.end,
14205                                    goal: SelectionGoal::None,
14206                                    reversed: selection.reversed,
14207                                };
14208                            }
14209                        }
14210                    }
14211                }
14212
14213                let mut new_range = old_range.clone();
14214                while let Some((_node, containing_range)) =
14215                    buffer.syntax_ancestor(new_range.clone())
14216                {
14217                    new_range = match containing_range {
14218                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14219                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14220                    };
14221                    if !display_map.intersects_fold(new_range.start)
14222                        && !display_map.intersects_fold(new_range.end)
14223                    {
14224                        break;
14225                    }
14226                }
14227
14228                selected_larger_node |= new_range != old_range;
14229                Selection {
14230                    id: selection.id,
14231                    start: new_range.start,
14232                    end: new_range.end,
14233                    goal: SelectionGoal::None,
14234                    reversed: selection.reversed,
14235                }
14236            })
14237            .collect::<Vec<_>>();
14238
14239        if !selected_larger_node {
14240            return; // don't put this call in the history
14241        }
14242
14243        // scroll based on transformation done to the last selection created by the user
14244        let (last_old, last_new) = old_selections
14245            .last()
14246            .zip(new_selections.last().cloned())
14247            .expect("old_selections isn't empty");
14248
14249        // revert selection
14250        let is_selection_reversed = {
14251            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14252            new_selections.last_mut().expect("checked above").reversed =
14253                should_newest_selection_be_reversed;
14254            should_newest_selection_be_reversed
14255        };
14256
14257        if selected_larger_node {
14258            self.select_syntax_node_history.disable_clearing = true;
14259            self.change_selections(None, window, cx, |s| {
14260                s.select(new_selections.clone());
14261            });
14262            self.select_syntax_node_history.disable_clearing = false;
14263        }
14264
14265        let start_row = last_new.start.to_display_point(&display_map).row().0;
14266        let end_row = last_new.end.to_display_point(&display_map).row().0;
14267        let selection_height = end_row - start_row + 1;
14268        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14269
14270        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14271        let scroll_behavior = if fits_on_the_screen {
14272            self.request_autoscroll(Autoscroll::fit(), cx);
14273            SelectSyntaxNodeScrollBehavior::FitSelection
14274        } else if is_selection_reversed {
14275            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14276            SelectSyntaxNodeScrollBehavior::CursorTop
14277        } else {
14278            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14279            SelectSyntaxNodeScrollBehavior::CursorBottom
14280        };
14281
14282        self.select_syntax_node_history.push((
14283            old_selections,
14284            scroll_behavior,
14285            is_selection_reversed,
14286        ));
14287    }
14288
14289    pub fn select_smaller_syntax_node(
14290        &mut self,
14291        _: &SelectSmallerSyntaxNode,
14292        window: &mut Window,
14293        cx: &mut Context<Self>,
14294    ) {
14295        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14296
14297        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14298            self.select_syntax_node_history.pop()
14299        {
14300            if let Some(selection) = selections.last_mut() {
14301                selection.reversed = is_selection_reversed;
14302            }
14303
14304            self.select_syntax_node_history.disable_clearing = true;
14305            self.change_selections(None, window, cx, |s| {
14306                s.select(selections.to_vec());
14307            });
14308            self.select_syntax_node_history.disable_clearing = false;
14309
14310            match scroll_behavior {
14311                SelectSyntaxNodeScrollBehavior::CursorTop => {
14312                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14313                }
14314                SelectSyntaxNodeScrollBehavior::FitSelection => {
14315                    self.request_autoscroll(Autoscroll::fit(), cx);
14316                }
14317                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14318                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14319                }
14320            }
14321        }
14322    }
14323
14324    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14325        if !EditorSettings::get_global(cx).gutter.runnables {
14326            self.clear_tasks();
14327            return Task::ready(());
14328        }
14329        let project = self.project.as_ref().map(Entity::downgrade);
14330        let task_sources = self.lsp_task_sources(cx);
14331        let multi_buffer = self.buffer.downgrade();
14332        cx.spawn_in(window, async move |editor, cx| {
14333            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14334            let Some(project) = project.and_then(|p| p.upgrade()) else {
14335                return;
14336            };
14337            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14338                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14339            }) else {
14340                return;
14341            };
14342
14343            let hide_runnables = project
14344                .update(cx, |project, cx| {
14345                    // Do not display any test indicators in non-dev server remote projects.
14346                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14347                })
14348                .unwrap_or(true);
14349            if hide_runnables {
14350                return;
14351            }
14352            let new_rows =
14353                cx.background_spawn({
14354                    let snapshot = display_snapshot.clone();
14355                    async move {
14356                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14357                    }
14358                })
14359                    .await;
14360            let Ok(lsp_tasks) =
14361                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14362            else {
14363                return;
14364            };
14365            let lsp_tasks = lsp_tasks.await;
14366
14367            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14368                lsp_tasks
14369                    .into_iter()
14370                    .flat_map(|(kind, tasks)| {
14371                        tasks.into_iter().filter_map(move |(location, task)| {
14372                            Some((kind.clone(), location?, task))
14373                        })
14374                    })
14375                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14376                        let buffer = location.target.buffer;
14377                        let buffer_snapshot = buffer.read(cx).snapshot();
14378                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14379                            |(excerpt_id, snapshot, _)| {
14380                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14381                                    display_snapshot
14382                                        .buffer_snapshot
14383                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14384                                } else {
14385                                    None
14386                                }
14387                            },
14388                        );
14389                        if let Some(offset) = offset {
14390                            let task_buffer_range =
14391                                location.target.range.to_point(&buffer_snapshot);
14392                            let context_buffer_range =
14393                                task_buffer_range.to_offset(&buffer_snapshot);
14394                            let context_range = BufferOffset(context_buffer_range.start)
14395                                ..BufferOffset(context_buffer_range.end);
14396
14397                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14398                                .or_insert_with(|| RunnableTasks {
14399                                    templates: Vec::new(),
14400                                    offset,
14401                                    column: task_buffer_range.start.column,
14402                                    extra_variables: HashMap::default(),
14403                                    context_range,
14404                                })
14405                                .templates
14406                                .push((kind, task.original_task().clone()));
14407                        }
14408
14409                        acc
14410                    })
14411            }) else {
14412                return;
14413            };
14414
14415            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14416                buffer.language_settings(cx).tasks.prefer_lsp
14417            }) else {
14418                return;
14419            };
14420
14421            let rows = Self::runnable_rows(
14422                project,
14423                display_snapshot,
14424                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14425                new_rows,
14426                cx.clone(),
14427            )
14428            .await;
14429            editor
14430                .update(cx, |editor, _| {
14431                    editor.clear_tasks();
14432                    for (key, mut value) in rows {
14433                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14434                            value.templates.extend(lsp_tasks.templates);
14435                        }
14436
14437                        editor.insert_tasks(key, value);
14438                    }
14439                    for (key, value) in lsp_tasks_by_rows {
14440                        editor.insert_tasks(key, value);
14441                    }
14442                })
14443                .ok();
14444        })
14445    }
14446    fn fetch_runnable_ranges(
14447        snapshot: &DisplaySnapshot,
14448        range: Range<Anchor>,
14449    ) -> Vec<language::RunnableRange> {
14450        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14451    }
14452
14453    fn runnable_rows(
14454        project: Entity<Project>,
14455        snapshot: DisplaySnapshot,
14456        prefer_lsp: bool,
14457        runnable_ranges: Vec<RunnableRange>,
14458        cx: AsyncWindowContext,
14459    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14460        cx.spawn(async move |cx| {
14461            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14462            for mut runnable in runnable_ranges {
14463                let Some(tasks) = cx
14464                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14465                    .ok()
14466                else {
14467                    continue;
14468                };
14469                let mut tasks = tasks.await;
14470
14471                if prefer_lsp {
14472                    tasks.retain(|(task_kind, _)| {
14473                        !matches!(task_kind, TaskSourceKind::Language { .. })
14474                    });
14475                }
14476                if tasks.is_empty() {
14477                    continue;
14478                }
14479
14480                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14481                let Some(row) = snapshot
14482                    .buffer_snapshot
14483                    .buffer_line_for_row(MultiBufferRow(point.row))
14484                    .map(|(_, range)| range.start.row)
14485                else {
14486                    continue;
14487                };
14488
14489                let context_range =
14490                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14491                runnable_rows.push((
14492                    (runnable.buffer_id, row),
14493                    RunnableTasks {
14494                        templates: tasks,
14495                        offset: snapshot
14496                            .buffer_snapshot
14497                            .anchor_before(runnable.run_range.start),
14498                        context_range,
14499                        column: point.column,
14500                        extra_variables: runnable.extra_captures,
14501                    },
14502                ));
14503            }
14504            runnable_rows
14505        })
14506    }
14507
14508    fn templates_with_tags(
14509        project: &Entity<Project>,
14510        runnable: &mut Runnable,
14511        cx: &mut App,
14512    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14513        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14514            let (worktree_id, file) = project
14515                .buffer_for_id(runnable.buffer, cx)
14516                .and_then(|buffer| buffer.read(cx).file())
14517                .map(|file| (file.worktree_id(cx), file.clone()))
14518                .unzip();
14519
14520            (
14521                project.task_store().read(cx).task_inventory().cloned(),
14522                worktree_id,
14523                file,
14524            )
14525        });
14526
14527        let tags = mem::take(&mut runnable.tags);
14528        let language = runnable.language.clone();
14529        cx.spawn(async move |cx| {
14530            let mut templates_with_tags = Vec::new();
14531            if let Some(inventory) = inventory {
14532                for RunnableTag(tag) in tags {
14533                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14534                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14535                    }) else {
14536                        return templates_with_tags;
14537                    };
14538                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14539                        move |(_, template)| {
14540                            template.tags.iter().any(|source_tag| source_tag == &tag)
14541                        },
14542                    ));
14543                }
14544            }
14545            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14546
14547            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14548                // Strongest source wins; if we have worktree tag binding, prefer that to
14549                // global and language bindings;
14550                // if we have a global binding, prefer that to language binding.
14551                let first_mismatch = templates_with_tags
14552                    .iter()
14553                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14554                if let Some(index) = first_mismatch {
14555                    templates_with_tags.truncate(index);
14556                }
14557            }
14558
14559            templates_with_tags
14560        })
14561    }
14562
14563    pub fn move_to_enclosing_bracket(
14564        &mut self,
14565        _: &MoveToEnclosingBracket,
14566        window: &mut Window,
14567        cx: &mut Context<Self>,
14568    ) {
14569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14570        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14571            s.move_offsets_with(|snapshot, selection| {
14572                let Some(enclosing_bracket_ranges) =
14573                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14574                else {
14575                    return;
14576                };
14577
14578                let mut best_length = usize::MAX;
14579                let mut best_inside = false;
14580                let mut best_in_bracket_range = false;
14581                let mut best_destination = None;
14582                for (open, close) in enclosing_bracket_ranges {
14583                    let close = close.to_inclusive();
14584                    let length = close.end() - open.start;
14585                    let inside = selection.start >= open.end && selection.end <= *close.start();
14586                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14587                        || close.contains(&selection.head());
14588
14589                    // If best is next to a bracket and current isn't, skip
14590                    if !in_bracket_range && best_in_bracket_range {
14591                        continue;
14592                    }
14593
14594                    // Prefer smaller lengths unless best is inside and current isn't
14595                    if length > best_length && (best_inside || !inside) {
14596                        continue;
14597                    }
14598
14599                    best_length = length;
14600                    best_inside = inside;
14601                    best_in_bracket_range = in_bracket_range;
14602                    best_destination = Some(
14603                        if close.contains(&selection.start) && close.contains(&selection.end) {
14604                            if inside { open.end } else { open.start }
14605                        } else if inside {
14606                            *close.start()
14607                        } else {
14608                            *close.end()
14609                        },
14610                    );
14611                }
14612
14613                if let Some(destination) = best_destination {
14614                    selection.collapse_to(destination, SelectionGoal::None);
14615                }
14616            })
14617        });
14618    }
14619
14620    pub fn undo_selection(
14621        &mut self,
14622        _: &UndoSelection,
14623        window: &mut Window,
14624        cx: &mut Context<Self>,
14625    ) {
14626        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14627        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14628            self.selection_history.mode = SelectionHistoryMode::Undoing;
14629            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14630                this.end_selection(window, cx);
14631                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14632                    s.select_anchors(entry.selections.to_vec())
14633                });
14634            });
14635            self.selection_history.mode = SelectionHistoryMode::Normal;
14636
14637            self.select_next_state = entry.select_next_state;
14638            self.select_prev_state = entry.select_prev_state;
14639            self.add_selections_state = entry.add_selections_state;
14640        }
14641    }
14642
14643    pub fn redo_selection(
14644        &mut self,
14645        _: &RedoSelection,
14646        window: &mut Window,
14647        cx: &mut Context<Self>,
14648    ) {
14649        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14650        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14651            self.selection_history.mode = SelectionHistoryMode::Redoing;
14652            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14653                this.end_selection(window, cx);
14654                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14655                    s.select_anchors(entry.selections.to_vec())
14656                });
14657            });
14658            self.selection_history.mode = SelectionHistoryMode::Normal;
14659
14660            self.select_next_state = entry.select_next_state;
14661            self.select_prev_state = entry.select_prev_state;
14662            self.add_selections_state = entry.add_selections_state;
14663        }
14664    }
14665
14666    pub fn expand_excerpts(
14667        &mut self,
14668        action: &ExpandExcerpts,
14669        _: &mut Window,
14670        cx: &mut Context<Self>,
14671    ) {
14672        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14673    }
14674
14675    pub fn expand_excerpts_down(
14676        &mut self,
14677        action: &ExpandExcerptsDown,
14678        _: &mut Window,
14679        cx: &mut Context<Self>,
14680    ) {
14681        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14682    }
14683
14684    pub fn expand_excerpts_up(
14685        &mut self,
14686        action: &ExpandExcerptsUp,
14687        _: &mut Window,
14688        cx: &mut Context<Self>,
14689    ) {
14690        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14691    }
14692
14693    pub fn expand_excerpts_for_direction(
14694        &mut self,
14695        lines: u32,
14696        direction: ExpandExcerptDirection,
14697
14698        cx: &mut Context<Self>,
14699    ) {
14700        let selections = self.selections.disjoint_anchors();
14701
14702        let lines = if lines == 0 {
14703            EditorSettings::get_global(cx).expand_excerpt_lines
14704        } else {
14705            lines
14706        };
14707
14708        self.buffer.update(cx, |buffer, cx| {
14709            let snapshot = buffer.snapshot(cx);
14710            let mut excerpt_ids = selections
14711                .iter()
14712                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14713                .collect::<Vec<_>>();
14714            excerpt_ids.sort();
14715            excerpt_ids.dedup();
14716            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14717        })
14718    }
14719
14720    pub fn expand_excerpt(
14721        &mut self,
14722        excerpt: ExcerptId,
14723        direction: ExpandExcerptDirection,
14724        window: &mut Window,
14725        cx: &mut Context<Self>,
14726    ) {
14727        let current_scroll_position = self.scroll_position(cx);
14728        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14729        let mut should_scroll_up = false;
14730
14731        if direction == ExpandExcerptDirection::Down {
14732            let multi_buffer = self.buffer.read(cx);
14733            let snapshot = multi_buffer.snapshot(cx);
14734            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14735                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14736                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14737                        let buffer_snapshot = buffer.read(cx).snapshot();
14738                        let excerpt_end_row =
14739                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14740                        let last_row = buffer_snapshot.max_point().row;
14741                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14742                        should_scroll_up = lines_below >= lines_to_expand;
14743                    }
14744                }
14745            }
14746        }
14747
14748        self.buffer.update(cx, |buffer, cx| {
14749            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14750        });
14751
14752        if should_scroll_up {
14753            let new_scroll_position =
14754                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14755            self.set_scroll_position(new_scroll_position, window, cx);
14756        }
14757    }
14758
14759    pub fn go_to_singleton_buffer_point(
14760        &mut self,
14761        point: Point,
14762        window: &mut Window,
14763        cx: &mut Context<Self>,
14764    ) {
14765        self.go_to_singleton_buffer_range(point..point, window, cx);
14766    }
14767
14768    pub fn go_to_singleton_buffer_range(
14769        &mut self,
14770        range: Range<Point>,
14771        window: &mut Window,
14772        cx: &mut Context<Self>,
14773    ) {
14774        let multibuffer = self.buffer().read(cx);
14775        let Some(buffer) = multibuffer.as_singleton() else {
14776            return;
14777        };
14778        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14779            return;
14780        };
14781        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14782            return;
14783        };
14784        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14785            s.select_anchor_ranges([start..end])
14786        });
14787    }
14788
14789    pub fn go_to_diagnostic(
14790        &mut self,
14791        _: &GoToDiagnostic,
14792        window: &mut Window,
14793        cx: &mut Context<Self>,
14794    ) {
14795        if !self.diagnostics_enabled() {
14796            return;
14797        }
14798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14799        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14800    }
14801
14802    pub fn go_to_prev_diagnostic(
14803        &mut self,
14804        _: &GoToPreviousDiagnostic,
14805        window: &mut Window,
14806        cx: &mut Context<Self>,
14807    ) {
14808        if !self.diagnostics_enabled() {
14809            return;
14810        }
14811        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14812        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14813    }
14814
14815    pub fn go_to_diagnostic_impl(
14816        &mut self,
14817        direction: Direction,
14818        window: &mut Window,
14819        cx: &mut Context<Self>,
14820    ) {
14821        let buffer = self.buffer.read(cx).snapshot(cx);
14822        let selection = self.selections.newest::<usize>(cx);
14823
14824        let mut active_group_id = None;
14825        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14826            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14827                active_group_id = Some(active_group.group_id);
14828            }
14829        }
14830
14831        fn filtered(
14832            snapshot: EditorSnapshot,
14833            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14834        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14835            diagnostics
14836                .filter(|entry| entry.range.start != entry.range.end)
14837                .filter(|entry| !entry.diagnostic.is_unnecessary)
14838                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14839        }
14840
14841        let snapshot = self.snapshot(window, cx);
14842        let before = filtered(
14843            snapshot.clone(),
14844            buffer
14845                .diagnostics_in_range(0..selection.start)
14846                .filter(|entry| entry.range.start <= selection.start),
14847        );
14848        let after = filtered(
14849            snapshot,
14850            buffer
14851                .diagnostics_in_range(selection.start..buffer.len())
14852                .filter(|entry| entry.range.start >= selection.start),
14853        );
14854
14855        let mut found: Option<DiagnosticEntry<usize>> = None;
14856        if direction == Direction::Prev {
14857            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14858            {
14859                for diagnostic in prev_diagnostics.into_iter().rev() {
14860                    if diagnostic.range.start != selection.start
14861                        || active_group_id
14862                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14863                    {
14864                        found = Some(diagnostic);
14865                        break 'outer;
14866                    }
14867                }
14868            }
14869        } else {
14870            for diagnostic in after.chain(before) {
14871                if diagnostic.range.start != selection.start
14872                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14873                {
14874                    found = Some(diagnostic);
14875                    break;
14876                }
14877            }
14878        }
14879        let Some(next_diagnostic) = found else {
14880            return;
14881        };
14882
14883        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14884            return;
14885        };
14886        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14887            s.select_ranges(vec![
14888                next_diagnostic.range.start..next_diagnostic.range.start,
14889            ])
14890        });
14891        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14892        self.refresh_inline_completion(false, true, window, cx);
14893    }
14894
14895    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14896        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14897        let snapshot = self.snapshot(window, cx);
14898        let selection = self.selections.newest::<Point>(cx);
14899        self.go_to_hunk_before_or_after_position(
14900            &snapshot,
14901            selection.head(),
14902            Direction::Next,
14903            window,
14904            cx,
14905        );
14906    }
14907
14908    pub fn go_to_hunk_before_or_after_position(
14909        &mut self,
14910        snapshot: &EditorSnapshot,
14911        position: Point,
14912        direction: Direction,
14913        window: &mut Window,
14914        cx: &mut Context<Editor>,
14915    ) {
14916        let row = if direction == Direction::Next {
14917            self.hunk_after_position(snapshot, position)
14918                .map(|hunk| hunk.row_range.start)
14919        } else {
14920            self.hunk_before_position(snapshot, position)
14921        };
14922
14923        if let Some(row) = row {
14924            let destination = Point::new(row.0, 0);
14925            let autoscroll = Autoscroll::center();
14926
14927            self.unfold_ranges(&[destination..destination], false, false, cx);
14928            self.change_selections(Some(autoscroll), window, cx, |s| {
14929                s.select_ranges([destination..destination]);
14930            });
14931        }
14932    }
14933
14934    fn hunk_after_position(
14935        &mut self,
14936        snapshot: &EditorSnapshot,
14937        position: Point,
14938    ) -> Option<MultiBufferDiffHunk> {
14939        snapshot
14940            .buffer_snapshot
14941            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14942            .find(|hunk| hunk.row_range.start.0 > position.row)
14943            .or_else(|| {
14944                snapshot
14945                    .buffer_snapshot
14946                    .diff_hunks_in_range(Point::zero()..position)
14947                    .find(|hunk| hunk.row_range.end.0 < position.row)
14948            })
14949    }
14950
14951    fn go_to_prev_hunk(
14952        &mut self,
14953        _: &GoToPreviousHunk,
14954        window: &mut Window,
14955        cx: &mut Context<Self>,
14956    ) {
14957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14958        let snapshot = self.snapshot(window, cx);
14959        let selection = self.selections.newest::<Point>(cx);
14960        self.go_to_hunk_before_or_after_position(
14961            &snapshot,
14962            selection.head(),
14963            Direction::Prev,
14964            window,
14965            cx,
14966        );
14967    }
14968
14969    fn hunk_before_position(
14970        &mut self,
14971        snapshot: &EditorSnapshot,
14972        position: Point,
14973    ) -> Option<MultiBufferRow> {
14974        snapshot
14975            .buffer_snapshot
14976            .diff_hunk_before(position)
14977            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14978    }
14979
14980    fn go_to_next_change(
14981        &mut self,
14982        _: &GoToNextChange,
14983        window: &mut Window,
14984        cx: &mut Context<Self>,
14985    ) {
14986        if let Some(selections) = self
14987            .change_list
14988            .next_change(1, Direction::Next)
14989            .map(|s| s.to_vec())
14990        {
14991            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14992                let map = s.display_map();
14993                s.select_display_ranges(selections.iter().map(|a| {
14994                    let point = a.to_display_point(&map);
14995                    point..point
14996                }))
14997            })
14998        }
14999    }
15000
15001    fn go_to_previous_change(
15002        &mut self,
15003        _: &GoToPreviousChange,
15004        window: &mut Window,
15005        cx: &mut Context<Self>,
15006    ) {
15007        if let Some(selections) = self
15008            .change_list
15009            .next_change(1, Direction::Prev)
15010            .map(|s| s.to_vec())
15011        {
15012            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15013                let map = s.display_map();
15014                s.select_display_ranges(selections.iter().map(|a| {
15015                    let point = a.to_display_point(&map);
15016                    point..point
15017                }))
15018            })
15019        }
15020    }
15021
15022    fn go_to_line<T: 'static>(
15023        &mut self,
15024        position: Anchor,
15025        highlight_color: Option<Hsla>,
15026        window: &mut Window,
15027        cx: &mut Context<Self>,
15028    ) {
15029        let snapshot = self.snapshot(window, cx).display_snapshot;
15030        let position = position.to_point(&snapshot.buffer_snapshot);
15031        let start = snapshot
15032            .buffer_snapshot
15033            .clip_point(Point::new(position.row, 0), Bias::Left);
15034        let end = start + Point::new(1, 0);
15035        let start = snapshot.buffer_snapshot.anchor_before(start);
15036        let end = snapshot.buffer_snapshot.anchor_before(end);
15037
15038        self.highlight_rows::<T>(
15039            start..end,
15040            highlight_color
15041                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15042            Default::default(),
15043            cx,
15044        );
15045
15046        if self.buffer.read(cx).is_singleton() {
15047            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15048        }
15049    }
15050
15051    pub fn go_to_definition(
15052        &mut self,
15053        _: &GoToDefinition,
15054        window: &mut Window,
15055        cx: &mut Context<Self>,
15056    ) -> Task<Result<Navigated>> {
15057        let definition =
15058            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15059        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15060        cx.spawn_in(window, async move |editor, cx| {
15061            if definition.await? == Navigated::Yes {
15062                return Ok(Navigated::Yes);
15063            }
15064            match fallback_strategy {
15065                GoToDefinitionFallback::None => Ok(Navigated::No),
15066                GoToDefinitionFallback::FindAllReferences => {
15067                    match editor.update_in(cx, |editor, window, cx| {
15068                        editor.find_all_references(&FindAllReferences, window, cx)
15069                    })? {
15070                        Some(references) => references.await,
15071                        None => Ok(Navigated::No),
15072                    }
15073                }
15074            }
15075        })
15076    }
15077
15078    pub fn go_to_declaration(
15079        &mut self,
15080        _: &GoToDeclaration,
15081        window: &mut Window,
15082        cx: &mut Context<Self>,
15083    ) -> Task<Result<Navigated>> {
15084        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15085    }
15086
15087    pub fn go_to_declaration_split(
15088        &mut self,
15089        _: &GoToDeclaration,
15090        window: &mut Window,
15091        cx: &mut Context<Self>,
15092    ) -> Task<Result<Navigated>> {
15093        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15094    }
15095
15096    pub fn go_to_implementation(
15097        &mut self,
15098        _: &GoToImplementation,
15099        window: &mut Window,
15100        cx: &mut Context<Self>,
15101    ) -> Task<Result<Navigated>> {
15102        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15103    }
15104
15105    pub fn go_to_implementation_split(
15106        &mut self,
15107        _: &GoToImplementationSplit,
15108        window: &mut Window,
15109        cx: &mut Context<Self>,
15110    ) -> Task<Result<Navigated>> {
15111        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15112    }
15113
15114    pub fn go_to_type_definition(
15115        &mut self,
15116        _: &GoToTypeDefinition,
15117        window: &mut Window,
15118        cx: &mut Context<Self>,
15119    ) -> Task<Result<Navigated>> {
15120        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15121    }
15122
15123    pub fn go_to_definition_split(
15124        &mut self,
15125        _: &GoToDefinitionSplit,
15126        window: &mut Window,
15127        cx: &mut Context<Self>,
15128    ) -> Task<Result<Navigated>> {
15129        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15130    }
15131
15132    pub fn go_to_type_definition_split(
15133        &mut self,
15134        _: &GoToTypeDefinitionSplit,
15135        window: &mut Window,
15136        cx: &mut Context<Self>,
15137    ) -> Task<Result<Navigated>> {
15138        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15139    }
15140
15141    fn go_to_definition_of_kind(
15142        &mut self,
15143        kind: GotoDefinitionKind,
15144        split: bool,
15145        window: &mut Window,
15146        cx: &mut Context<Self>,
15147    ) -> Task<Result<Navigated>> {
15148        let Some(provider) = self.semantics_provider.clone() else {
15149            return Task::ready(Ok(Navigated::No));
15150        };
15151        let head = self.selections.newest::<usize>(cx).head();
15152        let buffer = self.buffer.read(cx);
15153        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15154            text_anchor
15155        } else {
15156            return Task::ready(Ok(Navigated::No));
15157        };
15158
15159        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15160            return Task::ready(Ok(Navigated::No));
15161        };
15162
15163        cx.spawn_in(window, async move |editor, cx| {
15164            let definitions = definitions.await?;
15165            let navigated = editor
15166                .update_in(cx, |editor, window, cx| {
15167                    editor.navigate_to_hover_links(
15168                        Some(kind),
15169                        definitions
15170                            .into_iter()
15171                            .filter(|location| {
15172                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15173                            })
15174                            .map(HoverLink::Text)
15175                            .collect::<Vec<_>>(),
15176                        split,
15177                        window,
15178                        cx,
15179                    )
15180                })?
15181                .await?;
15182            anyhow::Ok(navigated)
15183        })
15184    }
15185
15186    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15187        let selection = self.selections.newest_anchor();
15188        let head = selection.head();
15189        let tail = selection.tail();
15190
15191        let Some((buffer, start_position)) =
15192            self.buffer.read(cx).text_anchor_for_position(head, cx)
15193        else {
15194            return;
15195        };
15196
15197        let end_position = if head != tail {
15198            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15199                return;
15200            };
15201            Some(pos)
15202        } else {
15203            None
15204        };
15205
15206        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15207            let url = if let Some(end_pos) = end_position {
15208                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15209            } else {
15210                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15211            };
15212
15213            if let Some(url) = url {
15214                editor.update(cx, |_, cx| {
15215                    cx.open_url(&url);
15216                })
15217            } else {
15218                Ok(())
15219            }
15220        });
15221
15222        url_finder.detach();
15223    }
15224
15225    pub fn open_selected_filename(
15226        &mut self,
15227        _: &OpenSelectedFilename,
15228        window: &mut Window,
15229        cx: &mut Context<Self>,
15230    ) {
15231        let Some(workspace) = self.workspace() else {
15232            return;
15233        };
15234
15235        let position = self.selections.newest_anchor().head();
15236
15237        let Some((buffer, buffer_position)) =
15238            self.buffer.read(cx).text_anchor_for_position(position, cx)
15239        else {
15240            return;
15241        };
15242
15243        let project = self.project.clone();
15244
15245        cx.spawn_in(window, async move |_, cx| {
15246            let result = find_file(&buffer, project, buffer_position, cx).await;
15247
15248            if let Some((_, path)) = result {
15249                workspace
15250                    .update_in(cx, |workspace, window, cx| {
15251                        workspace.open_resolved_path(path, window, cx)
15252                    })?
15253                    .await?;
15254            }
15255            anyhow::Ok(())
15256        })
15257        .detach();
15258    }
15259
15260    pub(crate) fn navigate_to_hover_links(
15261        &mut self,
15262        kind: Option<GotoDefinitionKind>,
15263        mut definitions: Vec<HoverLink>,
15264        split: bool,
15265        window: &mut Window,
15266        cx: &mut Context<Editor>,
15267    ) -> Task<Result<Navigated>> {
15268        // If there is one definition, just open it directly
15269        if definitions.len() == 1 {
15270            let definition = definitions.pop().unwrap();
15271
15272            enum TargetTaskResult {
15273                Location(Option<Location>),
15274                AlreadyNavigated,
15275            }
15276
15277            let target_task = match definition {
15278                HoverLink::Text(link) => {
15279                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15280                }
15281                HoverLink::InlayHint(lsp_location, server_id) => {
15282                    let computation =
15283                        self.compute_target_location(lsp_location, server_id, window, cx);
15284                    cx.background_spawn(async move {
15285                        let location = computation.await?;
15286                        Ok(TargetTaskResult::Location(location))
15287                    })
15288                }
15289                HoverLink::Url(url) => {
15290                    cx.open_url(&url);
15291                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15292                }
15293                HoverLink::File(path) => {
15294                    if let Some(workspace) = self.workspace() {
15295                        cx.spawn_in(window, async move |_, cx| {
15296                            workspace
15297                                .update_in(cx, |workspace, window, cx| {
15298                                    workspace.open_resolved_path(path, window, cx)
15299                                })?
15300                                .await
15301                                .map(|_| TargetTaskResult::AlreadyNavigated)
15302                        })
15303                    } else {
15304                        Task::ready(Ok(TargetTaskResult::Location(None)))
15305                    }
15306                }
15307            };
15308            cx.spawn_in(window, async move |editor, cx| {
15309                let target = match target_task.await.context("target resolution task")? {
15310                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15311                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15312                    TargetTaskResult::Location(Some(target)) => target,
15313                };
15314
15315                editor.update_in(cx, |editor, window, cx| {
15316                    let Some(workspace) = editor.workspace() else {
15317                        return Navigated::No;
15318                    };
15319                    let pane = workspace.read(cx).active_pane().clone();
15320
15321                    let range = target.range.to_point(target.buffer.read(cx));
15322                    let range = editor.range_for_match(&range);
15323                    let range = collapse_multiline_range(range);
15324
15325                    if !split
15326                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15327                    {
15328                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15329                    } else {
15330                        window.defer(cx, move |window, cx| {
15331                            let target_editor: Entity<Self> =
15332                                workspace.update(cx, |workspace, cx| {
15333                                    let pane = if split {
15334                                        workspace.adjacent_pane(window, cx)
15335                                    } else {
15336                                        workspace.active_pane().clone()
15337                                    };
15338
15339                                    workspace.open_project_item(
15340                                        pane,
15341                                        target.buffer.clone(),
15342                                        true,
15343                                        true,
15344                                        window,
15345                                        cx,
15346                                    )
15347                                });
15348                            target_editor.update(cx, |target_editor, cx| {
15349                                // When selecting a definition in a different buffer, disable the nav history
15350                                // to avoid creating a history entry at the previous cursor location.
15351                                pane.update(cx, |pane, _| pane.disable_history());
15352                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15353                                pane.update(cx, |pane, _| pane.enable_history());
15354                            });
15355                        });
15356                    }
15357                    Navigated::Yes
15358                })
15359            })
15360        } else if !definitions.is_empty() {
15361            cx.spawn_in(window, async move |editor, cx| {
15362                let (title, location_tasks, workspace) = editor
15363                    .update_in(cx, |editor, window, cx| {
15364                        let tab_kind = match kind {
15365                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15366                            _ => "Definitions",
15367                        };
15368                        let title = definitions
15369                            .iter()
15370                            .find_map(|definition| match definition {
15371                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15372                                    let buffer = origin.buffer.read(cx);
15373                                    format!(
15374                                        "{} for {}",
15375                                        tab_kind,
15376                                        buffer
15377                                            .text_for_range(origin.range.clone())
15378                                            .collect::<String>()
15379                                    )
15380                                }),
15381                                HoverLink::InlayHint(_, _) => None,
15382                                HoverLink::Url(_) => None,
15383                                HoverLink::File(_) => None,
15384                            })
15385                            .unwrap_or(tab_kind.to_string());
15386                        let location_tasks = definitions
15387                            .into_iter()
15388                            .map(|definition| match definition {
15389                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15390                                HoverLink::InlayHint(lsp_location, server_id) => editor
15391                                    .compute_target_location(lsp_location, server_id, window, cx),
15392                                HoverLink::Url(_) => Task::ready(Ok(None)),
15393                                HoverLink::File(_) => Task::ready(Ok(None)),
15394                            })
15395                            .collect::<Vec<_>>();
15396                        (title, location_tasks, editor.workspace().clone())
15397                    })
15398                    .context("location tasks preparation")?;
15399
15400                let locations: Vec<Location> = future::join_all(location_tasks)
15401                    .await
15402                    .into_iter()
15403                    .filter_map(|location| location.transpose())
15404                    .collect::<Result<_>>()
15405                    .context("location tasks")?;
15406
15407                if locations.is_empty() {
15408                    return Ok(Navigated::No);
15409                }
15410
15411                let Some(workspace) = workspace else {
15412                    return Ok(Navigated::No);
15413                };
15414
15415                let opened = workspace
15416                    .update_in(cx, |workspace, window, cx| {
15417                        Self::open_locations_in_multibuffer(
15418                            workspace,
15419                            locations,
15420                            title,
15421                            split,
15422                            MultibufferSelectionMode::First,
15423                            window,
15424                            cx,
15425                        )
15426                    })
15427                    .ok();
15428
15429                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15430            })
15431        } else {
15432            Task::ready(Ok(Navigated::No))
15433        }
15434    }
15435
15436    fn compute_target_location(
15437        &self,
15438        lsp_location: lsp::Location,
15439        server_id: LanguageServerId,
15440        window: &mut Window,
15441        cx: &mut Context<Self>,
15442    ) -> Task<anyhow::Result<Option<Location>>> {
15443        let Some(project) = self.project.clone() else {
15444            return Task::ready(Ok(None));
15445        };
15446
15447        cx.spawn_in(window, async move |editor, cx| {
15448            let location_task = editor.update(cx, |_, cx| {
15449                project.update(cx, |project, cx| {
15450                    let language_server_name = project
15451                        .language_server_statuses(cx)
15452                        .find(|(id, _)| server_id == *id)
15453                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15454                    language_server_name.map(|language_server_name| {
15455                        project.open_local_buffer_via_lsp(
15456                            lsp_location.uri.clone(),
15457                            server_id,
15458                            language_server_name,
15459                            cx,
15460                        )
15461                    })
15462                })
15463            })?;
15464            let location = match location_task {
15465                Some(task) => Some({
15466                    let target_buffer_handle = task.await.context("open local buffer")?;
15467                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15468                        let target_start = target_buffer
15469                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15470                        let target_end = target_buffer
15471                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15472                        target_buffer.anchor_after(target_start)
15473                            ..target_buffer.anchor_before(target_end)
15474                    })?;
15475                    Location {
15476                        buffer: target_buffer_handle,
15477                        range,
15478                    }
15479                }),
15480                None => None,
15481            };
15482            Ok(location)
15483        })
15484    }
15485
15486    pub fn find_all_references(
15487        &mut self,
15488        _: &FindAllReferences,
15489        window: &mut Window,
15490        cx: &mut Context<Self>,
15491    ) -> Option<Task<Result<Navigated>>> {
15492        let selection = self.selections.newest::<usize>(cx);
15493        let multi_buffer = self.buffer.read(cx);
15494        let head = selection.head();
15495
15496        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15497        let head_anchor = multi_buffer_snapshot.anchor_at(
15498            head,
15499            if head < selection.tail() {
15500                Bias::Right
15501            } else {
15502                Bias::Left
15503            },
15504        );
15505
15506        match self
15507            .find_all_references_task_sources
15508            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15509        {
15510            Ok(_) => {
15511                log::info!(
15512                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15513                );
15514                return None;
15515            }
15516            Err(i) => {
15517                self.find_all_references_task_sources.insert(i, head_anchor);
15518            }
15519        }
15520
15521        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15522        let workspace = self.workspace()?;
15523        let project = workspace.read(cx).project().clone();
15524        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15525        Some(cx.spawn_in(window, async move |editor, cx| {
15526            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15527                if let Ok(i) = editor
15528                    .find_all_references_task_sources
15529                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15530                {
15531                    editor.find_all_references_task_sources.remove(i);
15532                }
15533            });
15534
15535            let locations = references.await?;
15536            if locations.is_empty() {
15537                return anyhow::Ok(Navigated::No);
15538            }
15539
15540            workspace.update_in(cx, |workspace, window, cx| {
15541                let title = locations
15542                    .first()
15543                    .as_ref()
15544                    .map(|location| {
15545                        let buffer = location.buffer.read(cx);
15546                        format!(
15547                            "References to `{}`",
15548                            buffer
15549                                .text_for_range(location.range.clone())
15550                                .collect::<String>()
15551                        )
15552                    })
15553                    .unwrap();
15554                Self::open_locations_in_multibuffer(
15555                    workspace,
15556                    locations,
15557                    title,
15558                    false,
15559                    MultibufferSelectionMode::First,
15560                    window,
15561                    cx,
15562                );
15563                Navigated::Yes
15564            })
15565        }))
15566    }
15567
15568    /// Opens a multibuffer with the given project locations in it
15569    pub fn open_locations_in_multibuffer(
15570        workspace: &mut Workspace,
15571        mut locations: Vec<Location>,
15572        title: String,
15573        split: bool,
15574        multibuffer_selection_mode: MultibufferSelectionMode,
15575        window: &mut Window,
15576        cx: &mut Context<Workspace>,
15577    ) {
15578        if locations.is_empty() {
15579            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15580            return;
15581        }
15582
15583        // If there are multiple definitions, open them in a multibuffer
15584        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15585        let mut locations = locations.into_iter().peekable();
15586        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15587        let capability = workspace.project().read(cx).capability();
15588
15589        let excerpt_buffer = cx.new(|cx| {
15590            let mut multibuffer = MultiBuffer::new(capability);
15591            while let Some(location) = locations.next() {
15592                let buffer = location.buffer.read(cx);
15593                let mut ranges_for_buffer = Vec::new();
15594                let range = location.range.to_point(buffer);
15595                ranges_for_buffer.push(range.clone());
15596
15597                while let Some(next_location) = locations.peek() {
15598                    if next_location.buffer == location.buffer {
15599                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15600                        locations.next();
15601                    } else {
15602                        break;
15603                    }
15604                }
15605
15606                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15607                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15608                    PathKey::for_buffer(&location.buffer, cx),
15609                    location.buffer.clone(),
15610                    ranges_for_buffer,
15611                    DEFAULT_MULTIBUFFER_CONTEXT,
15612                    cx,
15613                );
15614                ranges.extend(new_ranges)
15615            }
15616
15617            multibuffer.with_title(title)
15618        });
15619
15620        let editor = cx.new(|cx| {
15621            Editor::for_multibuffer(
15622                excerpt_buffer,
15623                Some(workspace.project().clone()),
15624                window,
15625                cx,
15626            )
15627        });
15628        editor.update(cx, |editor, cx| {
15629            match multibuffer_selection_mode {
15630                MultibufferSelectionMode::First => {
15631                    if let Some(first_range) = ranges.first() {
15632                        editor.change_selections(None, window, cx, |selections| {
15633                            selections.clear_disjoint();
15634                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15635                        });
15636                    }
15637                    editor.highlight_background::<Self>(
15638                        &ranges,
15639                        |theme| theme.colors().editor_highlighted_line_background,
15640                        cx,
15641                    );
15642                }
15643                MultibufferSelectionMode::All => {
15644                    editor.change_selections(None, window, cx, |selections| {
15645                        selections.clear_disjoint();
15646                        selections.select_anchor_ranges(ranges);
15647                    });
15648                }
15649            }
15650            editor.register_buffers_with_language_servers(cx);
15651        });
15652
15653        let item = Box::new(editor);
15654        let item_id = item.item_id();
15655
15656        if split {
15657            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15658        } else {
15659            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15660                let (preview_item_id, preview_item_idx) =
15661                    workspace.active_pane().read_with(cx, |pane, _| {
15662                        (pane.preview_item_id(), pane.preview_item_idx())
15663                    });
15664
15665                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15666
15667                if let Some(preview_item_id) = preview_item_id {
15668                    workspace.active_pane().update(cx, |pane, cx| {
15669                        pane.remove_item(preview_item_id, false, false, window, cx);
15670                    });
15671                }
15672            } else {
15673                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15674            }
15675        }
15676        workspace.active_pane().update(cx, |pane, cx| {
15677            pane.set_preview_item_id(Some(item_id), cx);
15678        });
15679    }
15680
15681    pub fn rename(
15682        &mut self,
15683        _: &Rename,
15684        window: &mut Window,
15685        cx: &mut Context<Self>,
15686    ) -> Option<Task<Result<()>>> {
15687        use language::ToOffset as _;
15688
15689        let provider = self.semantics_provider.clone()?;
15690        let selection = self.selections.newest_anchor().clone();
15691        let (cursor_buffer, cursor_buffer_position) = self
15692            .buffer
15693            .read(cx)
15694            .text_anchor_for_position(selection.head(), cx)?;
15695        let (tail_buffer, cursor_buffer_position_end) = self
15696            .buffer
15697            .read(cx)
15698            .text_anchor_for_position(selection.tail(), cx)?;
15699        if tail_buffer != cursor_buffer {
15700            return None;
15701        }
15702
15703        let snapshot = cursor_buffer.read(cx).snapshot();
15704        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15705        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15706        let prepare_rename = provider
15707            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15708            .unwrap_or_else(|| Task::ready(Ok(None)));
15709        drop(snapshot);
15710
15711        Some(cx.spawn_in(window, async move |this, cx| {
15712            let rename_range = if let Some(range) = prepare_rename.await? {
15713                Some(range)
15714            } else {
15715                this.update(cx, |this, cx| {
15716                    let buffer = this.buffer.read(cx).snapshot(cx);
15717                    let mut buffer_highlights = this
15718                        .document_highlights_for_position(selection.head(), &buffer)
15719                        .filter(|highlight| {
15720                            highlight.start.excerpt_id == selection.head().excerpt_id
15721                                && highlight.end.excerpt_id == selection.head().excerpt_id
15722                        });
15723                    buffer_highlights
15724                        .next()
15725                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15726                })?
15727            };
15728            if let Some(rename_range) = rename_range {
15729                this.update_in(cx, |this, window, cx| {
15730                    let snapshot = cursor_buffer.read(cx).snapshot();
15731                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15732                    let cursor_offset_in_rename_range =
15733                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15734                    let cursor_offset_in_rename_range_end =
15735                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15736
15737                    this.take_rename(false, window, cx);
15738                    let buffer = this.buffer.read(cx).read(cx);
15739                    let cursor_offset = selection.head().to_offset(&buffer);
15740                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15741                    let rename_end = rename_start + rename_buffer_range.len();
15742                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15743                    let mut old_highlight_id = None;
15744                    let old_name: Arc<str> = buffer
15745                        .chunks(rename_start..rename_end, true)
15746                        .map(|chunk| {
15747                            if old_highlight_id.is_none() {
15748                                old_highlight_id = chunk.syntax_highlight_id;
15749                            }
15750                            chunk.text
15751                        })
15752                        .collect::<String>()
15753                        .into();
15754
15755                    drop(buffer);
15756
15757                    // Position the selection in the rename editor so that it matches the current selection.
15758                    this.show_local_selections = false;
15759                    let rename_editor = cx.new(|cx| {
15760                        let mut editor = Editor::single_line(window, cx);
15761                        editor.buffer.update(cx, |buffer, cx| {
15762                            buffer.edit([(0..0, old_name.clone())], None, cx)
15763                        });
15764                        let rename_selection_range = match cursor_offset_in_rename_range
15765                            .cmp(&cursor_offset_in_rename_range_end)
15766                        {
15767                            Ordering::Equal => {
15768                                editor.select_all(&SelectAll, window, cx);
15769                                return editor;
15770                            }
15771                            Ordering::Less => {
15772                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15773                            }
15774                            Ordering::Greater => {
15775                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15776                            }
15777                        };
15778                        if rename_selection_range.end > old_name.len() {
15779                            editor.select_all(&SelectAll, window, cx);
15780                        } else {
15781                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15782                                s.select_ranges([rename_selection_range]);
15783                            });
15784                        }
15785                        editor
15786                    });
15787                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15788                        if e == &EditorEvent::Focused {
15789                            cx.emit(EditorEvent::FocusedIn)
15790                        }
15791                    })
15792                    .detach();
15793
15794                    let write_highlights =
15795                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15796                    let read_highlights =
15797                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15798                    let ranges = write_highlights
15799                        .iter()
15800                        .flat_map(|(_, ranges)| ranges.iter())
15801                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15802                        .cloned()
15803                        .collect();
15804
15805                    this.highlight_text::<Rename>(
15806                        ranges,
15807                        HighlightStyle {
15808                            fade_out: Some(0.6),
15809                            ..Default::default()
15810                        },
15811                        cx,
15812                    );
15813                    let rename_focus_handle = rename_editor.focus_handle(cx);
15814                    window.focus(&rename_focus_handle);
15815                    let block_id = this.insert_blocks(
15816                        [BlockProperties {
15817                            style: BlockStyle::Flex,
15818                            placement: BlockPlacement::Below(range.start),
15819                            height: Some(1),
15820                            render: Arc::new({
15821                                let rename_editor = rename_editor.clone();
15822                                move |cx: &mut BlockContext| {
15823                                    let mut text_style = cx.editor_style.text.clone();
15824                                    if let Some(highlight_style) = old_highlight_id
15825                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15826                                    {
15827                                        text_style = text_style.highlight(highlight_style);
15828                                    }
15829                                    div()
15830                                        .block_mouse_except_scroll()
15831                                        .pl(cx.anchor_x)
15832                                        .child(EditorElement::new(
15833                                            &rename_editor,
15834                                            EditorStyle {
15835                                                background: cx.theme().system().transparent,
15836                                                local_player: cx.editor_style.local_player,
15837                                                text: text_style,
15838                                                scrollbar_width: cx.editor_style.scrollbar_width,
15839                                                syntax: cx.editor_style.syntax.clone(),
15840                                                status: cx.editor_style.status.clone(),
15841                                                inlay_hints_style: HighlightStyle {
15842                                                    font_weight: Some(FontWeight::BOLD),
15843                                                    ..make_inlay_hints_style(cx.app)
15844                                                },
15845                                                inline_completion_styles: make_suggestion_styles(
15846                                                    cx.app,
15847                                                ),
15848                                                ..EditorStyle::default()
15849                                            },
15850                                        ))
15851                                        .into_any_element()
15852                                }
15853                            }),
15854                            priority: 0,
15855                            render_in_minimap: true,
15856                        }],
15857                        Some(Autoscroll::fit()),
15858                        cx,
15859                    )[0];
15860                    this.pending_rename = Some(RenameState {
15861                        range,
15862                        old_name,
15863                        editor: rename_editor,
15864                        block_id,
15865                    });
15866                })?;
15867            }
15868
15869            Ok(())
15870        }))
15871    }
15872
15873    pub fn confirm_rename(
15874        &mut self,
15875        _: &ConfirmRename,
15876        window: &mut Window,
15877        cx: &mut Context<Self>,
15878    ) -> Option<Task<Result<()>>> {
15879        let rename = self.take_rename(false, window, cx)?;
15880        let workspace = self.workspace()?.downgrade();
15881        let (buffer, start) = self
15882            .buffer
15883            .read(cx)
15884            .text_anchor_for_position(rename.range.start, cx)?;
15885        let (end_buffer, _) = self
15886            .buffer
15887            .read(cx)
15888            .text_anchor_for_position(rename.range.end, cx)?;
15889        if buffer != end_buffer {
15890            return None;
15891        }
15892
15893        let old_name = rename.old_name;
15894        let new_name = rename.editor.read(cx).text(cx);
15895
15896        let rename = self.semantics_provider.as_ref()?.perform_rename(
15897            &buffer,
15898            start,
15899            new_name.clone(),
15900            cx,
15901        )?;
15902
15903        Some(cx.spawn_in(window, async move |editor, cx| {
15904            let project_transaction = rename.await?;
15905            Self::open_project_transaction(
15906                &editor,
15907                workspace,
15908                project_transaction,
15909                format!("Rename: {}{}", old_name, new_name),
15910                cx,
15911            )
15912            .await?;
15913
15914            editor.update(cx, |editor, cx| {
15915                editor.refresh_document_highlights(cx);
15916            })?;
15917            Ok(())
15918        }))
15919    }
15920
15921    fn take_rename(
15922        &mut self,
15923        moving_cursor: bool,
15924        window: &mut Window,
15925        cx: &mut Context<Self>,
15926    ) -> Option<RenameState> {
15927        let rename = self.pending_rename.take()?;
15928        if rename.editor.focus_handle(cx).is_focused(window) {
15929            window.focus(&self.focus_handle);
15930        }
15931
15932        self.remove_blocks(
15933            [rename.block_id].into_iter().collect(),
15934            Some(Autoscroll::fit()),
15935            cx,
15936        );
15937        self.clear_highlights::<Rename>(cx);
15938        self.show_local_selections = true;
15939
15940        if moving_cursor {
15941            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15942                editor.selections.newest::<usize>(cx).head()
15943            });
15944
15945            // Update the selection to match the position of the selection inside
15946            // the rename editor.
15947            let snapshot = self.buffer.read(cx).read(cx);
15948            let rename_range = rename.range.to_offset(&snapshot);
15949            let cursor_in_editor = snapshot
15950                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15951                .min(rename_range.end);
15952            drop(snapshot);
15953
15954            self.change_selections(None, window, cx, |s| {
15955                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15956            });
15957        } else {
15958            self.refresh_document_highlights(cx);
15959        }
15960
15961        Some(rename)
15962    }
15963
15964    pub fn pending_rename(&self) -> Option<&RenameState> {
15965        self.pending_rename.as_ref()
15966    }
15967
15968    fn format(
15969        &mut self,
15970        _: &Format,
15971        window: &mut Window,
15972        cx: &mut Context<Self>,
15973    ) -> Option<Task<Result<()>>> {
15974        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15975
15976        let project = match &self.project {
15977            Some(project) => project.clone(),
15978            None => return None,
15979        };
15980
15981        Some(self.perform_format(
15982            project,
15983            FormatTrigger::Manual,
15984            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15985            window,
15986            cx,
15987        ))
15988    }
15989
15990    fn format_selections(
15991        &mut self,
15992        _: &FormatSelections,
15993        window: &mut Window,
15994        cx: &mut Context<Self>,
15995    ) -> Option<Task<Result<()>>> {
15996        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15997
15998        let project = match &self.project {
15999            Some(project) => project.clone(),
16000            None => return None,
16001        };
16002
16003        let ranges = self
16004            .selections
16005            .all_adjusted(cx)
16006            .into_iter()
16007            .map(|selection| selection.range())
16008            .collect_vec();
16009
16010        Some(self.perform_format(
16011            project,
16012            FormatTrigger::Manual,
16013            FormatTarget::Ranges(ranges),
16014            window,
16015            cx,
16016        ))
16017    }
16018
16019    fn perform_format(
16020        &mut self,
16021        project: Entity<Project>,
16022        trigger: FormatTrigger,
16023        target: FormatTarget,
16024        window: &mut Window,
16025        cx: &mut Context<Self>,
16026    ) -> Task<Result<()>> {
16027        let buffer = self.buffer.clone();
16028        let (buffers, target) = match target {
16029            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16030            FormatTarget::Ranges(selection_ranges) => {
16031                let multi_buffer = buffer.read(cx);
16032                let snapshot = multi_buffer.read(cx);
16033                let mut buffers = HashSet::default();
16034                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16035                    BTreeMap::new();
16036                for selection_range in selection_ranges {
16037                    for (buffer, buffer_range, _) in
16038                        snapshot.range_to_buffer_ranges(selection_range)
16039                    {
16040                        let buffer_id = buffer.remote_id();
16041                        let start = buffer.anchor_before(buffer_range.start);
16042                        let end = buffer.anchor_after(buffer_range.end);
16043                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16044                        buffer_id_to_ranges
16045                            .entry(buffer_id)
16046                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16047                            .or_insert_with(|| vec![start..end]);
16048                    }
16049                }
16050                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16051            }
16052        };
16053
16054        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16055        let selections_prev = transaction_id_prev
16056            .and_then(|transaction_id_prev| {
16057                // default to selections as they were after the last edit, if we have them,
16058                // instead of how they are now.
16059                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16060                // will take you back to where you made the last edit, instead of staying where you scrolled
16061                self.selection_history
16062                    .transaction(transaction_id_prev)
16063                    .map(|t| t.0.clone())
16064            })
16065            .unwrap_or_else(|| {
16066                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16067                self.selections.disjoint_anchors()
16068            });
16069
16070        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16071        let format = project.update(cx, |project, cx| {
16072            project.format(buffers, target, true, trigger, cx)
16073        });
16074
16075        cx.spawn_in(window, async move |editor, cx| {
16076            let transaction = futures::select_biased! {
16077                transaction = format.log_err().fuse() => transaction,
16078                () = timeout => {
16079                    log::warn!("timed out waiting for formatting");
16080                    None
16081                }
16082            };
16083
16084            buffer
16085                .update(cx, |buffer, cx| {
16086                    if let Some(transaction) = transaction {
16087                        if !buffer.is_singleton() {
16088                            buffer.push_transaction(&transaction.0, cx);
16089                        }
16090                    }
16091                    cx.notify();
16092                })
16093                .ok();
16094
16095            if let Some(transaction_id_now) =
16096                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16097            {
16098                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16099                if has_new_transaction {
16100                    _ = editor.update(cx, |editor, _| {
16101                        editor
16102                            .selection_history
16103                            .insert_transaction(transaction_id_now, selections_prev);
16104                    });
16105                }
16106            }
16107
16108            Ok(())
16109        })
16110    }
16111
16112    fn organize_imports(
16113        &mut self,
16114        _: &OrganizeImports,
16115        window: &mut Window,
16116        cx: &mut Context<Self>,
16117    ) -> Option<Task<Result<()>>> {
16118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16119        let project = match &self.project {
16120            Some(project) => project.clone(),
16121            None => return None,
16122        };
16123        Some(self.perform_code_action_kind(
16124            project,
16125            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16126            window,
16127            cx,
16128        ))
16129    }
16130
16131    fn perform_code_action_kind(
16132        &mut self,
16133        project: Entity<Project>,
16134        kind: CodeActionKind,
16135        window: &mut Window,
16136        cx: &mut Context<Self>,
16137    ) -> Task<Result<()>> {
16138        let buffer = self.buffer.clone();
16139        let buffers = buffer.read(cx).all_buffers();
16140        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16141        let apply_action = project.update(cx, |project, cx| {
16142            project.apply_code_action_kind(buffers, kind, true, cx)
16143        });
16144        cx.spawn_in(window, async move |_, cx| {
16145            let transaction = futures::select_biased! {
16146                () = timeout => {
16147                    log::warn!("timed out waiting for executing code action");
16148                    None
16149                }
16150                transaction = apply_action.log_err().fuse() => transaction,
16151            };
16152            buffer
16153                .update(cx, |buffer, cx| {
16154                    // check if we need this
16155                    if let Some(transaction) = transaction {
16156                        if !buffer.is_singleton() {
16157                            buffer.push_transaction(&transaction.0, cx);
16158                        }
16159                    }
16160                    cx.notify();
16161                })
16162                .ok();
16163            Ok(())
16164        })
16165    }
16166
16167    fn restart_language_server(
16168        &mut self,
16169        _: &RestartLanguageServer,
16170        _: &mut Window,
16171        cx: &mut Context<Self>,
16172    ) {
16173        if let Some(project) = self.project.clone() {
16174            self.buffer.update(cx, |multi_buffer, cx| {
16175                project.update(cx, |project, cx| {
16176                    project.restart_language_servers_for_buffers(
16177                        multi_buffer.all_buffers().into_iter().collect(),
16178                        cx,
16179                    );
16180                });
16181            })
16182        }
16183    }
16184
16185    fn stop_language_server(
16186        &mut self,
16187        _: &StopLanguageServer,
16188        _: &mut Window,
16189        cx: &mut Context<Self>,
16190    ) {
16191        if let Some(project) = self.project.clone() {
16192            self.buffer.update(cx, |multi_buffer, cx| {
16193                project.update(cx, |project, cx| {
16194                    project.stop_language_servers_for_buffers(
16195                        multi_buffer.all_buffers().into_iter().collect(),
16196                        cx,
16197                    );
16198                    cx.emit(project::Event::RefreshInlayHints);
16199                });
16200            });
16201        }
16202    }
16203
16204    fn cancel_language_server_work(
16205        workspace: &mut Workspace,
16206        _: &actions::CancelLanguageServerWork,
16207        _: &mut Window,
16208        cx: &mut Context<Workspace>,
16209    ) {
16210        let project = workspace.project();
16211        let buffers = workspace
16212            .active_item(cx)
16213            .and_then(|item| item.act_as::<Editor>(cx))
16214            .map_or(HashSet::default(), |editor| {
16215                editor.read(cx).buffer.read(cx).all_buffers()
16216            });
16217        project.update(cx, |project, cx| {
16218            project.cancel_language_server_work_for_buffers(buffers, cx);
16219        });
16220    }
16221
16222    fn show_character_palette(
16223        &mut self,
16224        _: &ShowCharacterPalette,
16225        window: &mut Window,
16226        _: &mut Context<Self>,
16227    ) {
16228        window.show_character_palette();
16229    }
16230
16231    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16232        if !self.diagnostics_enabled() {
16233            return;
16234        }
16235
16236        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16237            let buffer = self.buffer.read(cx).snapshot(cx);
16238            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16239            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16240            let is_valid = buffer
16241                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16242                .any(|entry| {
16243                    entry.diagnostic.is_primary
16244                        && !entry.range.is_empty()
16245                        && entry.range.start == primary_range_start
16246                        && entry.diagnostic.message == active_diagnostics.active_message
16247                });
16248
16249            if !is_valid {
16250                self.dismiss_diagnostics(cx);
16251            }
16252        }
16253    }
16254
16255    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16256        match &self.active_diagnostics {
16257            ActiveDiagnostic::Group(group) => Some(group),
16258            _ => None,
16259        }
16260    }
16261
16262    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16263        if !self.diagnostics_enabled() {
16264            return;
16265        }
16266        self.dismiss_diagnostics(cx);
16267        self.active_diagnostics = ActiveDiagnostic::All;
16268    }
16269
16270    fn activate_diagnostics(
16271        &mut self,
16272        buffer_id: BufferId,
16273        diagnostic: DiagnosticEntry<usize>,
16274        window: &mut Window,
16275        cx: &mut Context<Self>,
16276    ) {
16277        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16278            return;
16279        }
16280        self.dismiss_diagnostics(cx);
16281        let snapshot = self.snapshot(window, cx);
16282        let buffer = self.buffer.read(cx).snapshot(cx);
16283        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16284            return;
16285        };
16286
16287        let diagnostic_group = buffer
16288            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16289            .collect::<Vec<_>>();
16290
16291        let blocks =
16292            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16293
16294        let blocks = self.display_map.update(cx, |display_map, cx| {
16295            display_map.insert_blocks(blocks, cx).into_iter().collect()
16296        });
16297        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16298            active_range: buffer.anchor_before(diagnostic.range.start)
16299                ..buffer.anchor_after(diagnostic.range.end),
16300            active_message: diagnostic.diagnostic.message.clone(),
16301            group_id: diagnostic.diagnostic.group_id,
16302            blocks,
16303        });
16304        cx.notify();
16305    }
16306
16307    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16308        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16309            return;
16310        };
16311
16312        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16313        if let ActiveDiagnostic::Group(group) = prev {
16314            self.display_map.update(cx, |display_map, cx| {
16315                display_map.remove_blocks(group.blocks, cx);
16316            });
16317            cx.notify();
16318        }
16319    }
16320
16321    /// Disable inline diagnostics rendering for this editor.
16322    pub fn disable_inline_diagnostics(&mut self) {
16323        self.inline_diagnostics_enabled = false;
16324        self.inline_diagnostics_update = Task::ready(());
16325        self.inline_diagnostics.clear();
16326    }
16327
16328    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16329        self.diagnostics_enabled = false;
16330        self.dismiss_diagnostics(cx);
16331        self.inline_diagnostics_update = Task::ready(());
16332        self.inline_diagnostics.clear();
16333    }
16334
16335    pub fn diagnostics_enabled(&self) -> bool {
16336        self.diagnostics_enabled && self.mode.is_full()
16337    }
16338
16339    pub fn inline_diagnostics_enabled(&self) -> bool {
16340        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16341    }
16342
16343    pub fn show_inline_diagnostics(&self) -> bool {
16344        self.show_inline_diagnostics
16345    }
16346
16347    pub fn toggle_inline_diagnostics(
16348        &mut self,
16349        _: &ToggleInlineDiagnostics,
16350        window: &mut Window,
16351        cx: &mut Context<Editor>,
16352    ) {
16353        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16354        self.refresh_inline_diagnostics(false, window, cx);
16355    }
16356
16357    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16358        self.diagnostics_max_severity = severity;
16359        self.display_map.update(cx, |display_map, _| {
16360            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16361        });
16362    }
16363
16364    pub fn toggle_diagnostics(
16365        &mut self,
16366        _: &ToggleDiagnostics,
16367        window: &mut Window,
16368        cx: &mut Context<Editor>,
16369    ) {
16370        if !self.diagnostics_enabled() {
16371            return;
16372        }
16373
16374        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16375            EditorSettings::get_global(cx)
16376                .diagnostics_max_severity
16377                .filter(|severity| severity != &DiagnosticSeverity::Off)
16378                .unwrap_or(DiagnosticSeverity::Hint)
16379        } else {
16380            DiagnosticSeverity::Off
16381        };
16382        self.set_max_diagnostics_severity(new_severity, cx);
16383        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16384            self.active_diagnostics = ActiveDiagnostic::None;
16385            self.inline_diagnostics_update = Task::ready(());
16386            self.inline_diagnostics.clear();
16387        } else {
16388            self.refresh_inline_diagnostics(false, window, cx);
16389        }
16390
16391        cx.notify();
16392    }
16393
16394    pub fn toggle_minimap(
16395        &mut self,
16396        _: &ToggleMinimap,
16397        window: &mut Window,
16398        cx: &mut Context<Editor>,
16399    ) {
16400        if self.supports_minimap(cx) {
16401            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16402        }
16403    }
16404
16405    fn refresh_inline_diagnostics(
16406        &mut self,
16407        debounce: bool,
16408        window: &mut Window,
16409        cx: &mut Context<Self>,
16410    ) {
16411        let max_severity = ProjectSettings::get_global(cx)
16412            .diagnostics
16413            .inline
16414            .max_severity
16415            .unwrap_or(self.diagnostics_max_severity);
16416
16417        if !self.inline_diagnostics_enabled()
16418            || !self.show_inline_diagnostics
16419            || max_severity == DiagnosticSeverity::Off
16420        {
16421            self.inline_diagnostics_update = Task::ready(());
16422            self.inline_diagnostics.clear();
16423            return;
16424        }
16425
16426        let debounce_ms = ProjectSettings::get_global(cx)
16427            .diagnostics
16428            .inline
16429            .update_debounce_ms;
16430        let debounce = if debounce && debounce_ms > 0 {
16431            Some(Duration::from_millis(debounce_ms))
16432        } else {
16433            None
16434        };
16435        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16436            if let Some(debounce) = debounce {
16437                cx.background_executor().timer(debounce).await;
16438            }
16439            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16440                editor
16441                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16442                    .ok()
16443            }) else {
16444                return;
16445            };
16446
16447            let new_inline_diagnostics = cx
16448                .background_spawn(async move {
16449                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16450                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16451                        let message = diagnostic_entry
16452                            .diagnostic
16453                            .message
16454                            .split_once('\n')
16455                            .map(|(line, _)| line)
16456                            .map(SharedString::new)
16457                            .unwrap_or_else(|| {
16458                                SharedString::from(diagnostic_entry.diagnostic.message)
16459                            });
16460                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16461                        let (Ok(i) | Err(i)) = inline_diagnostics
16462                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16463                        inline_diagnostics.insert(
16464                            i,
16465                            (
16466                                start_anchor,
16467                                InlineDiagnostic {
16468                                    message,
16469                                    group_id: diagnostic_entry.diagnostic.group_id,
16470                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16471                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16472                                    severity: diagnostic_entry.diagnostic.severity,
16473                                },
16474                            ),
16475                        );
16476                    }
16477                    inline_diagnostics
16478                })
16479                .await;
16480
16481            editor
16482                .update(cx, |editor, cx| {
16483                    editor.inline_diagnostics = new_inline_diagnostics;
16484                    cx.notify();
16485                })
16486                .ok();
16487        });
16488    }
16489
16490    fn pull_diagnostics(
16491        &mut self,
16492        buffer_id: Option<BufferId>,
16493        window: &Window,
16494        cx: &mut Context<Self>,
16495    ) -> Option<()> {
16496        if !self.mode().is_full() {
16497            return None;
16498        }
16499        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16500            .diagnostics
16501            .lsp_pull_diagnostics;
16502        if !pull_diagnostics_settings.enabled {
16503            return None;
16504        }
16505        let project = self.project.as_ref()?.downgrade();
16506        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16507        let mut buffers = self.buffer.read(cx).all_buffers();
16508        if let Some(buffer_id) = buffer_id {
16509            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16510        }
16511
16512        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16513            cx.background_executor().timer(debounce).await;
16514
16515            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16516                buffers
16517                    .into_iter()
16518                    .filter_map(|buffer| {
16519                        project
16520                            .update(cx, |project, cx| {
16521                                project.lsp_store().update(cx, |lsp_store, cx| {
16522                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16523                                })
16524                            })
16525                            .ok()
16526                    })
16527                    .collect::<FuturesUnordered<_>>()
16528            }) else {
16529                return;
16530            };
16531
16532            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16533                match pull_task {
16534                    Ok(()) => {
16535                        if editor
16536                            .update_in(cx, |editor, window, cx| {
16537                                editor.update_diagnostics_state(window, cx);
16538                            })
16539                            .is_err()
16540                        {
16541                            return;
16542                        }
16543                    }
16544                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16545                }
16546            }
16547        });
16548
16549        Some(())
16550    }
16551
16552    pub fn set_selections_from_remote(
16553        &mut self,
16554        selections: Vec<Selection<Anchor>>,
16555        pending_selection: Option<Selection<Anchor>>,
16556        window: &mut Window,
16557        cx: &mut Context<Self>,
16558    ) {
16559        let old_cursor_position = self.selections.newest_anchor().head();
16560        self.selections.change_with(cx, |s| {
16561            s.select_anchors(selections);
16562            if let Some(pending_selection) = pending_selection {
16563                s.set_pending(pending_selection, SelectMode::Character);
16564            } else {
16565                s.clear_pending();
16566            }
16567        });
16568        self.selections_did_change(
16569            false,
16570            &old_cursor_position,
16571            SelectionEffects::default(),
16572            window,
16573            cx,
16574        );
16575    }
16576
16577    pub fn transact(
16578        &mut self,
16579        window: &mut Window,
16580        cx: &mut Context<Self>,
16581        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16582    ) -> Option<TransactionId> {
16583        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16584            this.start_transaction_at(Instant::now(), window, cx);
16585            update(this, window, cx);
16586            this.end_transaction_at(Instant::now(), cx)
16587        })
16588    }
16589
16590    pub fn start_transaction_at(
16591        &mut self,
16592        now: Instant,
16593        window: &mut Window,
16594        cx: &mut Context<Self>,
16595    ) {
16596        self.end_selection(window, cx);
16597        if let Some(tx_id) = self
16598            .buffer
16599            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16600        {
16601            self.selection_history
16602                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16603            cx.emit(EditorEvent::TransactionBegun {
16604                transaction_id: tx_id,
16605            })
16606        }
16607    }
16608
16609    pub fn end_transaction_at(
16610        &mut self,
16611        now: Instant,
16612        cx: &mut Context<Self>,
16613    ) -> Option<TransactionId> {
16614        if let Some(transaction_id) = self
16615            .buffer
16616            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16617        {
16618            if let Some((_, end_selections)) =
16619                self.selection_history.transaction_mut(transaction_id)
16620            {
16621                *end_selections = Some(self.selections.disjoint_anchors());
16622            } else {
16623                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16624            }
16625
16626            cx.emit(EditorEvent::Edited { transaction_id });
16627            Some(transaction_id)
16628        } else {
16629            None
16630        }
16631    }
16632
16633    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16634        if self.selection_mark_mode {
16635            self.change_selections(None, window, cx, |s| {
16636                s.move_with(|_, sel| {
16637                    sel.collapse_to(sel.head(), SelectionGoal::None);
16638                });
16639            })
16640        }
16641        self.selection_mark_mode = true;
16642        cx.notify();
16643    }
16644
16645    pub fn swap_selection_ends(
16646        &mut self,
16647        _: &actions::SwapSelectionEnds,
16648        window: &mut Window,
16649        cx: &mut Context<Self>,
16650    ) {
16651        self.change_selections(None, window, cx, |s| {
16652            s.move_with(|_, sel| {
16653                if sel.start != sel.end {
16654                    sel.reversed = !sel.reversed
16655                }
16656            });
16657        });
16658        self.request_autoscroll(Autoscroll::newest(), cx);
16659        cx.notify();
16660    }
16661
16662    pub fn toggle_fold(
16663        &mut self,
16664        _: &actions::ToggleFold,
16665        window: &mut Window,
16666        cx: &mut Context<Self>,
16667    ) {
16668        if self.is_singleton(cx) {
16669            let selection = self.selections.newest::<Point>(cx);
16670
16671            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16672            let range = if selection.is_empty() {
16673                let point = selection.head().to_display_point(&display_map);
16674                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16675                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16676                    .to_point(&display_map);
16677                start..end
16678            } else {
16679                selection.range()
16680            };
16681            if display_map.folds_in_range(range).next().is_some() {
16682                self.unfold_lines(&Default::default(), window, cx)
16683            } else {
16684                self.fold(&Default::default(), window, cx)
16685            }
16686        } else {
16687            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16688            let buffer_ids: HashSet<_> = self
16689                .selections
16690                .disjoint_anchor_ranges()
16691                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16692                .collect();
16693
16694            let should_unfold = buffer_ids
16695                .iter()
16696                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16697
16698            for buffer_id in buffer_ids {
16699                if should_unfold {
16700                    self.unfold_buffer(buffer_id, cx);
16701                } else {
16702                    self.fold_buffer(buffer_id, cx);
16703                }
16704            }
16705        }
16706    }
16707
16708    pub fn toggle_fold_recursive(
16709        &mut self,
16710        _: &actions::ToggleFoldRecursive,
16711        window: &mut Window,
16712        cx: &mut Context<Self>,
16713    ) {
16714        let selection = self.selections.newest::<Point>(cx);
16715
16716        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16717        let range = if selection.is_empty() {
16718            let point = selection.head().to_display_point(&display_map);
16719            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16720            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16721                .to_point(&display_map);
16722            start..end
16723        } else {
16724            selection.range()
16725        };
16726        if display_map.folds_in_range(range).next().is_some() {
16727            self.unfold_recursive(&Default::default(), window, cx)
16728        } else {
16729            self.fold_recursive(&Default::default(), window, cx)
16730        }
16731    }
16732
16733    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16734        if self.is_singleton(cx) {
16735            let mut to_fold = Vec::new();
16736            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16737            let selections = self.selections.all_adjusted(cx);
16738
16739            for selection in selections {
16740                let range = selection.range().sorted();
16741                let buffer_start_row = range.start.row;
16742
16743                if range.start.row != range.end.row {
16744                    let mut found = false;
16745                    let mut row = range.start.row;
16746                    while row <= range.end.row {
16747                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16748                        {
16749                            found = true;
16750                            row = crease.range().end.row + 1;
16751                            to_fold.push(crease);
16752                        } else {
16753                            row += 1
16754                        }
16755                    }
16756                    if found {
16757                        continue;
16758                    }
16759                }
16760
16761                for row in (0..=range.start.row).rev() {
16762                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16763                        if crease.range().end.row >= buffer_start_row {
16764                            to_fold.push(crease);
16765                            if row <= range.start.row {
16766                                break;
16767                            }
16768                        }
16769                    }
16770                }
16771            }
16772
16773            self.fold_creases(to_fold, true, window, cx);
16774        } else {
16775            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16776            let buffer_ids = self
16777                .selections
16778                .disjoint_anchor_ranges()
16779                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16780                .collect::<HashSet<_>>();
16781            for buffer_id in buffer_ids {
16782                self.fold_buffer(buffer_id, cx);
16783            }
16784        }
16785    }
16786
16787    fn fold_at_level(
16788        &mut self,
16789        fold_at: &FoldAtLevel,
16790        window: &mut Window,
16791        cx: &mut Context<Self>,
16792    ) {
16793        if !self.buffer.read(cx).is_singleton() {
16794            return;
16795        }
16796
16797        let fold_at_level = fold_at.0;
16798        let snapshot = self.buffer.read(cx).snapshot(cx);
16799        let mut to_fold = Vec::new();
16800        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16801
16802        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16803            while start_row < end_row {
16804                match self
16805                    .snapshot(window, cx)
16806                    .crease_for_buffer_row(MultiBufferRow(start_row))
16807                {
16808                    Some(crease) => {
16809                        let nested_start_row = crease.range().start.row + 1;
16810                        let nested_end_row = crease.range().end.row;
16811
16812                        if current_level < fold_at_level {
16813                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16814                        } else if current_level == fold_at_level {
16815                            to_fold.push(crease);
16816                        }
16817
16818                        start_row = nested_end_row + 1;
16819                    }
16820                    None => start_row += 1,
16821                }
16822            }
16823        }
16824
16825        self.fold_creases(to_fold, true, window, cx);
16826    }
16827
16828    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16829        if self.buffer.read(cx).is_singleton() {
16830            let mut fold_ranges = Vec::new();
16831            let snapshot = self.buffer.read(cx).snapshot(cx);
16832
16833            for row in 0..snapshot.max_row().0 {
16834                if let Some(foldable_range) = self
16835                    .snapshot(window, cx)
16836                    .crease_for_buffer_row(MultiBufferRow(row))
16837                {
16838                    fold_ranges.push(foldable_range);
16839                }
16840            }
16841
16842            self.fold_creases(fold_ranges, true, window, cx);
16843        } else {
16844            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16845                editor
16846                    .update_in(cx, |editor, _, cx| {
16847                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16848                            editor.fold_buffer(buffer_id, cx);
16849                        }
16850                    })
16851                    .ok();
16852            });
16853        }
16854    }
16855
16856    pub fn fold_function_bodies(
16857        &mut self,
16858        _: &actions::FoldFunctionBodies,
16859        window: &mut Window,
16860        cx: &mut Context<Self>,
16861    ) {
16862        let snapshot = self.buffer.read(cx).snapshot(cx);
16863
16864        let ranges = snapshot
16865            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16866            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16867            .collect::<Vec<_>>();
16868
16869        let creases = ranges
16870            .into_iter()
16871            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16872            .collect();
16873
16874        self.fold_creases(creases, true, window, cx);
16875    }
16876
16877    pub fn fold_recursive(
16878        &mut self,
16879        _: &actions::FoldRecursive,
16880        window: &mut Window,
16881        cx: &mut Context<Self>,
16882    ) {
16883        let mut to_fold = Vec::new();
16884        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16885        let selections = self.selections.all_adjusted(cx);
16886
16887        for selection in selections {
16888            let range = selection.range().sorted();
16889            let buffer_start_row = range.start.row;
16890
16891            if range.start.row != range.end.row {
16892                let mut found = false;
16893                for row in range.start.row..=range.end.row {
16894                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16895                        found = true;
16896                        to_fold.push(crease);
16897                    }
16898                }
16899                if found {
16900                    continue;
16901                }
16902            }
16903
16904            for row in (0..=range.start.row).rev() {
16905                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16906                    if crease.range().end.row >= buffer_start_row {
16907                        to_fold.push(crease);
16908                    } else {
16909                        break;
16910                    }
16911                }
16912            }
16913        }
16914
16915        self.fold_creases(to_fold, true, window, cx);
16916    }
16917
16918    pub fn fold_at(
16919        &mut self,
16920        buffer_row: MultiBufferRow,
16921        window: &mut Window,
16922        cx: &mut Context<Self>,
16923    ) {
16924        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16925
16926        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16927            let autoscroll = self
16928                .selections
16929                .all::<Point>(cx)
16930                .iter()
16931                .any(|selection| crease.range().overlaps(&selection.range()));
16932
16933            self.fold_creases(vec![crease], autoscroll, window, cx);
16934        }
16935    }
16936
16937    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16938        if self.is_singleton(cx) {
16939            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16940            let buffer = &display_map.buffer_snapshot;
16941            let selections = self.selections.all::<Point>(cx);
16942            let ranges = selections
16943                .iter()
16944                .map(|s| {
16945                    let range = s.display_range(&display_map).sorted();
16946                    let mut start = range.start.to_point(&display_map);
16947                    let mut end = range.end.to_point(&display_map);
16948                    start.column = 0;
16949                    end.column = buffer.line_len(MultiBufferRow(end.row));
16950                    start..end
16951                })
16952                .collect::<Vec<_>>();
16953
16954            self.unfold_ranges(&ranges, true, true, cx);
16955        } else {
16956            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16957            let buffer_ids = self
16958                .selections
16959                .disjoint_anchor_ranges()
16960                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16961                .collect::<HashSet<_>>();
16962            for buffer_id in buffer_ids {
16963                self.unfold_buffer(buffer_id, cx);
16964            }
16965        }
16966    }
16967
16968    pub fn unfold_recursive(
16969        &mut self,
16970        _: &UnfoldRecursive,
16971        _window: &mut Window,
16972        cx: &mut Context<Self>,
16973    ) {
16974        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16975        let selections = self.selections.all::<Point>(cx);
16976        let ranges = selections
16977            .iter()
16978            .map(|s| {
16979                let mut range = s.display_range(&display_map).sorted();
16980                *range.start.column_mut() = 0;
16981                *range.end.column_mut() = display_map.line_len(range.end.row());
16982                let start = range.start.to_point(&display_map);
16983                let end = range.end.to_point(&display_map);
16984                start..end
16985            })
16986            .collect::<Vec<_>>();
16987
16988        self.unfold_ranges(&ranges, true, true, cx);
16989    }
16990
16991    pub fn unfold_at(
16992        &mut self,
16993        buffer_row: MultiBufferRow,
16994        _window: &mut Window,
16995        cx: &mut Context<Self>,
16996    ) {
16997        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16998
16999        let intersection_range = Point::new(buffer_row.0, 0)
17000            ..Point::new(
17001                buffer_row.0,
17002                display_map.buffer_snapshot.line_len(buffer_row),
17003            );
17004
17005        let autoscroll = self
17006            .selections
17007            .all::<Point>(cx)
17008            .iter()
17009            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17010
17011        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17012    }
17013
17014    pub fn unfold_all(
17015        &mut self,
17016        _: &actions::UnfoldAll,
17017        _window: &mut Window,
17018        cx: &mut Context<Self>,
17019    ) {
17020        if self.buffer.read(cx).is_singleton() {
17021            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17022            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17023        } else {
17024            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17025                editor
17026                    .update(cx, |editor, cx| {
17027                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17028                            editor.unfold_buffer(buffer_id, cx);
17029                        }
17030                    })
17031                    .ok();
17032            });
17033        }
17034    }
17035
17036    pub fn fold_selected_ranges(
17037        &mut self,
17038        _: &FoldSelectedRanges,
17039        window: &mut Window,
17040        cx: &mut Context<Self>,
17041    ) {
17042        let selections = self.selections.all_adjusted(cx);
17043        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17044        let ranges = selections
17045            .into_iter()
17046            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17047            .collect::<Vec<_>>();
17048        self.fold_creases(ranges, true, window, cx);
17049    }
17050
17051    pub fn fold_ranges<T: ToOffset + Clone>(
17052        &mut self,
17053        ranges: Vec<Range<T>>,
17054        auto_scroll: bool,
17055        window: &mut Window,
17056        cx: &mut Context<Self>,
17057    ) {
17058        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17059        let ranges = ranges
17060            .into_iter()
17061            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17062            .collect::<Vec<_>>();
17063        self.fold_creases(ranges, auto_scroll, window, cx);
17064    }
17065
17066    pub fn fold_creases<T: ToOffset + Clone>(
17067        &mut self,
17068        creases: Vec<Crease<T>>,
17069        auto_scroll: bool,
17070        _window: &mut Window,
17071        cx: &mut Context<Self>,
17072    ) {
17073        if creases.is_empty() {
17074            return;
17075        }
17076
17077        let mut buffers_affected = HashSet::default();
17078        let multi_buffer = self.buffer().read(cx);
17079        for crease in &creases {
17080            if let Some((_, buffer, _)) =
17081                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
17082            {
17083                buffers_affected.insert(buffer.read(cx).remote_id());
17084            };
17085        }
17086
17087        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17088
17089        if auto_scroll {
17090            self.request_autoscroll(Autoscroll::fit(), cx);
17091        }
17092
17093        cx.notify();
17094
17095        self.scrollbar_marker_state.dirty = true;
17096        self.folds_did_change(cx);
17097    }
17098
17099    /// Removes any folds whose ranges intersect any of the given ranges.
17100    pub fn unfold_ranges<T: ToOffset + Clone>(
17101        &mut self,
17102        ranges: &[Range<T>],
17103        inclusive: bool,
17104        auto_scroll: bool,
17105        cx: &mut Context<Self>,
17106    ) {
17107        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17108            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17109        });
17110        self.folds_did_change(cx);
17111    }
17112
17113    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17114        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17115            return;
17116        }
17117        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17118        self.display_map.update(cx, |display_map, cx| {
17119            display_map.fold_buffers([buffer_id], cx)
17120        });
17121        cx.emit(EditorEvent::BufferFoldToggled {
17122            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17123            folded: true,
17124        });
17125        cx.notify();
17126    }
17127
17128    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17129        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17130            return;
17131        }
17132        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17133        self.display_map.update(cx, |display_map, cx| {
17134            display_map.unfold_buffers([buffer_id], cx);
17135        });
17136        cx.emit(EditorEvent::BufferFoldToggled {
17137            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17138            folded: false,
17139        });
17140        cx.notify();
17141    }
17142
17143    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17144        self.display_map.read(cx).is_buffer_folded(buffer)
17145    }
17146
17147    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17148        self.display_map.read(cx).folded_buffers()
17149    }
17150
17151    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17152        self.display_map.update(cx, |display_map, cx| {
17153            display_map.disable_header_for_buffer(buffer_id, cx);
17154        });
17155        cx.notify();
17156    }
17157
17158    /// Removes any folds with the given ranges.
17159    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17160        &mut self,
17161        ranges: &[Range<T>],
17162        type_id: TypeId,
17163        auto_scroll: bool,
17164        cx: &mut Context<Self>,
17165    ) {
17166        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17167            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17168        });
17169        self.folds_did_change(cx);
17170    }
17171
17172    fn remove_folds_with<T: ToOffset + Clone>(
17173        &mut self,
17174        ranges: &[Range<T>],
17175        auto_scroll: bool,
17176        cx: &mut Context<Self>,
17177        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17178    ) {
17179        if ranges.is_empty() {
17180            return;
17181        }
17182
17183        let mut buffers_affected = HashSet::default();
17184        let multi_buffer = self.buffer().read(cx);
17185        for range in ranges {
17186            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17187                buffers_affected.insert(buffer.read(cx).remote_id());
17188            };
17189        }
17190
17191        self.display_map.update(cx, update);
17192
17193        if auto_scroll {
17194            self.request_autoscroll(Autoscroll::fit(), cx);
17195        }
17196
17197        cx.notify();
17198        self.scrollbar_marker_state.dirty = true;
17199        self.active_indent_guides_state.dirty = true;
17200    }
17201
17202    pub fn update_fold_widths(
17203        &mut self,
17204        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
17205        cx: &mut Context<Self>,
17206    ) -> bool {
17207        self.display_map
17208            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17209    }
17210
17211    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17212        self.display_map.read(cx).fold_placeholder.clone()
17213    }
17214
17215    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17216        self.buffer.update(cx, |buffer, cx| {
17217            buffer.set_all_diff_hunks_expanded(cx);
17218        });
17219    }
17220
17221    pub fn expand_all_diff_hunks(
17222        &mut self,
17223        _: &ExpandAllDiffHunks,
17224        _window: &mut Window,
17225        cx: &mut Context<Self>,
17226    ) {
17227        self.buffer.update(cx, |buffer, cx| {
17228            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17229        });
17230    }
17231
17232    pub fn toggle_selected_diff_hunks(
17233        &mut self,
17234        _: &ToggleSelectedDiffHunks,
17235        _window: &mut Window,
17236        cx: &mut Context<Self>,
17237    ) {
17238        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17239        self.toggle_diff_hunks_in_ranges(ranges, cx);
17240    }
17241
17242    pub fn diff_hunks_in_ranges<'a>(
17243        &'a self,
17244        ranges: &'a [Range<Anchor>],
17245        buffer: &'a MultiBufferSnapshot,
17246    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17247        ranges.iter().flat_map(move |range| {
17248            let end_excerpt_id = range.end.excerpt_id;
17249            let range = range.to_point(buffer);
17250            let mut peek_end = range.end;
17251            if range.end.row < buffer.max_row().0 {
17252                peek_end = Point::new(range.end.row + 1, 0);
17253            }
17254            buffer
17255                .diff_hunks_in_range(range.start..peek_end)
17256                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17257        })
17258    }
17259
17260    pub fn has_stageable_diff_hunks_in_ranges(
17261        &self,
17262        ranges: &[Range<Anchor>],
17263        snapshot: &MultiBufferSnapshot,
17264    ) -> bool {
17265        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17266        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17267    }
17268
17269    pub fn toggle_staged_selected_diff_hunks(
17270        &mut self,
17271        _: &::git::ToggleStaged,
17272        _: &mut Window,
17273        cx: &mut Context<Self>,
17274    ) {
17275        let snapshot = self.buffer.read(cx).snapshot(cx);
17276        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17277        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17278        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17279    }
17280
17281    pub fn set_render_diff_hunk_controls(
17282        &mut self,
17283        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17284        cx: &mut Context<Self>,
17285    ) {
17286        self.render_diff_hunk_controls = render_diff_hunk_controls;
17287        cx.notify();
17288    }
17289
17290    pub fn stage_and_next(
17291        &mut self,
17292        _: &::git::StageAndNext,
17293        window: &mut Window,
17294        cx: &mut Context<Self>,
17295    ) {
17296        self.do_stage_or_unstage_and_next(true, window, cx);
17297    }
17298
17299    pub fn unstage_and_next(
17300        &mut self,
17301        _: &::git::UnstageAndNext,
17302        window: &mut Window,
17303        cx: &mut Context<Self>,
17304    ) {
17305        self.do_stage_or_unstage_and_next(false, window, cx);
17306    }
17307
17308    pub fn stage_or_unstage_diff_hunks(
17309        &mut self,
17310        stage: bool,
17311        ranges: Vec<Range<Anchor>>,
17312        cx: &mut Context<Self>,
17313    ) {
17314        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17315        cx.spawn(async move |this, cx| {
17316            task.await?;
17317            this.update(cx, |this, cx| {
17318                let snapshot = this.buffer.read(cx).snapshot(cx);
17319                let chunk_by = this
17320                    .diff_hunks_in_ranges(&ranges, &snapshot)
17321                    .chunk_by(|hunk| hunk.buffer_id);
17322                for (buffer_id, hunks) in &chunk_by {
17323                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17324                }
17325            })
17326        })
17327        .detach_and_log_err(cx);
17328    }
17329
17330    fn save_buffers_for_ranges_if_needed(
17331        &mut self,
17332        ranges: &[Range<Anchor>],
17333        cx: &mut Context<Editor>,
17334    ) -> Task<Result<()>> {
17335        let multibuffer = self.buffer.read(cx);
17336        let snapshot = multibuffer.read(cx);
17337        let buffer_ids: HashSet<_> = ranges
17338            .iter()
17339            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17340            .collect();
17341        drop(snapshot);
17342
17343        let mut buffers = HashSet::default();
17344        for buffer_id in buffer_ids {
17345            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17346                let buffer = buffer_entity.read(cx);
17347                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17348                {
17349                    buffers.insert(buffer_entity);
17350                }
17351            }
17352        }
17353
17354        if let Some(project) = &self.project {
17355            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17356        } else {
17357            Task::ready(Ok(()))
17358        }
17359    }
17360
17361    fn do_stage_or_unstage_and_next(
17362        &mut self,
17363        stage: bool,
17364        window: &mut Window,
17365        cx: &mut Context<Self>,
17366    ) {
17367        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17368
17369        if ranges.iter().any(|range| range.start != range.end) {
17370            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17371            return;
17372        }
17373
17374        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17375        let snapshot = self.snapshot(window, cx);
17376        let position = self.selections.newest::<Point>(cx).head();
17377        let mut row = snapshot
17378            .buffer_snapshot
17379            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17380            .find(|hunk| hunk.row_range.start.0 > position.row)
17381            .map(|hunk| hunk.row_range.start);
17382
17383        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17384        // Outside of the project diff editor, wrap around to the beginning.
17385        if !all_diff_hunks_expanded {
17386            row = row.or_else(|| {
17387                snapshot
17388                    .buffer_snapshot
17389                    .diff_hunks_in_range(Point::zero()..position)
17390                    .find(|hunk| hunk.row_range.end.0 < position.row)
17391                    .map(|hunk| hunk.row_range.start)
17392            });
17393        }
17394
17395        if let Some(row) = row {
17396            let destination = Point::new(row.0, 0);
17397            let autoscroll = Autoscroll::center();
17398
17399            self.unfold_ranges(&[destination..destination], false, false, cx);
17400            self.change_selections(Some(autoscroll), window, cx, |s| {
17401                s.select_ranges([destination..destination]);
17402            });
17403        }
17404    }
17405
17406    fn do_stage_or_unstage(
17407        &self,
17408        stage: bool,
17409        buffer_id: BufferId,
17410        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17411        cx: &mut App,
17412    ) -> Option<()> {
17413        let project = self.project.as_ref()?;
17414        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17415        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17416        let buffer_snapshot = buffer.read(cx).snapshot();
17417        let file_exists = buffer_snapshot
17418            .file()
17419            .is_some_and(|file| file.disk_state().exists());
17420        diff.update(cx, |diff, cx| {
17421            diff.stage_or_unstage_hunks(
17422                stage,
17423                &hunks
17424                    .map(|hunk| buffer_diff::DiffHunk {
17425                        buffer_range: hunk.buffer_range,
17426                        diff_base_byte_range: hunk.diff_base_byte_range,
17427                        secondary_status: hunk.secondary_status,
17428                        range: Point::zero()..Point::zero(), // unused
17429                    })
17430                    .collect::<Vec<_>>(),
17431                &buffer_snapshot,
17432                file_exists,
17433                cx,
17434            )
17435        });
17436        None
17437    }
17438
17439    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17440        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17441        self.buffer
17442            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17443    }
17444
17445    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17446        self.buffer.update(cx, |buffer, cx| {
17447            let ranges = vec![Anchor::min()..Anchor::max()];
17448            if !buffer.all_diff_hunks_expanded()
17449                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17450            {
17451                buffer.collapse_diff_hunks(ranges, cx);
17452                true
17453            } else {
17454                false
17455            }
17456        })
17457    }
17458
17459    fn toggle_diff_hunks_in_ranges(
17460        &mut self,
17461        ranges: Vec<Range<Anchor>>,
17462        cx: &mut Context<Editor>,
17463    ) {
17464        self.buffer.update(cx, |buffer, cx| {
17465            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17466            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17467        })
17468    }
17469
17470    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17471        self.buffer.update(cx, |buffer, cx| {
17472            let snapshot = buffer.snapshot(cx);
17473            let excerpt_id = range.end.excerpt_id;
17474            let point_range = range.to_point(&snapshot);
17475            let expand = !buffer.single_hunk_is_expanded(range, cx);
17476            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17477        })
17478    }
17479
17480    pub(crate) fn apply_all_diff_hunks(
17481        &mut self,
17482        _: &ApplyAllDiffHunks,
17483        window: &mut Window,
17484        cx: &mut Context<Self>,
17485    ) {
17486        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17487
17488        let buffers = self.buffer.read(cx).all_buffers();
17489        for branch_buffer in buffers {
17490            branch_buffer.update(cx, |branch_buffer, cx| {
17491                branch_buffer.merge_into_base(Vec::new(), cx);
17492            });
17493        }
17494
17495        if let Some(project) = self.project.clone() {
17496            self.save(
17497                SaveOptions {
17498                    format: true,
17499                    autosave: false,
17500                },
17501                project,
17502                window,
17503                cx,
17504            )
17505            .detach_and_log_err(cx);
17506        }
17507    }
17508
17509    pub(crate) fn apply_selected_diff_hunks(
17510        &mut self,
17511        _: &ApplyDiffHunk,
17512        window: &mut Window,
17513        cx: &mut Context<Self>,
17514    ) {
17515        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17516        let snapshot = self.snapshot(window, cx);
17517        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17518        let mut ranges_by_buffer = HashMap::default();
17519        self.transact(window, cx, |editor, _window, cx| {
17520            for hunk in hunks {
17521                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17522                    ranges_by_buffer
17523                        .entry(buffer.clone())
17524                        .or_insert_with(Vec::new)
17525                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17526                }
17527            }
17528
17529            for (buffer, ranges) in ranges_by_buffer {
17530                buffer.update(cx, |buffer, cx| {
17531                    buffer.merge_into_base(ranges, cx);
17532                });
17533            }
17534        });
17535
17536        if let Some(project) = self.project.clone() {
17537            self.save(
17538                SaveOptions {
17539                    format: true,
17540                    autosave: false,
17541                },
17542                project,
17543                window,
17544                cx,
17545            )
17546            .detach_and_log_err(cx);
17547        }
17548    }
17549
17550    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17551        if hovered != self.gutter_hovered {
17552            self.gutter_hovered = hovered;
17553            cx.notify();
17554        }
17555    }
17556
17557    pub fn insert_blocks(
17558        &mut self,
17559        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17560        autoscroll: Option<Autoscroll>,
17561        cx: &mut Context<Self>,
17562    ) -> Vec<CustomBlockId> {
17563        let blocks = self
17564            .display_map
17565            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17566        if let Some(autoscroll) = autoscroll {
17567            self.request_autoscroll(autoscroll, cx);
17568        }
17569        cx.notify();
17570        blocks
17571    }
17572
17573    pub fn resize_blocks(
17574        &mut self,
17575        heights: HashMap<CustomBlockId, u32>,
17576        autoscroll: Option<Autoscroll>,
17577        cx: &mut Context<Self>,
17578    ) {
17579        self.display_map
17580            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17581        if let Some(autoscroll) = autoscroll {
17582            self.request_autoscroll(autoscroll, cx);
17583        }
17584        cx.notify();
17585    }
17586
17587    pub fn replace_blocks(
17588        &mut self,
17589        renderers: HashMap<CustomBlockId, RenderBlock>,
17590        autoscroll: Option<Autoscroll>,
17591        cx: &mut Context<Self>,
17592    ) {
17593        self.display_map
17594            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17595        if let Some(autoscroll) = autoscroll {
17596            self.request_autoscroll(autoscroll, cx);
17597        }
17598        cx.notify();
17599    }
17600
17601    pub fn remove_blocks(
17602        &mut self,
17603        block_ids: HashSet<CustomBlockId>,
17604        autoscroll: Option<Autoscroll>,
17605        cx: &mut Context<Self>,
17606    ) {
17607        self.display_map.update(cx, |display_map, cx| {
17608            display_map.remove_blocks(block_ids, cx)
17609        });
17610        if let Some(autoscroll) = autoscroll {
17611            self.request_autoscroll(autoscroll, cx);
17612        }
17613        cx.notify();
17614    }
17615
17616    pub fn row_for_block(
17617        &self,
17618        block_id: CustomBlockId,
17619        cx: &mut Context<Self>,
17620    ) -> Option<DisplayRow> {
17621        self.display_map
17622            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17623    }
17624
17625    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17626        self.focused_block = Some(focused_block);
17627    }
17628
17629    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17630        self.focused_block.take()
17631    }
17632
17633    pub fn insert_creases(
17634        &mut self,
17635        creases: impl IntoIterator<Item = Crease<Anchor>>,
17636        cx: &mut Context<Self>,
17637    ) -> Vec<CreaseId> {
17638        self.display_map
17639            .update(cx, |map, cx| map.insert_creases(creases, cx))
17640    }
17641
17642    pub fn remove_creases(
17643        &mut self,
17644        ids: impl IntoIterator<Item = CreaseId>,
17645        cx: &mut Context<Self>,
17646    ) -> Vec<(CreaseId, Range<Anchor>)> {
17647        self.display_map
17648            .update(cx, |map, cx| map.remove_creases(ids, cx))
17649    }
17650
17651    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17652        self.display_map
17653            .update(cx, |map, cx| map.snapshot(cx))
17654            .longest_row()
17655    }
17656
17657    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17658        self.display_map
17659            .update(cx, |map, cx| map.snapshot(cx))
17660            .max_point()
17661    }
17662
17663    pub fn text(&self, cx: &App) -> String {
17664        self.buffer.read(cx).read(cx).text()
17665    }
17666
17667    pub fn is_empty(&self, cx: &App) -> bool {
17668        self.buffer.read(cx).read(cx).is_empty()
17669    }
17670
17671    pub fn text_option(&self, cx: &App) -> Option<String> {
17672        let text = self.text(cx);
17673        let text = text.trim();
17674
17675        if text.is_empty() {
17676            return None;
17677        }
17678
17679        Some(text.to_string())
17680    }
17681
17682    pub fn set_text(
17683        &mut self,
17684        text: impl Into<Arc<str>>,
17685        window: &mut Window,
17686        cx: &mut Context<Self>,
17687    ) {
17688        self.transact(window, cx, |this, _, cx| {
17689            this.buffer
17690                .read(cx)
17691                .as_singleton()
17692                .expect("you can only call set_text on editors for singleton buffers")
17693                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17694        });
17695    }
17696
17697    pub fn display_text(&self, cx: &mut App) -> String {
17698        self.display_map
17699            .update(cx, |map, cx| map.snapshot(cx))
17700            .text()
17701    }
17702
17703    fn create_minimap(
17704        &self,
17705        minimap_settings: MinimapSettings,
17706        window: &mut Window,
17707        cx: &mut Context<Self>,
17708    ) -> Option<Entity<Self>> {
17709        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17710            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17711    }
17712
17713    fn initialize_new_minimap(
17714        &self,
17715        minimap_settings: MinimapSettings,
17716        window: &mut Window,
17717        cx: &mut Context<Self>,
17718    ) -> Entity<Self> {
17719        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17720
17721        let mut minimap = Editor::new_internal(
17722            EditorMode::Minimap {
17723                parent: cx.weak_entity(),
17724            },
17725            self.buffer.clone(),
17726            self.project.clone(),
17727            Some(self.display_map.clone()),
17728            window,
17729            cx,
17730        );
17731        minimap.scroll_manager.clone_state(&self.scroll_manager);
17732        minimap.set_text_style_refinement(TextStyleRefinement {
17733            font_size: Some(MINIMAP_FONT_SIZE),
17734            font_weight: Some(MINIMAP_FONT_WEIGHT),
17735            ..Default::default()
17736        });
17737        minimap.update_minimap_configuration(minimap_settings, cx);
17738        cx.new(|_| minimap)
17739    }
17740
17741    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17742        let current_line_highlight = minimap_settings
17743            .current_line_highlight
17744            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17745        self.set_current_line_highlight(Some(current_line_highlight));
17746    }
17747
17748    pub fn minimap(&self) -> Option<&Entity<Self>> {
17749        self.minimap
17750            .as_ref()
17751            .filter(|_| self.minimap_visibility.visible())
17752    }
17753
17754    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17755        let mut wrap_guides = smallvec![];
17756
17757        if self.show_wrap_guides == Some(false) {
17758            return wrap_guides;
17759        }
17760
17761        let settings = self.buffer.read(cx).language_settings(cx);
17762        if settings.show_wrap_guides {
17763            match self.soft_wrap_mode(cx) {
17764                SoftWrap::Column(soft_wrap) => {
17765                    wrap_guides.push((soft_wrap as usize, true));
17766                }
17767                SoftWrap::Bounded(soft_wrap) => {
17768                    wrap_guides.push((soft_wrap as usize, true));
17769                }
17770                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17771            }
17772            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17773        }
17774
17775        wrap_guides
17776    }
17777
17778    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17779        let settings = self.buffer.read(cx).language_settings(cx);
17780        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17781        match mode {
17782            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17783                SoftWrap::None
17784            }
17785            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17786            language_settings::SoftWrap::PreferredLineLength => {
17787                SoftWrap::Column(settings.preferred_line_length)
17788            }
17789            language_settings::SoftWrap::Bounded => {
17790                SoftWrap::Bounded(settings.preferred_line_length)
17791            }
17792        }
17793    }
17794
17795    pub fn set_soft_wrap_mode(
17796        &mut self,
17797        mode: language_settings::SoftWrap,
17798
17799        cx: &mut Context<Self>,
17800    ) {
17801        self.soft_wrap_mode_override = Some(mode);
17802        cx.notify();
17803    }
17804
17805    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17806        self.hard_wrap = hard_wrap;
17807        cx.notify();
17808    }
17809
17810    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17811        self.text_style_refinement = Some(style);
17812    }
17813
17814    /// called by the Element so we know what style we were most recently rendered with.
17815    pub(crate) fn set_style(
17816        &mut self,
17817        style: EditorStyle,
17818        window: &mut Window,
17819        cx: &mut Context<Self>,
17820    ) {
17821        // We intentionally do not inform the display map about the minimap style
17822        // so that wrapping is not recalculated and stays consistent for the editor
17823        // and its linked minimap.
17824        if !self.mode.is_minimap() {
17825            let rem_size = window.rem_size();
17826            self.display_map.update(cx, |map, cx| {
17827                map.set_font(
17828                    style.text.font(),
17829                    style.text.font_size.to_pixels(rem_size),
17830                    cx,
17831                )
17832            });
17833        }
17834        self.style = Some(style);
17835    }
17836
17837    pub fn style(&self) -> Option<&EditorStyle> {
17838        self.style.as_ref()
17839    }
17840
17841    // Called by the element. This method is not designed to be called outside of the editor
17842    // element's layout code because it does not notify when rewrapping is computed synchronously.
17843    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17844        self.display_map
17845            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17846    }
17847
17848    pub fn set_soft_wrap(&mut self) {
17849        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17850    }
17851
17852    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17853        if self.soft_wrap_mode_override.is_some() {
17854            self.soft_wrap_mode_override.take();
17855        } else {
17856            let soft_wrap = match self.soft_wrap_mode(cx) {
17857                SoftWrap::GitDiff => return,
17858                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17859                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17860                    language_settings::SoftWrap::None
17861                }
17862            };
17863            self.soft_wrap_mode_override = Some(soft_wrap);
17864        }
17865        cx.notify();
17866    }
17867
17868    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17869        let Some(workspace) = self.workspace() else {
17870            return;
17871        };
17872        let fs = workspace.read(cx).app_state().fs.clone();
17873        let current_show = TabBarSettings::get_global(cx).show;
17874        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17875            setting.show = Some(!current_show);
17876        });
17877    }
17878
17879    pub fn toggle_indent_guides(
17880        &mut self,
17881        _: &ToggleIndentGuides,
17882        _: &mut Window,
17883        cx: &mut Context<Self>,
17884    ) {
17885        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17886            self.buffer
17887                .read(cx)
17888                .language_settings(cx)
17889                .indent_guides
17890                .enabled
17891        });
17892        self.show_indent_guides = Some(!currently_enabled);
17893        cx.notify();
17894    }
17895
17896    fn should_show_indent_guides(&self) -> Option<bool> {
17897        self.show_indent_guides
17898    }
17899
17900    pub fn toggle_line_numbers(
17901        &mut self,
17902        _: &ToggleLineNumbers,
17903        _: &mut Window,
17904        cx: &mut Context<Self>,
17905    ) {
17906        let mut editor_settings = EditorSettings::get_global(cx).clone();
17907        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17908        EditorSettings::override_global(editor_settings, cx);
17909    }
17910
17911    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17912        if let Some(show_line_numbers) = self.show_line_numbers {
17913            return show_line_numbers;
17914        }
17915        EditorSettings::get_global(cx).gutter.line_numbers
17916    }
17917
17918    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17919        self.use_relative_line_numbers
17920            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17921    }
17922
17923    pub fn toggle_relative_line_numbers(
17924        &mut self,
17925        _: &ToggleRelativeLineNumbers,
17926        _: &mut Window,
17927        cx: &mut Context<Self>,
17928    ) {
17929        let is_relative = self.should_use_relative_line_numbers(cx);
17930        self.set_relative_line_number(Some(!is_relative), cx)
17931    }
17932
17933    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17934        self.use_relative_line_numbers = is_relative;
17935        cx.notify();
17936    }
17937
17938    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17939        self.show_gutter = show_gutter;
17940        cx.notify();
17941    }
17942
17943    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17944        self.show_scrollbars = ScrollbarAxes {
17945            horizontal: show,
17946            vertical: show,
17947        };
17948        cx.notify();
17949    }
17950
17951    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17952        self.show_scrollbars.vertical = show;
17953        cx.notify();
17954    }
17955
17956    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17957        self.show_scrollbars.horizontal = show;
17958        cx.notify();
17959    }
17960
17961    pub fn set_minimap_visibility(
17962        &mut self,
17963        minimap_visibility: MinimapVisibility,
17964        window: &mut Window,
17965        cx: &mut Context<Self>,
17966    ) {
17967        if self.minimap_visibility != minimap_visibility {
17968            if minimap_visibility.visible() && self.minimap.is_none() {
17969                let minimap_settings = EditorSettings::get_global(cx).minimap;
17970                self.minimap =
17971                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17972            }
17973            self.minimap_visibility = minimap_visibility;
17974            cx.notify();
17975        }
17976    }
17977
17978    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17979        self.set_show_scrollbars(false, cx);
17980        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17981    }
17982
17983    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17984        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17985    }
17986
17987    /// Normally the text in full mode and auto height editors is padded on the
17988    /// left side by roughly half a character width for improved hit testing.
17989    ///
17990    /// Use this method to disable this for cases where this is not wanted (e.g.
17991    /// if you want to align the editor text with some other text above or below)
17992    /// or if you want to add this padding to single-line editors.
17993    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17994        self.offset_content = offset_content;
17995        cx.notify();
17996    }
17997
17998    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17999        self.show_line_numbers = Some(show_line_numbers);
18000        cx.notify();
18001    }
18002
18003    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18004        self.disable_expand_excerpt_buttons = true;
18005        cx.notify();
18006    }
18007
18008    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18009        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18010        cx.notify();
18011    }
18012
18013    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18014        self.show_code_actions = Some(show_code_actions);
18015        cx.notify();
18016    }
18017
18018    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18019        self.show_runnables = Some(show_runnables);
18020        cx.notify();
18021    }
18022
18023    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18024        self.show_breakpoints = Some(show_breakpoints);
18025        cx.notify();
18026    }
18027
18028    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18029        if self.display_map.read(cx).masked != masked {
18030            self.display_map.update(cx, |map, _| map.masked = masked);
18031        }
18032        cx.notify()
18033    }
18034
18035    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18036        self.show_wrap_guides = Some(show_wrap_guides);
18037        cx.notify();
18038    }
18039
18040    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18041        self.show_indent_guides = Some(show_indent_guides);
18042        cx.notify();
18043    }
18044
18045    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18046        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18047            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18048                if let Some(dir) = file.abs_path(cx).parent() {
18049                    return Some(dir.to_owned());
18050                }
18051            }
18052
18053            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18054                return Some(project_path.path.to_path_buf());
18055            }
18056        }
18057
18058        None
18059    }
18060
18061    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18062        self.active_excerpt(cx)?
18063            .1
18064            .read(cx)
18065            .file()
18066            .and_then(|f| f.as_local())
18067    }
18068
18069    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18070        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18071            let buffer = buffer.read(cx);
18072            if let Some(project_path) = buffer.project_path(cx) {
18073                let project = self.project.as_ref()?.read(cx);
18074                project.absolute_path(&project_path, cx)
18075            } else {
18076                buffer
18077                    .file()
18078                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18079            }
18080        })
18081    }
18082
18083    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18084        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18085            let project_path = buffer.read(cx).project_path(cx)?;
18086            let project = self.project.as_ref()?.read(cx);
18087            let entry = project.entry_for_path(&project_path, cx)?;
18088            let path = entry.path.to_path_buf();
18089            Some(path)
18090        })
18091    }
18092
18093    pub fn reveal_in_finder(
18094        &mut self,
18095        _: &RevealInFileManager,
18096        _window: &mut Window,
18097        cx: &mut Context<Self>,
18098    ) {
18099        if let Some(target) = self.target_file(cx) {
18100            cx.reveal_path(&target.abs_path(cx));
18101        }
18102    }
18103
18104    pub fn copy_path(
18105        &mut self,
18106        _: &zed_actions::workspace::CopyPath,
18107        _window: &mut Window,
18108        cx: &mut Context<Self>,
18109    ) {
18110        if let Some(path) = self.target_file_abs_path(cx) {
18111            if let Some(path) = path.to_str() {
18112                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18113            }
18114        }
18115    }
18116
18117    pub fn copy_relative_path(
18118        &mut self,
18119        _: &zed_actions::workspace::CopyRelativePath,
18120        _window: &mut Window,
18121        cx: &mut Context<Self>,
18122    ) {
18123        if let Some(path) = self.target_file_path(cx) {
18124            if let Some(path) = path.to_str() {
18125                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18126            }
18127        }
18128    }
18129
18130    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18131        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18132            buffer.read(cx).project_path(cx)
18133        } else {
18134            None
18135        }
18136    }
18137
18138    // Returns true if the editor handled a go-to-line request
18139    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18140        maybe!({
18141            let breakpoint_store = self.breakpoint_store.as_ref()?;
18142
18143            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18144            else {
18145                self.clear_row_highlights::<ActiveDebugLine>();
18146                return None;
18147            };
18148
18149            let position = active_stack_frame.position;
18150            let buffer_id = position.buffer_id?;
18151            let snapshot = self
18152                .project
18153                .as_ref()?
18154                .read(cx)
18155                .buffer_for_id(buffer_id, cx)?
18156                .read(cx)
18157                .snapshot();
18158
18159            let mut handled = false;
18160            for (id, ExcerptRange { context, .. }) in
18161                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18162            {
18163                if context.start.cmp(&position, &snapshot).is_ge()
18164                    || context.end.cmp(&position, &snapshot).is_lt()
18165                {
18166                    continue;
18167                }
18168                let snapshot = self.buffer.read(cx).snapshot(cx);
18169                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18170
18171                handled = true;
18172                self.clear_row_highlights::<ActiveDebugLine>();
18173
18174                self.go_to_line::<ActiveDebugLine>(
18175                    multibuffer_anchor,
18176                    Some(cx.theme().colors().editor_debugger_active_line_background),
18177                    window,
18178                    cx,
18179                );
18180
18181                cx.notify();
18182            }
18183
18184            handled.then_some(())
18185        })
18186        .is_some()
18187    }
18188
18189    pub fn copy_file_name_without_extension(
18190        &mut self,
18191        _: &CopyFileNameWithoutExtension,
18192        _: &mut Window,
18193        cx: &mut Context<Self>,
18194    ) {
18195        if let Some(file) = self.target_file(cx) {
18196            if let Some(file_stem) = file.path().file_stem() {
18197                if let Some(name) = file_stem.to_str() {
18198                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18199                }
18200            }
18201        }
18202    }
18203
18204    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18205        if let Some(file) = self.target_file(cx) {
18206            if let Some(file_name) = file.path().file_name() {
18207                if let Some(name) = file_name.to_str() {
18208                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18209                }
18210            }
18211        }
18212    }
18213
18214    pub fn toggle_git_blame(
18215        &mut self,
18216        _: &::git::Blame,
18217        window: &mut Window,
18218        cx: &mut Context<Self>,
18219    ) {
18220        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18221
18222        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18223            self.start_git_blame(true, window, cx);
18224        }
18225
18226        cx.notify();
18227    }
18228
18229    pub fn toggle_git_blame_inline(
18230        &mut self,
18231        _: &ToggleGitBlameInline,
18232        window: &mut Window,
18233        cx: &mut Context<Self>,
18234    ) {
18235        self.toggle_git_blame_inline_internal(true, window, cx);
18236        cx.notify();
18237    }
18238
18239    pub fn open_git_blame_commit(
18240        &mut self,
18241        _: &OpenGitBlameCommit,
18242        window: &mut Window,
18243        cx: &mut Context<Self>,
18244    ) {
18245        self.open_git_blame_commit_internal(window, cx);
18246    }
18247
18248    fn open_git_blame_commit_internal(
18249        &mut self,
18250        window: &mut Window,
18251        cx: &mut Context<Self>,
18252    ) -> Option<()> {
18253        let blame = self.blame.as_ref()?;
18254        let snapshot = self.snapshot(window, cx);
18255        let cursor = self.selections.newest::<Point>(cx).head();
18256        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18257        let blame_entry = blame
18258            .update(cx, |blame, cx| {
18259                blame
18260                    .blame_for_rows(
18261                        &[RowInfo {
18262                            buffer_id: Some(buffer.remote_id()),
18263                            buffer_row: Some(point.row),
18264                            ..Default::default()
18265                        }],
18266                        cx,
18267                    )
18268                    .next()
18269            })
18270            .flatten()?;
18271        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18272        let repo = blame.read(cx).repository(cx)?;
18273        let workspace = self.workspace()?.downgrade();
18274        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18275        None
18276    }
18277
18278    pub fn git_blame_inline_enabled(&self) -> bool {
18279        self.git_blame_inline_enabled
18280    }
18281
18282    pub fn toggle_selection_menu(
18283        &mut self,
18284        _: &ToggleSelectionMenu,
18285        _: &mut Window,
18286        cx: &mut Context<Self>,
18287    ) {
18288        self.show_selection_menu = self
18289            .show_selection_menu
18290            .map(|show_selections_menu| !show_selections_menu)
18291            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18292
18293        cx.notify();
18294    }
18295
18296    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18297        self.show_selection_menu
18298            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18299    }
18300
18301    fn start_git_blame(
18302        &mut self,
18303        user_triggered: bool,
18304        window: &mut Window,
18305        cx: &mut Context<Self>,
18306    ) {
18307        if let Some(project) = self.project.as_ref() {
18308            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18309                return;
18310            };
18311
18312            if buffer.read(cx).file().is_none() {
18313                return;
18314            }
18315
18316            let focused = self.focus_handle(cx).contains_focused(window, cx);
18317
18318            let project = project.clone();
18319            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18320            self.blame_subscription =
18321                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18322            self.blame = Some(blame);
18323        }
18324    }
18325
18326    fn toggle_git_blame_inline_internal(
18327        &mut self,
18328        user_triggered: bool,
18329        window: &mut Window,
18330        cx: &mut Context<Self>,
18331    ) {
18332        if self.git_blame_inline_enabled {
18333            self.git_blame_inline_enabled = false;
18334            self.show_git_blame_inline = false;
18335            self.show_git_blame_inline_delay_task.take();
18336        } else {
18337            self.git_blame_inline_enabled = true;
18338            self.start_git_blame_inline(user_triggered, window, cx);
18339        }
18340
18341        cx.notify();
18342    }
18343
18344    fn start_git_blame_inline(
18345        &mut self,
18346        user_triggered: bool,
18347        window: &mut Window,
18348        cx: &mut Context<Self>,
18349    ) {
18350        self.start_git_blame(user_triggered, window, cx);
18351
18352        if ProjectSettings::get_global(cx)
18353            .git
18354            .inline_blame_delay()
18355            .is_some()
18356        {
18357            self.start_inline_blame_timer(window, cx);
18358        } else {
18359            self.show_git_blame_inline = true
18360        }
18361    }
18362
18363    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18364        self.blame.as_ref()
18365    }
18366
18367    pub fn show_git_blame_gutter(&self) -> bool {
18368        self.show_git_blame_gutter
18369    }
18370
18371    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18372        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18373    }
18374
18375    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18376        self.show_git_blame_inline
18377            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18378            && !self.newest_selection_head_on_empty_line(cx)
18379            && self.has_blame_entries(cx)
18380    }
18381
18382    fn has_blame_entries(&self, cx: &App) -> bool {
18383        self.blame()
18384            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18385    }
18386
18387    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18388        let cursor_anchor = self.selections.newest_anchor().head();
18389
18390        let snapshot = self.buffer.read(cx).snapshot(cx);
18391        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18392
18393        snapshot.line_len(buffer_row) == 0
18394    }
18395
18396    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18397        let buffer_and_selection = maybe!({
18398            let selection = self.selections.newest::<Point>(cx);
18399            let selection_range = selection.range();
18400
18401            let multi_buffer = self.buffer().read(cx);
18402            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18403            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18404
18405            let (buffer, range, _) = if selection.reversed {
18406                buffer_ranges.first()
18407            } else {
18408                buffer_ranges.last()
18409            }?;
18410
18411            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18412                ..text::ToPoint::to_point(&range.end, &buffer).row;
18413            Some((
18414                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18415                selection,
18416            ))
18417        });
18418
18419        let Some((buffer, selection)) = buffer_and_selection else {
18420            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18421        };
18422
18423        let Some(project) = self.project.as_ref() else {
18424            return Task::ready(Err(anyhow!("editor does not have project")));
18425        };
18426
18427        project.update(cx, |project, cx| {
18428            project.get_permalink_to_line(&buffer, selection, cx)
18429        })
18430    }
18431
18432    pub fn copy_permalink_to_line(
18433        &mut self,
18434        _: &CopyPermalinkToLine,
18435        window: &mut Window,
18436        cx: &mut Context<Self>,
18437    ) {
18438        let permalink_task = self.get_permalink_to_line(cx);
18439        let workspace = self.workspace();
18440
18441        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18442            Ok(permalink) => {
18443                cx.update(|_, cx| {
18444                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18445                })
18446                .ok();
18447            }
18448            Err(err) => {
18449                let message = format!("Failed to copy permalink: {err}");
18450
18451                anyhow::Result::<()>::Err(err).log_err();
18452
18453                if let Some(workspace) = workspace {
18454                    workspace
18455                        .update_in(cx, |workspace, _, cx| {
18456                            struct CopyPermalinkToLine;
18457
18458                            workspace.show_toast(
18459                                Toast::new(
18460                                    NotificationId::unique::<CopyPermalinkToLine>(),
18461                                    message,
18462                                ),
18463                                cx,
18464                            )
18465                        })
18466                        .ok();
18467                }
18468            }
18469        })
18470        .detach();
18471    }
18472
18473    pub fn copy_file_location(
18474        &mut self,
18475        _: &CopyFileLocation,
18476        _: &mut Window,
18477        cx: &mut Context<Self>,
18478    ) {
18479        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18480        if let Some(file) = self.target_file(cx) {
18481            if let Some(path) = file.path().to_str() {
18482                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18483            }
18484        }
18485    }
18486
18487    pub fn open_permalink_to_line(
18488        &mut self,
18489        _: &OpenPermalinkToLine,
18490        window: &mut Window,
18491        cx: &mut Context<Self>,
18492    ) {
18493        let permalink_task = self.get_permalink_to_line(cx);
18494        let workspace = self.workspace();
18495
18496        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18497            Ok(permalink) => {
18498                cx.update(|_, cx| {
18499                    cx.open_url(permalink.as_ref());
18500                })
18501                .ok();
18502            }
18503            Err(err) => {
18504                let message = format!("Failed to open permalink: {err}");
18505
18506                anyhow::Result::<()>::Err(err).log_err();
18507
18508                if let Some(workspace) = workspace {
18509                    workspace
18510                        .update(cx, |workspace, cx| {
18511                            struct OpenPermalinkToLine;
18512
18513                            workspace.show_toast(
18514                                Toast::new(
18515                                    NotificationId::unique::<OpenPermalinkToLine>(),
18516                                    message,
18517                                ),
18518                                cx,
18519                            )
18520                        })
18521                        .ok();
18522                }
18523            }
18524        })
18525        .detach();
18526    }
18527
18528    pub fn insert_uuid_v4(
18529        &mut self,
18530        _: &InsertUuidV4,
18531        window: &mut Window,
18532        cx: &mut Context<Self>,
18533    ) {
18534        self.insert_uuid(UuidVersion::V4, window, cx);
18535    }
18536
18537    pub fn insert_uuid_v7(
18538        &mut self,
18539        _: &InsertUuidV7,
18540        window: &mut Window,
18541        cx: &mut Context<Self>,
18542    ) {
18543        self.insert_uuid(UuidVersion::V7, window, cx);
18544    }
18545
18546    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18547        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18548        self.transact(window, cx, |this, window, cx| {
18549            let edits = this
18550                .selections
18551                .all::<Point>(cx)
18552                .into_iter()
18553                .map(|selection| {
18554                    let uuid = match version {
18555                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18556                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18557                    };
18558
18559                    (selection.range(), uuid.to_string())
18560                });
18561            this.edit(edits, cx);
18562            this.refresh_inline_completion(true, false, window, cx);
18563        });
18564    }
18565
18566    pub fn open_selections_in_multibuffer(
18567        &mut self,
18568        _: &OpenSelectionsInMultibuffer,
18569        window: &mut Window,
18570        cx: &mut Context<Self>,
18571    ) {
18572        let multibuffer = self.buffer.read(cx);
18573
18574        let Some(buffer) = multibuffer.as_singleton() else {
18575            return;
18576        };
18577
18578        let Some(workspace) = self.workspace() else {
18579            return;
18580        };
18581
18582        let title = multibuffer.title(cx).to_string();
18583
18584        let locations = self
18585            .selections
18586            .all_anchors(cx)
18587            .into_iter()
18588            .map(|selection| Location {
18589                buffer: buffer.clone(),
18590                range: selection.start.text_anchor..selection.end.text_anchor,
18591            })
18592            .collect::<Vec<_>>();
18593
18594        cx.spawn_in(window, async move |_, cx| {
18595            workspace.update_in(cx, |workspace, window, cx| {
18596                Self::open_locations_in_multibuffer(
18597                    workspace,
18598                    locations,
18599                    format!("Selections for '{title}'"),
18600                    false,
18601                    MultibufferSelectionMode::All,
18602                    window,
18603                    cx,
18604                );
18605            })
18606        })
18607        .detach();
18608    }
18609
18610    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18611    /// last highlight added will be used.
18612    ///
18613    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18614    pub fn highlight_rows<T: 'static>(
18615        &mut self,
18616        range: Range<Anchor>,
18617        color: Hsla,
18618        options: RowHighlightOptions,
18619        cx: &mut Context<Self>,
18620    ) {
18621        let snapshot = self.buffer().read(cx).snapshot(cx);
18622        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18623        let ix = row_highlights.binary_search_by(|highlight| {
18624            Ordering::Equal
18625                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18626                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18627        });
18628
18629        if let Err(mut ix) = ix {
18630            let index = post_inc(&mut self.highlight_order);
18631
18632            // If this range intersects with the preceding highlight, then merge it with
18633            // the preceding highlight. Otherwise insert a new highlight.
18634            let mut merged = false;
18635            if ix > 0 {
18636                let prev_highlight = &mut row_highlights[ix - 1];
18637                if prev_highlight
18638                    .range
18639                    .end
18640                    .cmp(&range.start, &snapshot)
18641                    .is_ge()
18642                {
18643                    ix -= 1;
18644                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18645                        prev_highlight.range.end = range.end;
18646                    }
18647                    merged = true;
18648                    prev_highlight.index = index;
18649                    prev_highlight.color = color;
18650                    prev_highlight.options = options;
18651                }
18652            }
18653
18654            if !merged {
18655                row_highlights.insert(
18656                    ix,
18657                    RowHighlight {
18658                        range: range.clone(),
18659                        index,
18660                        color,
18661                        options,
18662                        type_id: TypeId::of::<T>(),
18663                    },
18664                );
18665            }
18666
18667            // If any of the following highlights intersect with this one, merge them.
18668            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18669                let highlight = &row_highlights[ix];
18670                if next_highlight
18671                    .range
18672                    .start
18673                    .cmp(&highlight.range.end, &snapshot)
18674                    .is_le()
18675                {
18676                    if next_highlight
18677                        .range
18678                        .end
18679                        .cmp(&highlight.range.end, &snapshot)
18680                        .is_gt()
18681                    {
18682                        row_highlights[ix].range.end = next_highlight.range.end;
18683                    }
18684                    row_highlights.remove(ix + 1);
18685                } else {
18686                    break;
18687                }
18688            }
18689        }
18690    }
18691
18692    /// Remove any highlighted row ranges of the given type that intersect the
18693    /// given ranges.
18694    pub fn remove_highlighted_rows<T: 'static>(
18695        &mut self,
18696        ranges_to_remove: Vec<Range<Anchor>>,
18697        cx: &mut Context<Self>,
18698    ) {
18699        let snapshot = self.buffer().read(cx).snapshot(cx);
18700        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18701        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18702        row_highlights.retain(|highlight| {
18703            while let Some(range_to_remove) = ranges_to_remove.peek() {
18704                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18705                    Ordering::Less | Ordering::Equal => {
18706                        ranges_to_remove.next();
18707                    }
18708                    Ordering::Greater => {
18709                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18710                            Ordering::Less | Ordering::Equal => {
18711                                return false;
18712                            }
18713                            Ordering::Greater => break,
18714                        }
18715                    }
18716                }
18717            }
18718
18719            true
18720        })
18721    }
18722
18723    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18724    pub fn clear_row_highlights<T: 'static>(&mut self) {
18725        self.highlighted_rows.remove(&TypeId::of::<T>());
18726    }
18727
18728    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18729    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18730        self.highlighted_rows
18731            .get(&TypeId::of::<T>())
18732            .map_or(&[] as &[_], |vec| vec.as_slice())
18733            .iter()
18734            .map(|highlight| (highlight.range.clone(), highlight.color))
18735    }
18736
18737    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18738    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18739    /// Allows to ignore certain kinds of highlights.
18740    pub fn highlighted_display_rows(
18741        &self,
18742        window: &mut Window,
18743        cx: &mut App,
18744    ) -> BTreeMap<DisplayRow, LineHighlight> {
18745        let snapshot = self.snapshot(window, cx);
18746        let mut used_highlight_orders = HashMap::default();
18747        self.highlighted_rows
18748            .iter()
18749            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18750            .fold(
18751                BTreeMap::<DisplayRow, LineHighlight>::new(),
18752                |mut unique_rows, highlight| {
18753                    let start = highlight.range.start.to_display_point(&snapshot);
18754                    let end = highlight.range.end.to_display_point(&snapshot);
18755                    let start_row = start.row().0;
18756                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18757                        && end.column() == 0
18758                    {
18759                        end.row().0.saturating_sub(1)
18760                    } else {
18761                        end.row().0
18762                    };
18763                    for row in start_row..=end_row {
18764                        let used_index =
18765                            used_highlight_orders.entry(row).or_insert(highlight.index);
18766                        if highlight.index >= *used_index {
18767                            *used_index = highlight.index;
18768                            unique_rows.insert(
18769                                DisplayRow(row),
18770                                LineHighlight {
18771                                    include_gutter: highlight.options.include_gutter,
18772                                    border: None,
18773                                    background: highlight.color.into(),
18774                                    type_id: Some(highlight.type_id),
18775                                },
18776                            );
18777                        }
18778                    }
18779                    unique_rows
18780                },
18781            )
18782    }
18783
18784    pub fn highlighted_display_row_for_autoscroll(
18785        &self,
18786        snapshot: &DisplaySnapshot,
18787    ) -> Option<DisplayRow> {
18788        self.highlighted_rows
18789            .values()
18790            .flat_map(|highlighted_rows| highlighted_rows.iter())
18791            .filter_map(|highlight| {
18792                if highlight.options.autoscroll {
18793                    Some(highlight.range.start.to_display_point(snapshot).row())
18794                } else {
18795                    None
18796                }
18797            })
18798            .min()
18799    }
18800
18801    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18802        self.highlight_background::<SearchWithinRange>(
18803            ranges,
18804            |colors| colors.colors().editor_document_highlight_read_background,
18805            cx,
18806        )
18807    }
18808
18809    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18810        self.breadcrumb_header = Some(new_header);
18811    }
18812
18813    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18814        self.clear_background_highlights::<SearchWithinRange>(cx);
18815    }
18816
18817    pub fn highlight_background<T: 'static>(
18818        &mut self,
18819        ranges: &[Range<Anchor>],
18820        color_fetcher: fn(&Theme) -> Hsla,
18821        cx: &mut Context<Self>,
18822    ) {
18823        self.background_highlights.insert(
18824            HighlightKey::Type(TypeId::of::<T>()),
18825            (color_fetcher, Arc::from(ranges)),
18826        );
18827        self.scrollbar_marker_state.dirty = true;
18828        cx.notify();
18829    }
18830
18831    pub fn highlight_background_key<T: 'static>(
18832        &mut self,
18833        key: usize,
18834        ranges: &[Range<Anchor>],
18835        color_fetcher: fn(&Theme) -> Hsla,
18836        cx: &mut Context<Self>,
18837    ) {
18838        self.background_highlights.insert(
18839            HighlightKey::TypePlus(TypeId::of::<T>(), key),
18840            (color_fetcher, Arc::from(ranges)),
18841        );
18842        self.scrollbar_marker_state.dirty = true;
18843        cx.notify();
18844    }
18845
18846    pub fn clear_background_highlights<T: 'static>(
18847        &mut self,
18848        cx: &mut Context<Self>,
18849    ) -> Option<BackgroundHighlight> {
18850        let text_highlights = self
18851            .background_highlights
18852            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
18853        if !text_highlights.1.is_empty() {
18854            self.scrollbar_marker_state.dirty = true;
18855            cx.notify();
18856        }
18857        Some(text_highlights)
18858    }
18859
18860    pub fn highlight_gutter<T: 'static>(
18861        &mut self,
18862        ranges: impl Into<Vec<Range<Anchor>>>,
18863        color_fetcher: fn(&App) -> Hsla,
18864        cx: &mut Context<Self>,
18865    ) {
18866        self.gutter_highlights
18867            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18868        cx.notify();
18869    }
18870
18871    pub fn clear_gutter_highlights<T: 'static>(
18872        &mut self,
18873        cx: &mut Context<Self>,
18874    ) -> Option<GutterHighlight> {
18875        cx.notify();
18876        self.gutter_highlights.remove(&TypeId::of::<T>())
18877    }
18878
18879    pub fn insert_gutter_highlight<T: 'static>(
18880        &mut self,
18881        range: Range<Anchor>,
18882        color_fetcher: fn(&App) -> Hsla,
18883        cx: &mut Context<Self>,
18884    ) {
18885        let snapshot = self.buffer().read(cx).snapshot(cx);
18886        let mut highlights = self
18887            .gutter_highlights
18888            .remove(&TypeId::of::<T>())
18889            .map(|(_, highlights)| highlights)
18890            .unwrap_or_default();
18891        let ix = highlights.binary_search_by(|highlight| {
18892            Ordering::Equal
18893                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18894                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18895        });
18896        if let Err(ix) = ix {
18897            highlights.insert(ix, range);
18898        }
18899        self.gutter_highlights
18900            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18901    }
18902
18903    pub fn remove_gutter_highlights<T: 'static>(
18904        &mut self,
18905        ranges_to_remove: Vec<Range<Anchor>>,
18906        cx: &mut Context<Self>,
18907    ) {
18908        let snapshot = self.buffer().read(cx).snapshot(cx);
18909        let Some((color_fetcher, mut gutter_highlights)) =
18910            self.gutter_highlights.remove(&TypeId::of::<T>())
18911        else {
18912            return;
18913        };
18914        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18915        gutter_highlights.retain(|highlight| {
18916            while let Some(range_to_remove) = ranges_to_remove.peek() {
18917                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18918                    Ordering::Less | Ordering::Equal => {
18919                        ranges_to_remove.next();
18920                    }
18921                    Ordering::Greater => {
18922                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18923                            Ordering::Less | Ordering::Equal => {
18924                                return false;
18925                            }
18926                            Ordering::Greater => break,
18927                        }
18928                    }
18929                }
18930            }
18931
18932            true
18933        });
18934        self.gutter_highlights
18935            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18936    }
18937
18938    #[cfg(feature = "test-support")]
18939    pub fn all_text_highlights(
18940        &self,
18941        window: &mut Window,
18942        cx: &mut Context<Self>,
18943    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
18944        let snapshot = self.snapshot(window, cx);
18945        self.display_map.update(cx, |display_map, _| {
18946            display_map
18947                .all_text_highlights()
18948                .map(|highlight| {
18949                    let (style, ranges) = highlight.as_ref();
18950                    (
18951                        *style,
18952                        ranges
18953                            .iter()
18954                            .map(|range| range.clone().to_display_points(&snapshot))
18955                            .collect(),
18956                    )
18957                })
18958                .collect()
18959        })
18960    }
18961
18962    #[cfg(feature = "test-support")]
18963    pub fn all_text_background_highlights(
18964        &self,
18965        window: &mut Window,
18966        cx: &mut Context<Self>,
18967    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18968        let snapshot = self.snapshot(window, cx);
18969        let buffer = &snapshot.buffer_snapshot;
18970        let start = buffer.anchor_before(0);
18971        let end = buffer.anchor_after(buffer.len());
18972        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
18973    }
18974
18975    #[cfg(feature = "test-support")]
18976    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18977        let snapshot = self.buffer().read(cx).snapshot(cx);
18978
18979        let highlights = self
18980            .background_highlights
18981            .get(&HighlightKey::Type(TypeId::of::<
18982                items::BufferSearchHighlights,
18983            >()));
18984
18985        if let Some((_color, ranges)) = highlights {
18986            ranges
18987                .iter()
18988                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18989                .collect_vec()
18990        } else {
18991            vec![]
18992        }
18993    }
18994
18995    fn document_highlights_for_position<'a>(
18996        &'a self,
18997        position: Anchor,
18998        buffer: &'a MultiBufferSnapshot,
18999    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19000        let read_highlights = self
19001            .background_highlights
19002            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19003            .map(|h| &h.1);
19004        let write_highlights = self
19005            .background_highlights
19006            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19007            .map(|h| &h.1);
19008        let left_position = position.bias_left(buffer);
19009        let right_position = position.bias_right(buffer);
19010        read_highlights
19011            .into_iter()
19012            .chain(write_highlights)
19013            .flat_map(move |ranges| {
19014                let start_ix = match ranges.binary_search_by(|probe| {
19015                    let cmp = probe.end.cmp(&left_position, buffer);
19016                    if cmp.is_ge() {
19017                        Ordering::Greater
19018                    } else {
19019                        Ordering::Less
19020                    }
19021                }) {
19022                    Ok(i) | Err(i) => i,
19023                };
19024
19025                ranges[start_ix..]
19026                    .iter()
19027                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19028            })
19029    }
19030
19031    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19032        self.background_highlights
19033            .get(&HighlightKey::Type(TypeId::of::<T>()))
19034            .map_or(false, |(_, highlights)| !highlights.is_empty())
19035    }
19036
19037    pub fn background_highlights_in_range(
19038        &self,
19039        search_range: Range<Anchor>,
19040        display_snapshot: &DisplaySnapshot,
19041        theme: &Theme,
19042    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19043        let mut results = Vec::new();
19044        for (color_fetcher, ranges) in self.background_highlights.values() {
19045            let color = color_fetcher(theme);
19046            let start_ix = match ranges.binary_search_by(|probe| {
19047                let cmp = probe
19048                    .end
19049                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19050                if cmp.is_gt() {
19051                    Ordering::Greater
19052                } else {
19053                    Ordering::Less
19054                }
19055            }) {
19056                Ok(i) | Err(i) => i,
19057            };
19058            for range in &ranges[start_ix..] {
19059                if range
19060                    .start
19061                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19062                    .is_ge()
19063                {
19064                    break;
19065                }
19066
19067                let start = range.start.to_display_point(display_snapshot);
19068                let end = range.end.to_display_point(display_snapshot);
19069                results.push((start..end, color))
19070            }
19071        }
19072        results
19073    }
19074
19075    pub fn background_highlight_row_ranges<T: 'static>(
19076        &self,
19077        search_range: Range<Anchor>,
19078        display_snapshot: &DisplaySnapshot,
19079        count: usize,
19080    ) -> Vec<RangeInclusive<DisplayPoint>> {
19081        let mut results = Vec::new();
19082        let Some((_, ranges)) = self
19083            .background_highlights
19084            .get(&HighlightKey::Type(TypeId::of::<T>()))
19085        else {
19086            return vec![];
19087        };
19088
19089        let start_ix = match ranges.binary_search_by(|probe| {
19090            let cmp = probe
19091                .end
19092                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19093            if cmp.is_gt() {
19094                Ordering::Greater
19095            } else {
19096                Ordering::Less
19097            }
19098        }) {
19099            Ok(i) | Err(i) => i,
19100        };
19101        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19102            if let (Some(start_display), Some(end_display)) = (start, end) {
19103                results.push(
19104                    start_display.to_display_point(display_snapshot)
19105                        ..=end_display.to_display_point(display_snapshot),
19106                );
19107            }
19108        };
19109        let mut start_row: Option<Point> = None;
19110        let mut end_row: Option<Point> = None;
19111        if ranges.len() > count {
19112            return Vec::new();
19113        }
19114        for range in &ranges[start_ix..] {
19115            if range
19116                .start
19117                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19118                .is_ge()
19119            {
19120                break;
19121            }
19122            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19123            if let Some(current_row) = &end_row {
19124                if end.row == current_row.row {
19125                    continue;
19126                }
19127            }
19128            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19129            if start_row.is_none() {
19130                assert_eq!(end_row, None);
19131                start_row = Some(start);
19132                end_row = Some(end);
19133                continue;
19134            }
19135            if let Some(current_end) = end_row.as_mut() {
19136                if start.row > current_end.row + 1 {
19137                    push_region(start_row, end_row);
19138                    start_row = Some(start);
19139                    end_row = Some(end);
19140                } else {
19141                    // Merge two hunks.
19142                    *current_end = end;
19143                }
19144            } else {
19145                unreachable!();
19146            }
19147        }
19148        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19149        push_region(start_row, end_row);
19150        results
19151    }
19152
19153    pub fn gutter_highlights_in_range(
19154        &self,
19155        search_range: Range<Anchor>,
19156        display_snapshot: &DisplaySnapshot,
19157        cx: &App,
19158    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19159        let mut results = Vec::new();
19160        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19161            let color = color_fetcher(cx);
19162            let start_ix = match ranges.binary_search_by(|probe| {
19163                let cmp = probe
19164                    .end
19165                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19166                if cmp.is_gt() {
19167                    Ordering::Greater
19168                } else {
19169                    Ordering::Less
19170                }
19171            }) {
19172                Ok(i) | Err(i) => i,
19173            };
19174            for range in &ranges[start_ix..] {
19175                if range
19176                    .start
19177                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19178                    .is_ge()
19179                {
19180                    break;
19181                }
19182
19183                let start = range.start.to_display_point(display_snapshot);
19184                let end = range.end.to_display_point(display_snapshot);
19185                results.push((start..end, color))
19186            }
19187        }
19188        results
19189    }
19190
19191    /// Get the text ranges corresponding to the redaction query
19192    pub fn redacted_ranges(
19193        &self,
19194        search_range: Range<Anchor>,
19195        display_snapshot: &DisplaySnapshot,
19196        cx: &App,
19197    ) -> Vec<Range<DisplayPoint>> {
19198        display_snapshot
19199            .buffer_snapshot
19200            .redacted_ranges(search_range, |file| {
19201                if let Some(file) = file {
19202                    file.is_private()
19203                        && EditorSettings::get(
19204                            Some(SettingsLocation {
19205                                worktree_id: file.worktree_id(cx),
19206                                path: file.path().as_ref(),
19207                            }),
19208                            cx,
19209                        )
19210                        .redact_private_values
19211                } else {
19212                    false
19213                }
19214            })
19215            .map(|range| {
19216                range.start.to_display_point(display_snapshot)
19217                    ..range.end.to_display_point(display_snapshot)
19218            })
19219            .collect()
19220    }
19221
19222    pub fn highlight_text_key<T: 'static>(
19223        &mut self,
19224        key: usize,
19225        ranges: Vec<Range<Anchor>>,
19226        style: HighlightStyle,
19227        cx: &mut Context<Self>,
19228    ) {
19229        self.display_map.update(cx, |map, _| {
19230            map.highlight_text(
19231                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19232                ranges,
19233                style,
19234            );
19235        });
19236        cx.notify();
19237    }
19238
19239    pub fn highlight_text<T: 'static>(
19240        &mut self,
19241        ranges: Vec<Range<Anchor>>,
19242        style: HighlightStyle,
19243        cx: &mut Context<Self>,
19244    ) {
19245        self.display_map.update(cx, |map, _| {
19246            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19247        });
19248        cx.notify();
19249    }
19250
19251    pub(crate) fn highlight_inlays<T: 'static>(
19252        &mut self,
19253        highlights: Vec<InlayHighlight>,
19254        style: HighlightStyle,
19255        cx: &mut Context<Self>,
19256    ) {
19257        self.display_map.update(cx, |map, _| {
19258            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19259        });
19260        cx.notify();
19261    }
19262
19263    pub fn text_highlights<'a, T: 'static>(
19264        &'a self,
19265        cx: &'a App,
19266    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19267        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19268    }
19269
19270    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19271        let cleared = self
19272            .display_map
19273            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19274        if cleared {
19275            cx.notify();
19276        }
19277    }
19278
19279    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19280        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19281            && self.focus_handle.is_focused(window)
19282    }
19283
19284    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19285        self.show_cursor_when_unfocused = is_enabled;
19286        cx.notify();
19287    }
19288
19289    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19290        cx.notify();
19291    }
19292
19293    fn on_debug_session_event(
19294        &mut self,
19295        _session: Entity<Session>,
19296        event: &SessionEvent,
19297        cx: &mut Context<Self>,
19298    ) {
19299        match event {
19300            SessionEvent::InvalidateInlineValue => {
19301                self.refresh_inline_values(cx);
19302            }
19303            _ => {}
19304        }
19305    }
19306
19307    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19308        let Some(project) = self.project.clone() else {
19309            return;
19310        };
19311
19312        if !self.inline_value_cache.enabled {
19313            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19314            self.splice_inlays(&inlays, Vec::new(), cx);
19315            return;
19316        }
19317
19318        let current_execution_position = self
19319            .highlighted_rows
19320            .get(&TypeId::of::<ActiveDebugLine>())
19321            .and_then(|lines| lines.last().map(|line| line.range.end));
19322
19323        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19324            let inline_values = editor
19325                .update(cx, |editor, cx| {
19326                    let Some(current_execution_position) = current_execution_position else {
19327                        return Some(Task::ready(Ok(Vec::new())));
19328                    };
19329
19330                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19331                        let snapshot = buffer.snapshot(cx);
19332
19333                        let excerpt = snapshot.excerpt_containing(
19334                            current_execution_position..current_execution_position,
19335                        )?;
19336
19337                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19338                    })?;
19339
19340                    let range =
19341                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19342
19343                    project.inline_values(buffer, range, cx)
19344                })
19345                .ok()
19346                .flatten()?
19347                .await
19348                .context("refreshing debugger inlays")
19349                .log_err()?;
19350
19351            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19352
19353            for (buffer_id, inline_value) in inline_values
19354                .into_iter()
19355                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19356            {
19357                buffer_inline_values
19358                    .entry(buffer_id)
19359                    .or_default()
19360                    .push(inline_value);
19361            }
19362
19363            editor
19364                .update(cx, |editor, cx| {
19365                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19366                    let mut new_inlays = Vec::default();
19367
19368                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19369                        let buffer_id = buffer_snapshot.remote_id();
19370                        buffer_inline_values
19371                            .get(&buffer_id)
19372                            .into_iter()
19373                            .flatten()
19374                            .for_each(|hint| {
19375                                let inlay = Inlay::debugger(
19376                                    post_inc(&mut editor.next_inlay_id),
19377                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19378                                    hint.text(),
19379                                );
19380
19381                                new_inlays.push(inlay);
19382                            });
19383                    }
19384
19385                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19386                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19387
19388                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19389                })
19390                .ok()?;
19391            Some(())
19392        });
19393    }
19394
19395    fn on_buffer_event(
19396        &mut self,
19397        multibuffer: &Entity<MultiBuffer>,
19398        event: &multi_buffer::Event,
19399        window: &mut Window,
19400        cx: &mut Context<Self>,
19401    ) {
19402        match event {
19403            multi_buffer::Event::Edited {
19404                singleton_buffer_edited,
19405                edited_buffer,
19406            } => {
19407                self.scrollbar_marker_state.dirty = true;
19408                self.active_indent_guides_state.dirty = true;
19409                self.refresh_active_diagnostics(cx);
19410                self.refresh_code_actions(window, cx);
19411                self.refresh_selected_text_highlights(true, window, cx);
19412                refresh_matching_bracket_highlights(self, window, cx);
19413                if self.has_active_inline_completion() {
19414                    self.update_visible_inline_completion(window, cx);
19415                }
19416                if let Some(project) = self.project.as_ref() {
19417                    if let Some(edited_buffer) = edited_buffer {
19418                        project.update(cx, |project, cx| {
19419                            self.registered_buffers
19420                                .entry(edited_buffer.read(cx).remote_id())
19421                                .or_insert_with(|| {
19422                                    project
19423                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19424                                });
19425                        });
19426                    }
19427                }
19428                cx.emit(EditorEvent::BufferEdited);
19429                cx.emit(SearchEvent::MatchesInvalidated);
19430
19431                if let Some(buffer) = edited_buffer {
19432                    self.update_lsp_data(None, Some(buffer.read(cx).remote_id()), window, cx);
19433                }
19434
19435                if *singleton_buffer_edited {
19436                    if let Some(buffer) = edited_buffer {
19437                        if buffer.read(cx).file().is_none() {
19438                            cx.emit(EditorEvent::TitleChanged);
19439                        }
19440                    }
19441                    if let Some(project) = &self.project {
19442                        #[allow(clippy::mutable_key_type)]
19443                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19444                            multibuffer
19445                                .all_buffers()
19446                                .into_iter()
19447                                .filter_map(|buffer| {
19448                                    buffer.update(cx, |buffer, cx| {
19449                                        let language = buffer.language()?;
19450                                        let should_discard = project.update(cx, |project, cx| {
19451                                            project.is_local()
19452                                                && !project.has_language_servers_for(buffer, cx)
19453                                        });
19454                                        should_discard.not().then_some(language.clone())
19455                                    })
19456                                })
19457                                .collect::<HashSet<_>>()
19458                        });
19459                        if !languages_affected.is_empty() {
19460                            self.refresh_inlay_hints(
19461                                InlayHintRefreshReason::BufferEdited(languages_affected),
19462                                cx,
19463                            );
19464                        }
19465                    }
19466                }
19467
19468                let Some(project) = &self.project else { return };
19469                let (telemetry, is_via_ssh) = {
19470                    let project = project.read(cx);
19471                    let telemetry = project.client().telemetry().clone();
19472                    let is_via_ssh = project.is_via_ssh();
19473                    (telemetry, is_via_ssh)
19474                };
19475                refresh_linked_ranges(self, window, cx);
19476                telemetry.log_edit_event("editor", is_via_ssh);
19477            }
19478            multi_buffer::Event::ExcerptsAdded {
19479                buffer,
19480                predecessor,
19481                excerpts,
19482            } => {
19483                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19484                let buffer_id = buffer.read(cx).remote_id();
19485                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19486                    if let Some(project) = &self.project {
19487                        update_uncommitted_diff_for_buffer(
19488                            cx.entity(),
19489                            project,
19490                            [buffer.clone()],
19491                            self.buffer.clone(),
19492                            cx,
19493                        )
19494                        .detach();
19495                    }
19496                }
19497                self.update_lsp_data(None, Some(buffer_id), window, cx);
19498                cx.emit(EditorEvent::ExcerptsAdded {
19499                    buffer: buffer.clone(),
19500                    predecessor: *predecessor,
19501                    excerpts: excerpts.clone(),
19502                });
19503                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19504            }
19505            multi_buffer::Event::ExcerptsRemoved {
19506                ids,
19507                removed_buffer_ids,
19508            } => {
19509                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19510                let buffer = self.buffer.read(cx);
19511                self.registered_buffers
19512                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19513                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19514                cx.emit(EditorEvent::ExcerptsRemoved {
19515                    ids: ids.clone(),
19516                    removed_buffer_ids: removed_buffer_ids.clone(),
19517                });
19518            }
19519            multi_buffer::Event::ExcerptsEdited {
19520                excerpt_ids,
19521                buffer_ids,
19522            } => {
19523                self.display_map.update(cx, |map, cx| {
19524                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19525                });
19526                cx.emit(EditorEvent::ExcerptsEdited {
19527                    ids: excerpt_ids.clone(),
19528                });
19529            }
19530            multi_buffer::Event::ExcerptsExpanded { ids } => {
19531                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19532                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19533            }
19534            multi_buffer::Event::Reparsed(buffer_id) => {
19535                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19536                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19537
19538                cx.emit(EditorEvent::Reparsed(*buffer_id));
19539            }
19540            multi_buffer::Event::DiffHunksToggled => {
19541                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19542            }
19543            multi_buffer::Event::LanguageChanged(buffer_id) => {
19544                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19545                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19546                cx.emit(EditorEvent::Reparsed(*buffer_id));
19547                cx.notify();
19548            }
19549            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19550            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19551            multi_buffer::Event::FileHandleChanged
19552            | multi_buffer::Event::Reloaded
19553            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19554            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19555            multi_buffer::Event::DiagnosticsUpdated => {
19556                self.update_diagnostics_state(window, cx);
19557            }
19558            _ => {}
19559        };
19560    }
19561
19562    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19563        if !self.diagnostics_enabled() {
19564            return;
19565        }
19566        self.refresh_active_diagnostics(cx);
19567        self.refresh_inline_diagnostics(true, window, cx);
19568        self.scrollbar_marker_state.dirty = true;
19569        cx.notify();
19570    }
19571
19572    pub fn start_temporary_diff_override(&mut self) {
19573        self.load_diff_task.take();
19574        self.temporary_diff_override = true;
19575    }
19576
19577    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19578        self.temporary_diff_override = false;
19579        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19580        self.buffer.update(cx, |buffer, cx| {
19581            buffer.set_all_diff_hunks_collapsed(cx);
19582        });
19583
19584        if let Some(project) = self.project.clone() {
19585            self.load_diff_task = Some(
19586                update_uncommitted_diff_for_buffer(
19587                    cx.entity(),
19588                    &project,
19589                    self.buffer.read(cx).all_buffers(),
19590                    self.buffer.clone(),
19591                    cx,
19592                )
19593                .shared(),
19594            );
19595        }
19596    }
19597
19598    fn on_display_map_changed(
19599        &mut self,
19600        _: Entity<DisplayMap>,
19601        _: &mut Window,
19602        cx: &mut Context<Self>,
19603    ) {
19604        cx.notify();
19605    }
19606
19607    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19608        let new_severity = if self.diagnostics_enabled() {
19609            EditorSettings::get_global(cx)
19610                .diagnostics_max_severity
19611                .unwrap_or(DiagnosticSeverity::Hint)
19612        } else {
19613            DiagnosticSeverity::Off
19614        };
19615        self.set_max_diagnostics_severity(new_severity, cx);
19616        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19617        self.update_edit_prediction_settings(cx);
19618        self.refresh_inline_completion(true, false, window, cx);
19619        self.refresh_inlay_hints(
19620            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19621                self.selections.newest_anchor().head(),
19622                &self.buffer.read(cx).snapshot(cx),
19623                cx,
19624            )),
19625            cx,
19626        );
19627
19628        let old_cursor_shape = self.cursor_shape;
19629
19630        {
19631            let editor_settings = EditorSettings::get_global(cx);
19632            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19633            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19634            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19635            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19636            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19637        }
19638
19639        if old_cursor_shape != self.cursor_shape {
19640            cx.emit(EditorEvent::CursorShapeChanged);
19641        }
19642
19643        let project_settings = ProjectSettings::get_global(cx);
19644        self.serialize_dirty_buffers =
19645            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19646
19647        if self.mode.is_full() {
19648            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19649            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19650            if self.show_inline_diagnostics != show_inline_diagnostics {
19651                self.show_inline_diagnostics = show_inline_diagnostics;
19652                self.refresh_inline_diagnostics(false, window, cx);
19653            }
19654
19655            if self.git_blame_inline_enabled != inline_blame_enabled {
19656                self.toggle_git_blame_inline_internal(false, window, cx);
19657            }
19658
19659            let minimap_settings = EditorSettings::get_global(cx).minimap;
19660            if self.minimap_visibility != MinimapVisibility::Disabled {
19661                if self.minimap_visibility.settings_visibility()
19662                    != minimap_settings.minimap_enabled()
19663                {
19664                    self.set_minimap_visibility(
19665                        MinimapVisibility::for_mode(self.mode(), cx),
19666                        window,
19667                        cx,
19668                    );
19669                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19670                    minimap_entity.update(cx, |minimap_editor, cx| {
19671                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19672                    })
19673                }
19674            }
19675        }
19676
19677        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19678            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19679        }) {
19680            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19681                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19682            }
19683            self.refresh_colors(None, None, window, cx);
19684        }
19685
19686        cx.notify();
19687    }
19688
19689    pub fn set_searchable(&mut self, searchable: bool) {
19690        self.searchable = searchable;
19691    }
19692
19693    pub fn searchable(&self) -> bool {
19694        self.searchable
19695    }
19696
19697    fn open_proposed_changes_editor(
19698        &mut self,
19699        _: &OpenProposedChangesEditor,
19700        window: &mut Window,
19701        cx: &mut Context<Self>,
19702    ) {
19703        let Some(workspace) = self.workspace() else {
19704            cx.propagate();
19705            return;
19706        };
19707
19708        let selections = self.selections.all::<usize>(cx);
19709        let multi_buffer = self.buffer.read(cx);
19710        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19711        let mut new_selections_by_buffer = HashMap::default();
19712        for selection in selections {
19713            for (buffer, range, _) in
19714                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19715            {
19716                let mut range = range.to_point(buffer);
19717                range.start.column = 0;
19718                range.end.column = buffer.line_len(range.end.row);
19719                new_selections_by_buffer
19720                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19721                    .or_insert(Vec::new())
19722                    .push(range)
19723            }
19724        }
19725
19726        let proposed_changes_buffers = new_selections_by_buffer
19727            .into_iter()
19728            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19729            .collect::<Vec<_>>();
19730        let proposed_changes_editor = cx.new(|cx| {
19731            ProposedChangesEditor::new(
19732                "Proposed changes",
19733                proposed_changes_buffers,
19734                self.project.clone(),
19735                window,
19736                cx,
19737            )
19738        });
19739
19740        window.defer(cx, move |window, cx| {
19741            workspace.update(cx, |workspace, cx| {
19742                workspace.active_pane().update(cx, |pane, cx| {
19743                    pane.add_item(
19744                        Box::new(proposed_changes_editor),
19745                        true,
19746                        true,
19747                        None,
19748                        window,
19749                        cx,
19750                    );
19751                });
19752            });
19753        });
19754    }
19755
19756    pub fn open_excerpts_in_split(
19757        &mut self,
19758        _: &OpenExcerptsSplit,
19759        window: &mut Window,
19760        cx: &mut Context<Self>,
19761    ) {
19762        self.open_excerpts_common(None, true, window, cx)
19763    }
19764
19765    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19766        self.open_excerpts_common(None, false, window, cx)
19767    }
19768
19769    fn open_excerpts_common(
19770        &mut self,
19771        jump_data: Option<JumpData>,
19772        split: bool,
19773        window: &mut Window,
19774        cx: &mut Context<Self>,
19775    ) {
19776        let Some(workspace) = self.workspace() else {
19777            cx.propagate();
19778            return;
19779        };
19780
19781        if self.buffer.read(cx).is_singleton() {
19782            cx.propagate();
19783            return;
19784        }
19785
19786        let mut new_selections_by_buffer = HashMap::default();
19787        match &jump_data {
19788            Some(JumpData::MultiBufferPoint {
19789                excerpt_id,
19790                position,
19791                anchor,
19792                line_offset_from_top,
19793            }) => {
19794                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19795                if let Some(buffer) = multi_buffer_snapshot
19796                    .buffer_id_for_excerpt(*excerpt_id)
19797                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19798                {
19799                    let buffer_snapshot = buffer.read(cx).snapshot();
19800                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19801                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19802                    } else {
19803                        buffer_snapshot.clip_point(*position, Bias::Left)
19804                    };
19805                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19806                    new_selections_by_buffer.insert(
19807                        buffer,
19808                        (
19809                            vec![jump_to_offset..jump_to_offset],
19810                            Some(*line_offset_from_top),
19811                        ),
19812                    );
19813                }
19814            }
19815            Some(JumpData::MultiBufferRow {
19816                row,
19817                line_offset_from_top,
19818            }) => {
19819                let point = MultiBufferPoint::new(row.0, 0);
19820                if let Some((buffer, buffer_point, _)) =
19821                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19822                {
19823                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19824                    new_selections_by_buffer
19825                        .entry(buffer)
19826                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19827                        .0
19828                        .push(buffer_offset..buffer_offset)
19829                }
19830            }
19831            None => {
19832                let selections = self.selections.all::<usize>(cx);
19833                let multi_buffer = self.buffer.read(cx);
19834                for selection in selections {
19835                    for (snapshot, range, _, anchor) in multi_buffer
19836                        .snapshot(cx)
19837                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19838                    {
19839                        if let Some(anchor) = anchor {
19840                            // selection is in a deleted hunk
19841                            let Some(buffer_id) = anchor.buffer_id else {
19842                                continue;
19843                            };
19844                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19845                                continue;
19846                            };
19847                            let offset = text::ToOffset::to_offset(
19848                                &anchor.text_anchor,
19849                                &buffer_handle.read(cx).snapshot(),
19850                            );
19851                            let range = offset..offset;
19852                            new_selections_by_buffer
19853                                .entry(buffer_handle)
19854                                .or_insert((Vec::new(), None))
19855                                .0
19856                                .push(range)
19857                        } else {
19858                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19859                            else {
19860                                continue;
19861                            };
19862                            new_selections_by_buffer
19863                                .entry(buffer_handle)
19864                                .or_insert((Vec::new(), None))
19865                                .0
19866                                .push(range)
19867                        }
19868                    }
19869                }
19870            }
19871        }
19872
19873        new_selections_by_buffer
19874            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19875
19876        if new_selections_by_buffer.is_empty() {
19877            return;
19878        }
19879
19880        // We defer the pane interaction because we ourselves are a workspace item
19881        // and activating a new item causes the pane to call a method on us reentrantly,
19882        // which panics if we're on the stack.
19883        window.defer(cx, move |window, cx| {
19884            workspace.update(cx, |workspace, cx| {
19885                let pane = if split {
19886                    workspace.adjacent_pane(window, cx)
19887                } else {
19888                    workspace.active_pane().clone()
19889                };
19890
19891                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19892                    let editor = buffer
19893                        .read(cx)
19894                        .file()
19895                        .is_none()
19896                        .then(|| {
19897                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19898                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19899                            // Instead, we try to activate the existing editor in the pane first.
19900                            let (editor, pane_item_index) =
19901                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19902                                    let editor = item.downcast::<Editor>()?;
19903                                    let singleton_buffer =
19904                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19905                                    if singleton_buffer == buffer {
19906                                        Some((editor, i))
19907                                    } else {
19908                                        None
19909                                    }
19910                                })?;
19911                            pane.update(cx, |pane, cx| {
19912                                pane.activate_item(pane_item_index, true, true, window, cx)
19913                            });
19914                            Some(editor)
19915                        })
19916                        .flatten()
19917                        .unwrap_or_else(|| {
19918                            workspace.open_project_item::<Self>(
19919                                pane.clone(),
19920                                buffer,
19921                                true,
19922                                true,
19923                                window,
19924                                cx,
19925                            )
19926                        });
19927
19928                    editor.update(cx, |editor, cx| {
19929                        let autoscroll = match scroll_offset {
19930                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19931                            None => Autoscroll::newest(),
19932                        };
19933                        let nav_history = editor.nav_history.take();
19934                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19935                            s.select_ranges(ranges);
19936                        });
19937                        editor.nav_history = nav_history;
19938                    });
19939                }
19940            })
19941        });
19942    }
19943
19944    // For now, don't allow opening excerpts in buffers that aren't backed by
19945    // regular project files.
19946    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19947        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19948    }
19949
19950    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19951        let snapshot = self.buffer.read(cx).read(cx);
19952        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19953        Some(
19954            ranges
19955                .iter()
19956                .map(move |range| {
19957                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19958                })
19959                .collect(),
19960        )
19961    }
19962
19963    fn selection_replacement_ranges(
19964        &self,
19965        range: Range<OffsetUtf16>,
19966        cx: &mut App,
19967    ) -> Vec<Range<OffsetUtf16>> {
19968        let selections = self.selections.all::<OffsetUtf16>(cx);
19969        let newest_selection = selections
19970            .iter()
19971            .max_by_key(|selection| selection.id)
19972            .unwrap();
19973        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19974        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19975        let snapshot = self.buffer.read(cx).read(cx);
19976        selections
19977            .into_iter()
19978            .map(|mut selection| {
19979                selection.start.0 =
19980                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19981                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19982                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19983                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19984            })
19985            .collect()
19986    }
19987
19988    fn report_editor_event(
19989        &self,
19990        event_type: &'static str,
19991        file_extension: Option<String>,
19992        cx: &App,
19993    ) {
19994        if cfg!(any(test, feature = "test-support")) {
19995            return;
19996        }
19997
19998        let Some(project) = &self.project else { return };
19999
20000        // If None, we are in a file without an extension
20001        let file = self
20002            .buffer
20003            .read(cx)
20004            .as_singleton()
20005            .and_then(|b| b.read(cx).file());
20006        let file_extension = file_extension.or(file
20007            .as_ref()
20008            .and_then(|file| Path::new(file.file_name(cx)).extension())
20009            .and_then(|e| e.to_str())
20010            .map(|a| a.to_string()));
20011
20012        let vim_mode = vim_enabled(cx);
20013
20014        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20015        let copilot_enabled = edit_predictions_provider
20016            == language::language_settings::EditPredictionProvider::Copilot;
20017        let copilot_enabled_for_language = self
20018            .buffer
20019            .read(cx)
20020            .language_settings(cx)
20021            .show_edit_predictions;
20022
20023        let project = project.read(cx);
20024        telemetry::event!(
20025            event_type,
20026            file_extension,
20027            vim_mode,
20028            copilot_enabled,
20029            copilot_enabled_for_language,
20030            edit_predictions_provider,
20031            is_via_ssh = project.is_via_ssh(),
20032        );
20033    }
20034
20035    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20036    /// with each line being an array of {text, highlight} objects.
20037    fn copy_highlight_json(
20038        &mut self,
20039        _: &CopyHighlightJson,
20040        window: &mut Window,
20041        cx: &mut Context<Self>,
20042    ) {
20043        #[derive(Serialize)]
20044        struct Chunk<'a> {
20045            text: String,
20046            highlight: Option<&'a str>,
20047        }
20048
20049        let snapshot = self.buffer.read(cx).snapshot(cx);
20050        let range = self
20051            .selected_text_range(false, window, cx)
20052            .and_then(|selection| {
20053                if selection.range.is_empty() {
20054                    None
20055                } else {
20056                    Some(selection.range)
20057                }
20058            })
20059            .unwrap_or_else(|| 0..snapshot.len());
20060
20061        let chunks = snapshot.chunks(range, true);
20062        let mut lines = Vec::new();
20063        let mut line: VecDeque<Chunk> = VecDeque::new();
20064
20065        let Some(style) = self.style.as_ref() else {
20066            return;
20067        };
20068
20069        for chunk in chunks {
20070            let highlight = chunk
20071                .syntax_highlight_id
20072                .and_then(|id| id.name(&style.syntax));
20073            let mut chunk_lines = chunk.text.split('\n').peekable();
20074            while let Some(text) = chunk_lines.next() {
20075                let mut merged_with_last_token = false;
20076                if let Some(last_token) = line.back_mut() {
20077                    if last_token.highlight == highlight {
20078                        last_token.text.push_str(text);
20079                        merged_with_last_token = true;
20080                    }
20081                }
20082
20083                if !merged_with_last_token {
20084                    line.push_back(Chunk {
20085                        text: text.into(),
20086                        highlight,
20087                    });
20088                }
20089
20090                if chunk_lines.peek().is_some() {
20091                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20092                        line.pop_front();
20093                    }
20094                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20095                        line.pop_back();
20096                    }
20097
20098                    lines.push(mem::take(&mut line));
20099                }
20100            }
20101        }
20102
20103        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20104            return;
20105        };
20106        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20107    }
20108
20109    pub fn open_context_menu(
20110        &mut self,
20111        _: &OpenContextMenu,
20112        window: &mut Window,
20113        cx: &mut Context<Self>,
20114    ) {
20115        self.request_autoscroll(Autoscroll::newest(), cx);
20116        let position = self.selections.newest_display(cx).start;
20117        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20118    }
20119
20120    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20121        &self.inlay_hint_cache
20122    }
20123
20124    pub fn replay_insert_event(
20125        &mut self,
20126        text: &str,
20127        relative_utf16_range: Option<Range<isize>>,
20128        window: &mut Window,
20129        cx: &mut Context<Self>,
20130    ) {
20131        if !self.input_enabled {
20132            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20133            return;
20134        }
20135        if let Some(relative_utf16_range) = relative_utf16_range {
20136            let selections = self.selections.all::<OffsetUtf16>(cx);
20137            self.change_selections(None, window, cx, |s| {
20138                let new_ranges = selections.into_iter().map(|range| {
20139                    let start = OffsetUtf16(
20140                        range
20141                            .head()
20142                            .0
20143                            .saturating_add_signed(relative_utf16_range.start),
20144                    );
20145                    let end = OffsetUtf16(
20146                        range
20147                            .head()
20148                            .0
20149                            .saturating_add_signed(relative_utf16_range.end),
20150                    );
20151                    start..end
20152                });
20153                s.select_ranges(new_ranges);
20154            });
20155        }
20156
20157        self.handle_input(text, window, cx);
20158    }
20159
20160    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20161        let Some(provider) = self.semantics_provider.as_ref() else {
20162            return false;
20163        };
20164
20165        let mut supports = false;
20166        self.buffer().update(cx, |this, cx| {
20167            this.for_each_buffer(|buffer| {
20168                supports |= provider.supports_inlay_hints(buffer, cx);
20169            });
20170        });
20171
20172        supports
20173    }
20174
20175    pub fn is_focused(&self, window: &Window) -> bool {
20176        self.focus_handle.is_focused(window)
20177    }
20178
20179    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20180        cx.emit(EditorEvent::Focused);
20181
20182        if let Some(descendant) = self
20183            .last_focused_descendant
20184            .take()
20185            .and_then(|descendant| descendant.upgrade())
20186        {
20187            window.focus(&descendant);
20188        } else {
20189            if let Some(blame) = self.blame.as_ref() {
20190                blame.update(cx, GitBlame::focus)
20191            }
20192
20193            self.blink_manager.update(cx, BlinkManager::enable);
20194            self.show_cursor_names(window, cx);
20195            self.buffer.update(cx, |buffer, cx| {
20196                buffer.finalize_last_transaction(cx);
20197                if self.leader_id.is_none() {
20198                    buffer.set_active_selections(
20199                        &self.selections.disjoint_anchors(),
20200                        self.selections.line_mode,
20201                        self.cursor_shape,
20202                        cx,
20203                    );
20204                }
20205            });
20206        }
20207    }
20208
20209    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20210        cx.emit(EditorEvent::FocusedIn)
20211    }
20212
20213    fn handle_focus_out(
20214        &mut self,
20215        event: FocusOutEvent,
20216        _window: &mut Window,
20217        cx: &mut Context<Self>,
20218    ) {
20219        if event.blurred != self.focus_handle {
20220            self.last_focused_descendant = Some(event.blurred);
20221        }
20222        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20223    }
20224
20225    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20226        self.blink_manager.update(cx, BlinkManager::disable);
20227        self.buffer
20228            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20229
20230        if let Some(blame) = self.blame.as_ref() {
20231            blame.update(cx, GitBlame::blur)
20232        }
20233        if !self.hover_state.focused(window, cx) {
20234            hide_hover(self, cx);
20235        }
20236        if !self
20237            .context_menu
20238            .borrow()
20239            .as_ref()
20240            .is_some_and(|context_menu| context_menu.focused(window, cx))
20241        {
20242            self.hide_context_menu(window, cx);
20243        }
20244        self.discard_inline_completion(false, cx);
20245        cx.emit(EditorEvent::Blurred);
20246        cx.notify();
20247    }
20248
20249    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20250        let mut pending: String = window
20251            .pending_input_keystrokes()
20252            .into_iter()
20253            .flatten()
20254            .filter_map(|keystroke| {
20255                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20256                    keystroke.key_char.clone()
20257                } else {
20258                    None
20259                }
20260            })
20261            .collect();
20262
20263        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20264            pending = "".to_string();
20265        }
20266
20267        let existing_pending = self
20268            .text_highlights::<PendingInput>(cx)
20269            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20270        if existing_pending.is_none() && pending.is_empty() {
20271            return;
20272        }
20273        let transaction =
20274            self.transact(window, cx, |this, window, cx| {
20275                let selections = this.selections.all::<usize>(cx);
20276                let edits = selections
20277                    .iter()
20278                    .map(|selection| (selection.end..selection.end, pending.clone()));
20279                this.edit(edits, cx);
20280                this.change_selections(None, window, cx, |s| {
20281                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20282                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20283                    }));
20284                });
20285                if let Some(existing_ranges) = existing_pending {
20286                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20287                    this.edit(edits, cx);
20288                }
20289            });
20290
20291        let snapshot = self.snapshot(window, cx);
20292        let ranges = self
20293            .selections
20294            .all::<usize>(cx)
20295            .into_iter()
20296            .map(|selection| {
20297                snapshot.buffer_snapshot.anchor_after(selection.end)
20298                    ..snapshot
20299                        .buffer_snapshot
20300                        .anchor_before(selection.end + pending.len())
20301            })
20302            .collect();
20303
20304        if pending.is_empty() {
20305            self.clear_highlights::<PendingInput>(cx);
20306        } else {
20307            self.highlight_text::<PendingInput>(
20308                ranges,
20309                HighlightStyle {
20310                    underline: Some(UnderlineStyle {
20311                        thickness: px(1.),
20312                        color: None,
20313                        wavy: false,
20314                    }),
20315                    ..Default::default()
20316                },
20317                cx,
20318            );
20319        }
20320
20321        self.ime_transaction = self.ime_transaction.or(transaction);
20322        if let Some(transaction) = self.ime_transaction {
20323            self.buffer.update(cx, |buffer, cx| {
20324                buffer.group_until_transaction(transaction, cx);
20325            });
20326        }
20327
20328        if self.text_highlights::<PendingInput>(cx).is_none() {
20329            self.ime_transaction.take();
20330        }
20331    }
20332
20333    pub fn register_action_renderer(
20334        &mut self,
20335        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20336    ) -> Subscription {
20337        let id = self.next_editor_action_id.post_inc();
20338        self.editor_actions
20339            .borrow_mut()
20340            .insert(id, Box::new(listener));
20341
20342        let editor_actions = self.editor_actions.clone();
20343        Subscription::new(move || {
20344            editor_actions.borrow_mut().remove(&id);
20345        })
20346    }
20347
20348    pub fn register_action<A: Action>(
20349        &mut self,
20350        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20351    ) -> Subscription {
20352        let id = self.next_editor_action_id.post_inc();
20353        let listener = Arc::new(listener);
20354        self.editor_actions.borrow_mut().insert(
20355            id,
20356            Box::new(move |_, window, _| {
20357                let listener = listener.clone();
20358                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20359                    let action = action.downcast_ref().unwrap();
20360                    if phase == DispatchPhase::Bubble {
20361                        listener(action, window, cx)
20362                    }
20363                })
20364            }),
20365        );
20366
20367        let editor_actions = self.editor_actions.clone();
20368        Subscription::new(move || {
20369            editor_actions.borrow_mut().remove(&id);
20370        })
20371    }
20372
20373    pub fn file_header_size(&self) -> u32 {
20374        FILE_HEADER_HEIGHT
20375    }
20376
20377    pub fn restore(
20378        &mut self,
20379        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20380        window: &mut Window,
20381        cx: &mut Context<Self>,
20382    ) {
20383        let workspace = self.workspace();
20384        let project = self.project.as_ref();
20385        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20386            let mut tasks = Vec::new();
20387            for (buffer_id, changes) in revert_changes {
20388                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20389                    buffer.update(cx, |buffer, cx| {
20390                        buffer.edit(
20391                            changes
20392                                .into_iter()
20393                                .map(|(range, text)| (range, text.to_string())),
20394                            None,
20395                            cx,
20396                        );
20397                    });
20398
20399                    if let Some(project) =
20400                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20401                    {
20402                        project.update(cx, |project, cx| {
20403                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20404                        })
20405                    }
20406                }
20407            }
20408            tasks
20409        });
20410        cx.spawn_in(window, async move |_, cx| {
20411            for (buffer, task) in save_tasks {
20412                let result = task.await;
20413                if result.is_err() {
20414                    let Some(path) = buffer
20415                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20416                        .ok()
20417                    else {
20418                        continue;
20419                    };
20420                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20421                        let Some(task) = cx
20422                            .update_window_entity(&workspace, |workspace, window, cx| {
20423                                workspace
20424                                    .open_path_preview(path, None, false, false, false, window, cx)
20425                            })
20426                            .ok()
20427                        else {
20428                            continue;
20429                        };
20430                        task.await.log_err();
20431                    }
20432                }
20433            }
20434        })
20435        .detach();
20436        self.change_selections(None, window, cx, |selections| selections.refresh());
20437    }
20438
20439    pub fn to_pixel_point(
20440        &self,
20441        source: multi_buffer::Anchor,
20442        editor_snapshot: &EditorSnapshot,
20443        window: &mut Window,
20444    ) -> Option<gpui::Point<Pixels>> {
20445        let source_point = source.to_display_point(editor_snapshot);
20446        self.display_to_pixel_point(source_point, editor_snapshot, window)
20447    }
20448
20449    pub fn display_to_pixel_point(
20450        &self,
20451        source: DisplayPoint,
20452        editor_snapshot: &EditorSnapshot,
20453        window: &mut Window,
20454    ) -> Option<gpui::Point<Pixels>> {
20455        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20456        let text_layout_details = self.text_layout_details(window);
20457        let scroll_top = text_layout_details
20458            .scroll_anchor
20459            .scroll_position(editor_snapshot)
20460            .y;
20461
20462        if source.row().as_f32() < scroll_top.floor() {
20463            return None;
20464        }
20465        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20466        let source_y = line_height * (source.row().as_f32() - scroll_top);
20467        Some(gpui::Point::new(source_x, source_y))
20468    }
20469
20470    pub fn has_visible_completions_menu(&self) -> bool {
20471        !self.edit_prediction_preview_is_active()
20472            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20473                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20474            })
20475    }
20476
20477    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20478        if self.mode.is_minimap() {
20479            return;
20480        }
20481        self.addons
20482            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20483    }
20484
20485    pub fn unregister_addon<T: Addon>(&mut self) {
20486        self.addons.remove(&std::any::TypeId::of::<T>());
20487    }
20488
20489    pub fn addon<T: Addon>(&self) -> Option<&T> {
20490        let type_id = std::any::TypeId::of::<T>();
20491        self.addons
20492            .get(&type_id)
20493            .and_then(|item| item.to_any().downcast_ref::<T>())
20494    }
20495
20496    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20497        let type_id = std::any::TypeId::of::<T>();
20498        self.addons
20499            .get_mut(&type_id)
20500            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20501    }
20502
20503    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20504        let text_layout_details = self.text_layout_details(window);
20505        let style = &text_layout_details.editor_style;
20506        let font_id = window.text_system().resolve_font(&style.text.font());
20507        let font_size = style.text.font_size.to_pixels(window.rem_size());
20508        let line_height = style.text.line_height_in_pixels(window.rem_size());
20509        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20510
20511        gpui::Size::new(em_width, line_height)
20512    }
20513
20514    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20515        self.load_diff_task.clone()
20516    }
20517
20518    fn read_metadata_from_db(
20519        &mut self,
20520        item_id: u64,
20521        workspace_id: WorkspaceId,
20522        window: &mut Window,
20523        cx: &mut Context<Editor>,
20524    ) {
20525        if self.is_singleton(cx)
20526            && !self.mode.is_minimap()
20527            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20528        {
20529            let buffer_snapshot = OnceCell::new();
20530
20531            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20532                if !folds.is_empty() {
20533                    let snapshot =
20534                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20535                    self.fold_ranges(
20536                        folds
20537                            .into_iter()
20538                            .map(|(start, end)| {
20539                                snapshot.clip_offset(start, Bias::Left)
20540                                    ..snapshot.clip_offset(end, Bias::Right)
20541                            })
20542                            .collect(),
20543                        false,
20544                        window,
20545                        cx,
20546                    );
20547                }
20548            }
20549
20550            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20551                if !selections.is_empty() {
20552                    let snapshot =
20553                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20554                    // skip adding the initial selection to selection history
20555                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20556                    self.change_selections(None, window, cx, |s| {
20557                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20558                            snapshot.clip_offset(start, Bias::Left)
20559                                ..snapshot.clip_offset(end, Bias::Right)
20560                        }));
20561                    });
20562                    self.selection_history.mode = SelectionHistoryMode::Normal;
20563                }
20564            };
20565        }
20566
20567        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20568    }
20569
20570    fn update_lsp_data(
20571        &mut self,
20572        for_server_id: Option<LanguageServerId>,
20573        for_buffer: Option<BufferId>,
20574        window: &mut Window,
20575        cx: &mut Context<'_, Self>,
20576    ) {
20577        self.pull_diagnostics(for_buffer, window, cx);
20578        self.refresh_colors(for_server_id, for_buffer, window, cx);
20579    }
20580}
20581
20582fn vim_enabled(cx: &App) -> bool {
20583    cx.global::<SettingsStore>()
20584        .raw_user_settings()
20585        .get("vim_mode")
20586        == Some(&serde_json::Value::Bool(true))
20587}
20588
20589fn process_completion_for_edit(
20590    completion: &Completion,
20591    intent: CompletionIntent,
20592    buffer: &Entity<Buffer>,
20593    cursor_position: &text::Anchor,
20594    cx: &mut Context<Editor>,
20595) -> CompletionEdit {
20596    let buffer = buffer.read(cx);
20597    let buffer_snapshot = buffer.snapshot();
20598    let (snippet, new_text) = if completion.is_snippet() {
20599        // Workaround for typescript language server issues so that methods don't expand within
20600        // strings and functions with type expressions. The previous point is used because the query
20601        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20602        let mut snippet_source = completion.new_text.clone();
20603        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20604        previous_point.column = previous_point.column.saturating_sub(1);
20605        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20606            if scope.prefers_label_for_snippet_in_completion() {
20607                if let Some(label) = completion.label() {
20608                    if matches!(
20609                        completion.kind(),
20610                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20611                    ) {
20612                        snippet_source = label;
20613                    }
20614                }
20615            }
20616        }
20617        match Snippet::parse(&snippet_source).log_err() {
20618            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20619            None => (None, completion.new_text.clone()),
20620        }
20621    } else {
20622        (None, completion.new_text.clone())
20623    };
20624
20625    let mut range_to_replace = {
20626        let replace_range = &completion.replace_range;
20627        if let CompletionSource::Lsp {
20628            insert_range: Some(insert_range),
20629            ..
20630        } = &completion.source
20631        {
20632            debug_assert_eq!(
20633                insert_range.start, replace_range.start,
20634                "insert_range and replace_range should start at the same position"
20635            );
20636            debug_assert!(
20637                insert_range
20638                    .start
20639                    .cmp(&cursor_position, &buffer_snapshot)
20640                    .is_le(),
20641                "insert_range should start before or at cursor position"
20642            );
20643            debug_assert!(
20644                replace_range
20645                    .start
20646                    .cmp(&cursor_position, &buffer_snapshot)
20647                    .is_le(),
20648                "replace_range should start before or at cursor position"
20649            );
20650            debug_assert!(
20651                insert_range
20652                    .end
20653                    .cmp(&cursor_position, &buffer_snapshot)
20654                    .is_le(),
20655                "insert_range should end before or at cursor position"
20656            );
20657
20658            let should_replace = match intent {
20659                CompletionIntent::CompleteWithInsert => false,
20660                CompletionIntent::CompleteWithReplace => true,
20661                CompletionIntent::Complete | CompletionIntent::Compose => {
20662                    let insert_mode =
20663                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20664                            .completions
20665                            .lsp_insert_mode;
20666                    match insert_mode {
20667                        LspInsertMode::Insert => false,
20668                        LspInsertMode::Replace => true,
20669                        LspInsertMode::ReplaceSubsequence => {
20670                            let mut text_to_replace = buffer.chars_for_range(
20671                                buffer.anchor_before(replace_range.start)
20672                                    ..buffer.anchor_after(replace_range.end),
20673                            );
20674                            let mut current_needle = text_to_replace.next();
20675                            for haystack_ch in completion.label.text.chars() {
20676                                if let Some(needle_ch) = current_needle {
20677                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20678                                        current_needle = text_to_replace.next();
20679                                    }
20680                                }
20681                            }
20682                            current_needle.is_none()
20683                        }
20684                        LspInsertMode::ReplaceSuffix => {
20685                            if replace_range
20686                                .end
20687                                .cmp(&cursor_position, &buffer_snapshot)
20688                                .is_gt()
20689                            {
20690                                let range_after_cursor = *cursor_position..replace_range.end;
20691                                let text_after_cursor = buffer
20692                                    .text_for_range(
20693                                        buffer.anchor_before(range_after_cursor.start)
20694                                            ..buffer.anchor_after(range_after_cursor.end),
20695                                    )
20696                                    .collect::<String>()
20697                                    .to_ascii_lowercase();
20698                                completion
20699                                    .label
20700                                    .text
20701                                    .to_ascii_lowercase()
20702                                    .ends_with(&text_after_cursor)
20703                            } else {
20704                                true
20705                            }
20706                        }
20707                    }
20708                }
20709            };
20710
20711            if should_replace {
20712                replace_range.clone()
20713            } else {
20714                insert_range.clone()
20715            }
20716        } else {
20717            replace_range.clone()
20718        }
20719    };
20720
20721    if range_to_replace
20722        .end
20723        .cmp(&cursor_position, &buffer_snapshot)
20724        .is_lt()
20725    {
20726        range_to_replace.end = *cursor_position;
20727    }
20728
20729    CompletionEdit {
20730        new_text,
20731        replace_range: range_to_replace.to_offset(&buffer),
20732        snippet,
20733    }
20734}
20735
20736struct CompletionEdit {
20737    new_text: String,
20738    replace_range: Range<usize>,
20739    snippet: Option<Snippet>,
20740}
20741
20742fn insert_extra_newline_brackets(
20743    buffer: &MultiBufferSnapshot,
20744    range: Range<usize>,
20745    language: &language::LanguageScope,
20746) -> bool {
20747    let leading_whitespace_len = buffer
20748        .reversed_chars_at(range.start)
20749        .take_while(|c| c.is_whitespace() && *c != '\n')
20750        .map(|c| c.len_utf8())
20751        .sum::<usize>();
20752    let trailing_whitespace_len = buffer
20753        .chars_at(range.end)
20754        .take_while(|c| c.is_whitespace() && *c != '\n')
20755        .map(|c| c.len_utf8())
20756        .sum::<usize>();
20757    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20758
20759    language.brackets().any(|(pair, enabled)| {
20760        let pair_start = pair.start.trim_end();
20761        let pair_end = pair.end.trim_start();
20762
20763        enabled
20764            && pair.newline
20765            && buffer.contains_str_at(range.end, pair_end)
20766            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20767    })
20768}
20769
20770fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20771    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20772        [(buffer, range, _)] => (*buffer, range.clone()),
20773        _ => return false,
20774    };
20775    let pair = {
20776        let mut result: Option<BracketMatch> = None;
20777
20778        for pair in buffer
20779            .all_bracket_ranges(range.clone())
20780            .filter(move |pair| {
20781                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20782            })
20783        {
20784            let len = pair.close_range.end - pair.open_range.start;
20785
20786            if let Some(existing) = &result {
20787                let existing_len = existing.close_range.end - existing.open_range.start;
20788                if len > existing_len {
20789                    continue;
20790                }
20791            }
20792
20793            result = Some(pair);
20794        }
20795
20796        result
20797    };
20798    let Some(pair) = pair else {
20799        return false;
20800    };
20801    pair.newline_only
20802        && buffer
20803            .chars_for_range(pair.open_range.end..range.start)
20804            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20805            .all(|c| c.is_whitespace() && c != '\n')
20806}
20807
20808fn update_uncommitted_diff_for_buffer(
20809    editor: Entity<Editor>,
20810    project: &Entity<Project>,
20811    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20812    buffer: Entity<MultiBuffer>,
20813    cx: &mut App,
20814) -> Task<()> {
20815    let mut tasks = Vec::new();
20816    project.update(cx, |project, cx| {
20817        for buffer in buffers {
20818            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20819                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20820            }
20821        }
20822    });
20823    cx.spawn(async move |cx| {
20824        let diffs = future::join_all(tasks).await;
20825        if editor
20826            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20827            .unwrap_or(false)
20828        {
20829            return;
20830        }
20831
20832        buffer
20833            .update(cx, |buffer, cx| {
20834                for diff in diffs.into_iter().flatten() {
20835                    buffer.add_diff(diff, cx);
20836                }
20837            })
20838            .ok();
20839    })
20840}
20841
20842fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20843    let tab_size = tab_size.get() as usize;
20844    let mut width = offset;
20845
20846    for ch in text.chars() {
20847        width += if ch == '\t' {
20848            tab_size - (width % tab_size)
20849        } else {
20850            1
20851        };
20852    }
20853
20854    width - offset
20855}
20856
20857#[cfg(test)]
20858mod tests {
20859    use super::*;
20860
20861    #[test]
20862    fn test_string_size_with_expanded_tabs() {
20863        let nz = |val| NonZeroU32::new(val).unwrap();
20864        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20865        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20866        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20867        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20868        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20869        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20870        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20871        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20872    }
20873}
20874
20875/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20876struct WordBreakingTokenizer<'a> {
20877    input: &'a str,
20878}
20879
20880impl<'a> WordBreakingTokenizer<'a> {
20881    fn new(input: &'a str) -> Self {
20882        Self { input }
20883    }
20884}
20885
20886fn is_char_ideographic(ch: char) -> bool {
20887    use unicode_script::Script::*;
20888    use unicode_script::UnicodeScript;
20889    matches!(ch.script(), Han | Tangut | Yi)
20890}
20891
20892fn is_grapheme_ideographic(text: &str) -> bool {
20893    text.chars().any(is_char_ideographic)
20894}
20895
20896fn is_grapheme_whitespace(text: &str) -> bool {
20897    text.chars().any(|x| x.is_whitespace())
20898}
20899
20900fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20901    text.chars().next().map_or(false, |ch| {
20902        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20903    })
20904}
20905
20906#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20907enum WordBreakToken<'a> {
20908    Word { token: &'a str, grapheme_len: usize },
20909    InlineWhitespace { token: &'a str, grapheme_len: usize },
20910    Newline,
20911}
20912
20913impl<'a> Iterator for WordBreakingTokenizer<'a> {
20914    /// Yields a span, the count of graphemes in the token, and whether it was
20915    /// whitespace. Note that it also breaks at word boundaries.
20916    type Item = WordBreakToken<'a>;
20917
20918    fn next(&mut self) -> Option<Self::Item> {
20919        use unicode_segmentation::UnicodeSegmentation;
20920        if self.input.is_empty() {
20921            return None;
20922        }
20923
20924        let mut iter = self.input.graphemes(true).peekable();
20925        let mut offset = 0;
20926        let mut grapheme_len = 0;
20927        if let Some(first_grapheme) = iter.next() {
20928            let is_newline = first_grapheme == "\n";
20929            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20930            offset += first_grapheme.len();
20931            grapheme_len += 1;
20932            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20933                if let Some(grapheme) = iter.peek().copied() {
20934                    if should_stay_with_preceding_ideograph(grapheme) {
20935                        offset += grapheme.len();
20936                        grapheme_len += 1;
20937                    }
20938                }
20939            } else {
20940                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20941                let mut next_word_bound = words.peek().copied();
20942                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20943                    next_word_bound = words.next();
20944                }
20945                while let Some(grapheme) = iter.peek().copied() {
20946                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20947                        break;
20948                    };
20949                    if is_grapheme_whitespace(grapheme) != is_whitespace
20950                        || (grapheme == "\n") != is_newline
20951                    {
20952                        break;
20953                    };
20954                    offset += grapheme.len();
20955                    grapheme_len += 1;
20956                    iter.next();
20957                }
20958            }
20959            let token = &self.input[..offset];
20960            self.input = &self.input[offset..];
20961            if token == "\n" {
20962                Some(WordBreakToken::Newline)
20963            } else if is_whitespace {
20964                Some(WordBreakToken::InlineWhitespace {
20965                    token,
20966                    grapheme_len,
20967                })
20968            } else {
20969                Some(WordBreakToken::Word {
20970                    token,
20971                    grapheme_len,
20972                })
20973            }
20974        } else {
20975            None
20976        }
20977    }
20978}
20979
20980#[test]
20981fn test_word_breaking_tokenizer() {
20982    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20983        ("", &[]),
20984        ("  ", &[whitespace("  ", 2)]),
20985        ("Ʒ", &[word("Ʒ", 1)]),
20986        ("Ǽ", &[word("Ǽ", 1)]),
20987        ("", &[word("", 1)]),
20988        ("⋑⋑", &[word("⋑⋑", 2)]),
20989        (
20990            "原理,进而",
20991            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20992        ),
20993        (
20994            "hello world",
20995            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20996        ),
20997        (
20998            "hello, world",
20999            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21000        ),
21001        (
21002            "  hello world",
21003            &[
21004                whitespace("  ", 2),
21005                word("hello", 5),
21006                whitespace(" ", 1),
21007                word("world", 5),
21008            ],
21009        ),
21010        (
21011            "这是什么 \n 钢笔",
21012            &[
21013                word("", 1),
21014                word("", 1),
21015                word("", 1),
21016                word("", 1),
21017                whitespace(" ", 1),
21018                newline(),
21019                whitespace(" ", 1),
21020                word("", 1),
21021                word("", 1),
21022            ],
21023        ),
21024        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21025    ];
21026
21027    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21028        WordBreakToken::Word {
21029            token,
21030            grapheme_len,
21031        }
21032    }
21033
21034    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21035        WordBreakToken::InlineWhitespace {
21036            token,
21037            grapheme_len,
21038        }
21039    }
21040
21041    fn newline() -> WordBreakToken<'static> {
21042        WordBreakToken::Newline
21043    }
21044
21045    for (input, result) in tests {
21046        assert_eq!(
21047            WordBreakingTokenizer::new(input)
21048                .collect::<Vec<_>>()
21049                .as_slice(),
21050            *result,
21051        );
21052    }
21053}
21054
21055fn wrap_with_prefix(
21056    line_prefix: String,
21057    unwrapped_text: String,
21058    wrap_column: usize,
21059    tab_size: NonZeroU32,
21060    preserve_existing_whitespace: bool,
21061) -> String {
21062    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
21063    let mut wrapped_text = String::new();
21064    let mut current_line = line_prefix.clone();
21065
21066    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21067    let mut current_line_len = line_prefix_len;
21068    let mut in_whitespace = false;
21069    for token in tokenizer {
21070        let have_preceding_whitespace = in_whitespace;
21071        match token {
21072            WordBreakToken::Word {
21073                token,
21074                grapheme_len,
21075            } => {
21076                in_whitespace = false;
21077                if current_line_len + grapheme_len > wrap_column
21078                    && current_line_len != line_prefix_len
21079                {
21080                    wrapped_text.push_str(current_line.trim_end());
21081                    wrapped_text.push('\n');
21082                    current_line.truncate(line_prefix.len());
21083                    current_line_len = line_prefix_len;
21084                }
21085                current_line.push_str(token);
21086                current_line_len += grapheme_len;
21087            }
21088            WordBreakToken::InlineWhitespace {
21089                mut token,
21090                mut grapheme_len,
21091            } => {
21092                in_whitespace = true;
21093                if have_preceding_whitespace && !preserve_existing_whitespace {
21094                    continue;
21095                }
21096                if !preserve_existing_whitespace {
21097                    token = " ";
21098                    grapheme_len = 1;
21099                }
21100                if current_line_len + grapheme_len > wrap_column {
21101                    wrapped_text.push_str(current_line.trim_end());
21102                    wrapped_text.push('\n');
21103                    current_line.truncate(line_prefix.len());
21104                    current_line_len = line_prefix_len;
21105                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
21106                    current_line.push_str(token);
21107                    current_line_len += grapheme_len;
21108                }
21109            }
21110            WordBreakToken::Newline => {
21111                in_whitespace = true;
21112                if preserve_existing_whitespace {
21113                    wrapped_text.push_str(current_line.trim_end());
21114                    wrapped_text.push('\n');
21115                    current_line.truncate(line_prefix.len());
21116                    current_line_len = line_prefix_len;
21117                } else if have_preceding_whitespace {
21118                    continue;
21119                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
21120                {
21121                    wrapped_text.push_str(current_line.trim_end());
21122                    wrapped_text.push('\n');
21123                    current_line.truncate(line_prefix.len());
21124                    current_line_len = line_prefix_len;
21125                } else if current_line_len != line_prefix_len {
21126                    current_line.push(' ');
21127                    current_line_len += 1;
21128                }
21129            }
21130        }
21131    }
21132
21133    if !current_line.is_empty() {
21134        wrapped_text.push_str(&current_line);
21135    }
21136    wrapped_text
21137}
21138
21139#[test]
21140fn test_wrap_with_prefix() {
21141    assert_eq!(
21142        wrap_with_prefix(
21143            "# ".to_string(),
21144            "abcdefg".to_string(),
21145            4,
21146            NonZeroU32::new(4).unwrap(),
21147            false,
21148        ),
21149        "# abcdefg"
21150    );
21151    assert_eq!(
21152        wrap_with_prefix(
21153            "".to_string(),
21154            "\thello world".to_string(),
21155            8,
21156            NonZeroU32::new(4).unwrap(),
21157            false,
21158        ),
21159        "hello\nworld"
21160    );
21161    assert_eq!(
21162        wrap_with_prefix(
21163            "// ".to_string(),
21164            "xx \nyy zz aa bb cc".to_string(),
21165            12,
21166            NonZeroU32::new(4).unwrap(),
21167            false,
21168        ),
21169        "// xx yy zz\n// aa bb cc"
21170    );
21171    assert_eq!(
21172        wrap_with_prefix(
21173            String::new(),
21174            "这是什么 \n 钢笔".to_string(),
21175            3,
21176            NonZeroU32::new(4).unwrap(),
21177            false,
21178        ),
21179        "这是什\n么 钢\n"
21180    );
21181}
21182
21183pub trait CollaborationHub {
21184    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21185    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21186    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21187}
21188
21189impl CollaborationHub for Entity<Project> {
21190    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21191        self.read(cx).collaborators()
21192    }
21193
21194    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21195        self.read(cx).user_store().read(cx).participant_indices()
21196    }
21197
21198    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21199        let this = self.read(cx);
21200        let user_ids = this.collaborators().values().map(|c| c.user_id);
21201        this.user_store().read(cx).participant_names(user_ids, cx)
21202    }
21203}
21204
21205pub trait SemanticsProvider {
21206    fn hover(
21207        &self,
21208        buffer: &Entity<Buffer>,
21209        position: text::Anchor,
21210        cx: &mut App,
21211    ) -> Option<Task<Vec<project::Hover>>>;
21212
21213    fn inline_values(
21214        &self,
21215        buffer_handle: Entity<Buffer>,
21216        range: Range<text::Anchor>,
21217        cx: &mut App,
21218    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21219
21220    fn inlay_hints(
21221        &self,
21222        buffer_handle: Entity<Buffer>,
21223        range: Range<text::Anchor>,
21224        cx: &mut App,
21225    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21226
21227    fn resolve_inlay_hint(
21228        &self,
21229        hint: InlayHint,
21230        buffer_handle: Entity<Buffer>,
21231        server_id: LanguageServerId,
21232        cx: &mut App,
21233    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21234
21235    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21236
21237    fn document_highlights(
21238        &self,
21239        buffer: &Entity<Buffer>,
21240        position: text::Anchor,
21241        cx: &mut App,
21242    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21243
21244    fn definitions(
21245        &self,
21246        buffer: &Entity<Buffer>,
21247        position: text::Anchor,
21248        kind: GotoDefinitionKind,
21249        cx: &mut App,
21250    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21251
21252    fn range_for_rename(
21253        &self,
21254        buffer: &Entity<Buffer>,
21255        position: text::Anchor,
21256        cx: &mut App,
21257    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21258
21259    fn perform_rename(
21260        &self,
21261        buffer: &Entity<Buffer>,
21262        position: text::Anchor,
21263        new_name: String,
21264        cx: &mut App,
21265    ) -> Option<Task<Result<ProjectTransaction>>>;
21266}
21267
21268pub trait CompletionProvider {
21269    fn completions(
21270        &self,
21271        excerpt_id: ExcerptId,
21272        buffer: &Entity<Buffer>,
21273        buffer_position: text::Anchor,
21274        trigger: CompletionContext,
21275        window: &mut Window,
21276        cx: &mut Context<Editor>,
21277    ) -> Task<Result<Vec<CompletionResponse>>>;
21278
21279    fn resolve_completions(
21280        &self,
21281        _buffer: Entity<Buffer>,
21282        _completion_indices: Vec<usize>,
21283        _completions: Rc<RefCell<Box<[Completion]>>>,
21284        _cx: &mut Context<Editor>,
21285    ) -> Task<Result<bool>> {
21286        Task::ready(Ok(false))
21287    }
21288
21289    fn apply_additional_edits_for_completion(
21290        &self,
21291        _buffer: Entity<Buffer>,
21292        _completions: Rc<RefCell<Box<[Completion]>>>,
21293        _completion_index: usize,
21294        _push_to_history: bool,
21295        _cx: &mut Context<Editor>,
21296    ) -> Task<Result<Option<language::Transaction>>> {
21297        Task::ready(Ok(None))
21298    }
21299
21300    fn is_completion_trigger(
21301        &self,
21302        buffer: &Entity<Buffer>,
21303        position: language::Anchor,
21304        text: &str,
21305        trigger_in_words: bool,
21306        menu_is_open: bool,
21307        cx: &mut Context<Editor>,
21308    ) -> bool;
21309
21310    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21311
21312    fn sort_completions(&self) -> bool {
21313        true
21314    }
21315
21316    fn filter_completions(&self) -> bool {
21317        true
21318    }
21319}
21320
21321pub trait CodeActionProvider {
21322    fn id(&self) -> Arc<str>;
21323
21324    fn code_actions(
21325        &self,
21326        buffer: &Entity<Buffer>,
21327        range: Range<text::Anchor>,
21328        window: &mut Window,
21329        cx: &mut App,
21330    ) -> Task<Result<Vec<CodeAction>>>;
21331
21332    fn apply_code_action(
21333        &self,
21334        buffer_handle: Entity<Buffer>,
21335        action: CodeAction,
21336        excerpt_id: ExcerptId,
21337        push_to_history: bool,
21338        window: &mut Window,
21339        cx: &mut App,
21340    ) -> Task<Result<ProjectTransaction>>;
21341}
21342
21343impl CodeActionProvider for Entity<Project> {
21344    fn id(&self) -> Arc<str> {
21345        "project".into()
21346    }
21347
21348    fn code_actions(
21349        &self,
21350        buffer: &Entity<Buffer>,
21351        range: Range<text::Anchor>,
21352        _window: &mut Window,
21353        cx: &mut App,
21354    ) -> Task<Result<Vec<CodeAction>>> {
21355        self.update(cx, |project, cx| {
21356            let code_lens = project.code_lens(buffer, range.clone(), cx);
21357            let code_actions = project.code_actions(buffer, range, None, cx);
21358            cx.background_spawn(async move {
21359                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21360                Ok(code_lens
21361                    .context("code lens fetch")?
21362                    .into_iter()
21363                    .chain(code_actions.context("code action fetch")?)
21364                    .collect())
21365            })
21366        })
21367    }
21368
21369    fn apply_code_action(
21370        &self,
21371        buffer_handle: Entity<Buffer>,
21372        action: CodeAction,
21373        _excerpt_id: ExcerptId,
21374        push_to_history: bool,
21375        _window: &mut Window,
21376        cx: &mut App,
21377    ) -> Task<Result<ProjectTransaction>> {
21378        self.update(cx, |project, cx| {
21379            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21380        })
21381    }
21382}
21383
21384fn snippet_completions(
21385    project: &Project,
21386    buffer: &Entity<Buffer>,
21387    buffer_position: text::Anchor,
21388    cx: &mut App,
21389) -> Task<Result<CompletionResponse>> {
21390    let languages = buffer.read(cx).languages_at(buffer_position);
21391    let snippet_store = project.snippets().read(cx);
21392
21393    let scopes: Vec<_> = languages
21394        .iter()
21395        .filter_map(|language| {
21396            let language_name = language.lsp_id();
21397            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21398
21399            if snippets.is_empty() {
21400                None
21401            } else {
21402                Some((language.default_scope(), snippets))
21403            }
21404        })
21405        .collect();
21406
21407    if scopes.is_empty() {
21408        return Task::ready(Ok(CompletionResponse {
21409            completions: vec![],
21410            is_incomplete: false,
21411        }));
21412    }
21413
21414    let snapshot = buffer.read(cx).text_snapshot();
21415    let chars: String = snapshot
21416        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21417        .collect();
21418    let executor = cx.background_executor().clone();
21419
21420    cx.background_spawn(async move {
21421        let mut is_incomplete = false;
21422        let mut completions: Vec<Completion> = Vec::new();
21423        for (scope, snippets) in scopes.into_iter() {
21424            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21425            let mut last_word = chars
21426                .chars()
21427                .take_while(|c| classifier.is_word(*c))
21428                .collect::<String>();
21429            last_word = last_word.chars().rev().collect();
21430
21431            if last_word.is_empty() {
21432                return Ok(CompletionResponse {
21433                    completions: vec![],
21434                    is_incomplete: true,
21435                });
21436            }
21437
21438            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21439            let to_lsp = |point: &text::Anchor| {
21440                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21441                point_to_lsp(end)
21442            };
21443            let lsp_end = to_lsp(&buffer_position);
21444
21445            let candidates = snippets
21446                .iter()
21447                .enumerate()
21448                .flat_map(|(ix, snippet)| {
21449                    snippet
21450                        .prefix
21451                        .iter()
21452                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21453                })
21454                .collect::<Vec<StringMatchCandidate>>();
21455
21456            const MAX_RESULTS: usize = 100;
21457            let mut matches = fuzzy::match_strings(
21458                &candidates,
21459                &last_word,
21460                last_word.chars().any(|c| c.is_uppercase()),
21461                true,
21462                MAX_RESULTS,
21463                &Default::default(),
21464                executor.clone(),
21465            )
21466            .await;
21467
21468            if matches.len() >= MAX_RESULTS {
21469                is_incomplete = true;
21470            }
21471
21472            // Remove all candidates where the query's start does not match the start of any word in the candidate
21473            if let Some(query_start) = last_word.chars().next() {
21474                matches.retain(|string_match| {
21475                    split_words(&string_match.string).any(|word| {
21476                        // Check that the first codepoint of the word as lowercase matches the first
21477                        // codepoint of the query as lowercase
21478                        word.chars()
21479                            .flat_map(|codepoint| codepoint.to_lowercase())
21480                            .zip(query_start.to_lowercase())
21481                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21482                    })
21483                });
21484            }
21485
21486            let matched_strings = matches
21487                .into_iter()
21488                .map(|m| m.string)
21489                .collect::<HashSet<_>>();
21490
21491            completions.extend(snippets.iter().filter_map(|snippet| {
21492                let matching_prefix = snippet
21493                    .prefix
21494                    .iter()
21495                    .find(|prefix| matched_strings.contains(*prefix))?;
21496                let start = as_offset - last_word.len();
21497                let start = snapshot.anchor_before(start);
21498                let range = start..buffer_position;
21499                let lsp_start = to_lsp(&start);
21500                let lsp_range = lsp::Range {
21501                    start: lsp_start,
21502                    end: lsp_end,
21503                };
21504                Some(Completion {
21505                    replace_range: range,
21506                    new_text: snippet.body.clone(),
21507                    source: CompletionSource::Lsp {
21508                        insert_range: None,
21509                        server_id: LanguageServerId(usize::MAX),
21510                        resolved: true,
21511                        lsp_completion: Box::new(lsp::CompletionItem {
21512                            label: snippet.prefix.first().unwrap().clone(),
21513                            kind: Some(CompletionItemKind::SNIPPET),
21514                            label_details: snippet.description.as_ref().map(|description| {
21515                                lsp::CompletionItemLabelDetails {
21516                                    detail: Some(description.clone()),
21517                                    description: None,
21518                                }
21519                            }),
21520                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21521                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21522                                lsp::InsertReplaceEdit {
21523                                    new_text: snippet.body.clone(),
21524                                    insert: lsp_range,
21525                                    replace: lsp_range,
21526                                },
21527                            )),
21528                            filter_text: Some(snippet.body.clone()),
21529                            sort_text: Some(char::MAX.to_string()),
21530                            ..lsp::CompletionItem::default()
21531                        }),
21532                        lsp_defaults: None,
21533                    },
21534                    label: CodeLabel {
21535                        text: matching_prefix.clone(),
21536                        runs: Vec::new(),
21537                        filter_range: 0..matching_prefix.len(),
21538                    },
21539                    icon_path: None,
21540                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21541                        single_line: snippet.name.clone().into(),
21542                        plain_text: snippet
21543                            .description
21544                            .clone()
21545                            .map(|description| description.into()),
21546                    }),
21547                    insert_text_mode: None,
21548                    confirm: None,
21549                })
21550            }))
21551        }
21552
21553        Ok(CompletionResponse {
21554            completions,
21555            is_incomplete,
21556        })
21557    })
21558}
21559
21560impl CompletionProvider for Entity<Project> {
21561    fn completions(
21562        &self,
21563        _excerpt_id: ExcerptId,
21564        buffer: &Entity<Buffer>,
21565        buffer_position: text::Anchor,
21566        options: CompletionContext,
21567        _window: &mut Window,
21568        cx: &mut Context<Editor>,
21569    ) -> Task<Result<Vec<CompletionResponse>>> {
21570        self.update(cx, |project, cx| {
21571            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21572            let project_completions = project.completions(buffer, buffer_position, options, cx);
21573            cx.background_spawn(async move {
21574                let mut responses = project_completions.await?;
21575                let snippets = snippets.await?;
21576                if !snippets.completions.is_empty() {
21577                    responses.push(snippets);
21578                }
21579                Ok(responses)
21580            })
21581        })
21582    }
21583
21584    fn resolve_completions(
21585        &self,
21586        buffer: Entity<Buffer>,
21587        completion_indices: Vec<usize>,
21588        completions: Rc<RefCell<Box<[Completion]>>>,
21589        cx: &mut Context<Editor>,
21590    ) -> Task<Result<bool>> {
21591        self.update(cx, |project, cx| {
21592            project.lsp_store().update(cx, |lsp_store, cx| {
21593                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21594            })
21595        })
21596    }
21597
21598    fn apply_additional_edits_for_completion(
21599        &self,
21600        buffer: Entity<Buffer>,
21601        completions: Rc<RefCell<Box<[Completion]>>>,
21602        completion_index: usize,
21603        push_to_history: bool,
21604        cx: &mut Context<Editor>,
21605    ) -> Task<Result<Option<language::Transaction>>> {
21606        self.update(cx, |project, cx| {
21607            project.lsp_store().update(cx, |lsp_store, cx| {
21608                lsp_store.apply_additional_edits_for_completion(
21609                    buffer,
21610                    completions,
21611                    completion_index,
21612                    push_to_history,
21613                    cx,
21614                )
21615            })
21616        })
21617    }
21618
21619    fn is_completion_trigger(
21620        &self,
21621        buffer: &Entity<Buffer>,
21622        position: language::Anchor,
21623        text: &str,
21624        trigger_in_words: bool,
21625        menu_is_open: bool,
21626        cx: &mut Context<Editor>,
21627    ) -> bool {
21628        let mut chars = text.chars();
21629        let char = if let Some(char) = chars.next() {
21630            char
21631        } else {
21632            return false;
21633        };
21634        if chars.next().is_some() {
21635            return false;
21636        }
21637
21638        let buffer = buffer.read(cx);
21639        let snapshot = buffer.snapshot();
21640        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21641            return false;
21642        }
21643        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21644        if trigger_in_words && classifier.is_word(char) {
21645            return true;
21646        }
21647
21648        buffer.completion_triggers().contains(text)
21649    }
21650}
21651
21652impl SemanticsProvider for Entity<Project> {
21653    fn hover(
21654        &self,
21655        buffer: &Entity<Buffer>,
21656        position: text::Anchor,
21657        cx: &mut App,
21658    ) -> Option<Task<Vec<project::Hover>>> {
21659        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21660    }
21661
21662    fn document_highlights(
21663        &self,
21664        buffer: &Entity<Buffer>,
21665        position: text::Anchor,
21666        cx: &mut App,
21667    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21668        Some(self.update(cx, |project, cx| {
21669            project.document_highlights(buffer, position, cx)
21670        }))
21671    }
21672
21673    fn definitions(
21674        &self,
21675        buffer: &Entity<Buffer>,
21676        position: text::Anchor,
21677        kind: GotoDefinitionKind,
21678        cx: &mut App,
21679    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21680        Some(self.update(cx, |project, cx| match kind {
21681            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21682            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21683            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21684            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21685        }))
21686    }
21687
21688    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21689        // TODO: make this work for remote projects
21690        self.update(cx, |project, cx| {
21691            if project
21692                .active_debug_session(cx)
21693                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21694            {
21695                return true;
21696            }
21697
21698            buffer.update(cx, |buffer, cx| {
21699                project.any_language_server_supports_inlay_hints(buffer, cx)
21700            })
21701        })
21702    }
21703
21704    fn inline_values(
21705        &self,
21706        buffer_handle: Entity<Buffer>,
21707        range: Range<text::Anchor>,
21708        cx: &mut App,
21709    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21710        self.update(cx, |project, cx| {
21711            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21712
21713            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21714        })
21715    }
21716
21717    fn inlay_hints(
21718        &self,
21719        buffer_handle: Entity<Buffer>,
21720        range: Range<text::Anchor>,
21721        cx: &mut App,
21722    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21723        Some(self.update(cx, |project, cx| {
21724            project.inlay_hints(buffer_handle, range, cx)
21725        }))
21726    }
21727
21728    fn resolve_inlay_hint(
21729        &self,
21730        hint: InlayHint,
21731        buffer_handle: Entity<Buffer>,
21732        server_id: LanguageServerId,
21733        cx: &mut App,
21734    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21735        Some(self.update(cx, |project, cx| {
21736            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21737        }))
21738    }
21739
21740    fn range_for_rename(
21741        &self,
21742        buffer: &Entity<Buffer>,
21743        position: text::Anchor,
21744        cx: &mut App,
21745    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21746        Some(self.update(cx, |project, cx| {
21747            let buffer = buffer.clone();
21748            let task = project.prepare_rename(buffer.clone(), position, cx);
21749            cx.spawn(async move |_, cx| {
21750                Ok(match task.await? {
21751                    PrepareRenameResponse::Success(range) => Some(range),
21752                    PrepareRenameResponse::InvalidPosition => None,
21753                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21754                        // Fallback on using TreeSitter info to determine identifier range
21755                        buffer.read_with(cx, |buffer, _| {
21756                            let snapshot = buffer.snapshot();
21757                            let (range, kind) = snapshot.surrounding_word(position);
21758                            if kind != Some(CharKind::Word) {
21759                                return None;
21760                            }
21761                            Some(
21762                                snapshot.anchor_before(range.start)
21763                                    ..snapshot.anchor_after(range.end),
21764                            )
21765                        })?
21766                    }
21767                })
21768            })
21769        }))
21770    }
21771
21772    fn perform_rename(
21773        &self,
21774        buffer: &Entity<Buffer>,
21775        position: text::Anchor,
21776        new_name: String,
21777        cx: &mut App,
21778    ) -> Option<Task<Result<ProjectTransaction>>> {
21779        Some(self.update(cx, |project, cx| {
21780            project.perform_rename(buffer.clone(), position, new_name, cx)
21781        }))
21782    }
21783}
21784
21785fn inlay_hint_settings(
21786    location: Anchor,
21787    snapshot: &MultiBufferSnapshot,
21788    cx: &mut Context<Editor>,
21789) -> InlayHintSettings {
21790    let file = snapshot.file_at(location);
21791    let language = snapshot.language_at(location).map(|l| l.name());
21792    language_settings(language, file, cx).inlay_hints
21793}
21794
21795fn consume_contiguous_rows(
21796    contiguous_row_selections: &mut Vec<Selection<Point>>,
21797    selection: &Selection<Point>,
21798    display_map: &DisplaySnapshot,
21799    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21800) -> (MultiBufferRow, MultiBufferRow) {
21801    contiguous_row_selections.push(selection.clone());
21802    let start_row = MultiBufferRow(selection.start.row);
21803    let mut end_row = ending_row(selection, display_map);
21804
21805    while let Some(next_selection) = selections.peek() {
21806        if next_selection.start.row <= end_row.0 {
21807            end_row = ending_row(next_selection, display_map);
21808            contiguous_row_selections.push(selections.next().unwrap().clone());
21809        } else {
21810            break;
21811        }
21812    }
21813    (start_row, end_row)
21814}
21815
21816fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21817    if next_selection.end.column > 0 || next_selection.is_empty() {
21818        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21819    } else {
21820        MultiBufferRow(next_selection.end.row)
21821    }
21822}
21823
21824impl EditorSnapshot {
21825    pub fn remote_selections_in_range<'a>(
21826        &'a self,
21827        range: &'a Range<Anchor>,
21828        collaboration_hub: &dyn CollaborationHub,
21829        cx: &'a App,
21830    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21831        let participant_names = collaboration_hub.user_names(cx);
21832        let participant_indices = collaboration_hub.user_participant_indices(cx);
21833        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21834        let collaborators_by_replica_id = collaborators_by_peer_id
21835            .values()
21836            .map(|collaborator| (collaborator.replica_id, collaborator))
21837            .collect::<HashMap<_, _>>();
21838        self.buffer_snapshot
21839            .selections_in_range(range, false)
21840            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21841                if replica_id == AGENT_REPLICA_ID {
21842                    Some(RemoteSelection {
21843                        replica_id,
21844                        selection,
21845                        cursor_shape,
21846                        line_mode,
21847                        collaborator_id: CollaboratorId::Agent,
21848                        user_name: Some("Agent".into()),
21849                        color: cx.theme().players().agent(),
21850                    })
21851                } else {
21852                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21853                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21854                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21855                    Some(RemoteSelection {
21856                        replica_id,
21857                        selection,
21858                        cursor_shape,
21859                        line_mode,
21860                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21861                        user_name,
21862                        color: if let Some(index) = participant_index {
21863                            cx.theme().players().color_for_participant(index.0)
21864                        } else {
21865                            cx.theme().players().absent()
21866                        },
21867                    })
21868                }
21869            })
21870    }
21871
21872    pub fn hunks_for_ranges(
21873        &self,
21874        ranges: impl IntoIterator<Item = Range<Point>>,
21875    ) -> Vec<MultiBufferDiffHunk> {
21876        let mut hunks = Vec::new();
21877        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21878            HashMap::default();
21879        for query_range in ranges {
21880            let query_rows =
21881                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21882            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21883                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21884            ) {
21885                // Include deleted hunks that are adjacent to the query range, because
21886                // otherwise they would be missed.
21887                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21888                if hunk.status().is_deleted() {
21889                    intersects_range |= hunk.row_range.start == query_rows.end;
21890                    intersects_range |= hunk.row_range.end == query_rows.start;
21891                }
21892                if intersects_range {
21893                    if !processed_buffer_rows
21894                        .entry(hunk.buffer_id)
21895                        .or_default()
21896                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21897                    {
21898                        continue;
21899                    }
21900                    hunks.push(hunk);
21901                }
21902            }
21903        }
21904
21905        hunks
21906    }
21907
21908    fn display_diff_hunks_for_rows<'a>(
21909        &'a self,
21910        display_rows: Range<DisplayRow>,
21911        folded_buffers: &'a HashSet<BufferId>,
21912    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21913        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21914        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21915
21916        self.buffer_snapshot
21917            .diff_hunks_in_range(buffer_start..buffer_end)
21918            .filter_map(|hunk| {
21919                if folded_buffers.contains(&hunk.buffer_id) {
21920                    return None;
21921                }
21922
21923                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21924                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21925
21926                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21927                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21928
21929                let display_hunk = if hunk_display_start.column() != 0 {
21930                    DisplayDiffHunk::Folded {
21931                        display_row: hunk_display_start.row(),
21932                    }
21933                } else {
21934                    let mut end_row = hunk_display_end.row();
21935                    if hunk_display_end.column() > 0 {
21936                        end_row.0 += 1;
21937                    }
21938                    let is_created_file = hunk.is_created_file();
21939                    DisplayDiffHunk::Unfolded {
21940                        status: hunk.status(),
21941                        diff_base_byte_range: hunk.diff_base_byte_range,
21942                        display_row_range: hunk_display_start.row()..end_row,
21943                        multi_buffer_range: Anchor::range_in_buffer(
21944                            hunk.excerpt_id,
21945                            hunk.buffer_id,
21946                            hunk.buffer_range,
21947                        ),
21948                        is_created_file,
21949                    }
21950                };
21951
21952                Some(display_hunk)
21953            })
21954    }
21955
21956    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21957        self.display_snapshot.buffer_snapshot.language_at(position)
21958    }
21959
21960    pub fn is_focused(&self) -> bool {
21961        self.is_focused
21962    }
21963
21964    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21965        self.placeholder_text.as_ref()
21966    }
21967
21968    pub fn scroll_position(&self) -> gpui::Point<f32> {
21969        self.scroll_anchor.scroll_position(&self.display_snapshot)
21970    }
21971
21972    fn gutter_dimensions(
21973        &self,
21974        font_id: FontId,
21975        font_size: Pixels,
21976        max_line_number_width: Pixels,
21977        cx: &App,
21978    ) -> Option<GutterDimensions> {
21979        if !self.show_gutter {
21980            return None;
21981        }
21982
21983        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21984        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21985
21986        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21987            matches!(
21988                ProjectSettings::get_global(cx).git.git_gutter,
21989                Some(GitGutterSetting::TrackedFiles)
21990            )
21991        });
21992        let gutter_settings = EditorSettings::get_global(cx).gutter;
21993        let show_line_numbers = self
21994            .show_line_numbers
21995            .unwrap_or(gutter_settings.line_numbers);
21996        let line_gutter_width = if show_line_numbers {
21997            // Avoid flicker-like gutter resizes when the line number gains another digit by
21998            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21999            let min_width_for_number_on_gutter =
22000                ch_advance * gutter_settings.min_line_number_digits as f32;
22001            max_line_number_width.max(min_width_for_number_on_gutter)
22002        } else {
22003            0.0.into()
22004        };
22005
22006        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22007        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22008
22009        let git_blame_entries_width =
22010            self.git_blame_gutter_max_author_length
22011                .map(|max_author_length| {
22012                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22013                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22014
22015                    /// The number of characters to dedicate to gaps and margins.
22016                    const SPACING_WIDTH: usize = 4;
22017
22018                    let max_char_count = max_author_length.min(renderer.max_author_length())
22019                        + ::git::SHORT_SHA_LENGTH
22020                        + MAX_RELATIVE_TIMESTAMP.len()
22021                        + SPACING_WIDTH;
22022
22023                    ch_advance * max_char_count
22024                });
22025
22026        let is_singleton = self.buffer_snapshot.is_singleton();
22027
22028        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22029        left_padding += if !is_singleton {
22030            ch_width * 4.0
22031        } else if show_runnables || show_breakpoints {
22032            ch_width * 3.0
22033        } else if show_git_gutter && show_line_numbers {
22034            ch_width * 2.0
22035        } else if show_git_gutter || show_line_numbers {
22036            ch_width
22037        } else {
22038            px(0.)
22039        };
22040
22041        let shows_folds = is_singleton && gutter_settings.folds;
22042
22043        let right_padding = if shows_folds && show_line_numbers {
22044            ch_width * 4.0
22045        } else if shows_folds || (!is_singleton && show_line_numbers) {
22046            ch_width * 3.0
22047        } else if show_line_numbers {
22048            ch_width
22049        } else {
22050            px(0.)
22051        };
22052
22053        Some(GutterDimensions {
22054            left_padding,
22055            right_padding,
22056            width: line_gutter_width + left_padding + right_padding,
22057            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22058            git_blame_entries_width,
22059        })
22060    }
22061
22062    pub fn render_crease_toggle(
22063        &self,
22064        buffer_row: MultiBufferRow,
22065        row_contains_cursor: bool,
22066        editor: Entity<Editor>,
22067        window: &mut Window,
22068        cx: &mut App,
22069    ) -> Option<AnyElement> {
22070        let folded = self.is_line_folded(buffer_row);
22071        let mut is_foldable = false;
22072
22073        if let Some(crease) = self
22074            .crease_snapshot
22075            .query_row(buffer_row, &self.buffer_snapshot)
22076        {
22077            is_foldable = true;
22078            match crease {
22079                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22080                    if let Some(render_toggle) = render_toggle {
22081                        let toggle_callback =
22082                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22083                                if folded {
22084                                    editor.update(cx, |editor, cx| {
22085                                        editor.fold_at(buffer_row, window, cx)
22086                                    });
22087                                } else {
22088                                    editor.update(cx, |editor, cx| {
22089                                        editor.unfold_at(buffer_row, window, cx)
22090                                    });
22091                                }
22092                            });
22093                        return Some((render_toggle)(
22094                            buffer_row,
22095                            folded,
22096                            toggle_callback,
22097                            window,
22098                            cx,
22099                        ));
22100                    }
22101                }
22102            }
22103        }
22104
22105        is_foldable |= self.starts_indent(buffer_row);
22106
22107        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22108            Some(
22109                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22110                    .toggle_state(folded)
22111                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22112                        if folded {
22113                            this.unfold_at(buffer_row, window, cx);
22114                        } else {
22115                            this.fold_at(buffer_row, window, cx);
22116                        }
22117                    }))
22118                    .into_any_element(),
22119            )
22120        } else {
22121            None
22122        }
22123    }
22124
22125    pub fn render_crease_trailer(
22126        &self,
22127        buffer_row: MultiBufferRow,
22128        window: &mut Window,
22129        cx: &mut App,
22130    ) -> Option<AnyElement> {
22131        let folded = self.is_line_folded(buffer_row);
22132        if let Crease::Inline { render_trailer, .. } = self
22133            .crease_snapshot
22134            .query_row(buffer_row, &self.buffer_snapshot)?
22135        {
22136            let render_trailer = render_trailer.as_ref()?;
22137            Some(render_trailer(buffer_row, folded, window, cx))
22138        } else {
22139            None
22140        }
22141    }
22142}
22143
22144impl Deref for EditorSnapshot {
22145    type Target = DisplaySnapshot;
22146
22147    fn deref(&self) -> &Self::Target {
22148        &self.display_snapshot
22149    }
22150}
22151
22152#[derive(Clone, Debug, PartialEq, Eq)]
22153pub enum EditorEvent {
22154    InputIgnored {
22155        text: Arc<str>,
22156    },
22157    InputHandled {
22158        utf16_range_to_replace: Option<Range<isize>>,
22159        text: Arc<str>,
22160    },
22161    ExcerptsAdded {
22162        buffer: Entity<Buffer>,
22163        predecessor: ExcerptId,
22164        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22165    },
22166    ExcerptsRemoved {
22167        ids: Vec<ExcerptId>,
22168        removed_buffer_ids: Vec<BufferId>,
22169    },
22170    BufferFoldToggled {
22171        ids: Vec<ExcerptId>,
22172        folded: bool,
22173    },
22174    ExcerptsEdited {
22175        ids: Vec<ExcerptId>,
22176    },
22177    ExcerptsExpanded {
22178        ids: Vec<ExcerptId>,
22179    },
22180    BufferEdited,
22181    Edited {
22182        transaction_id: clock::Lamport,
22183    },
22184    Reparsed(BufferId),
22185    Focused,
22186    FocusedIn,
22187    Blurred,
22188    DirtyChanged,
22189    Saved,
22190    TitleChanged,
22191    DiffBaseChanged,
22192    SelectionsChanged {
22193        local: bool,
22194    },
22195    ScrollPositionChanged {
22196        local: bool,
22197        autoscroll: bool,
22198    },
22199    Closed,
22200    TransactionUndone {
22201        transaction_id: clock::Lamport,
22202    },
22203    TransactionBegun {
22204        transaction_id: clock::Lamport,
22205    },
22206    Reloaded,
22207    CursorShapeChanged,
22208    PushedToNavHistory {
22209        anchor: Anchor,
22210        is_deactivate: bool,
22211    },
22212}
22213
22214impl EventEmitter<EditorEvent> for Editor {}
22215
22216impl Focusable for Editor {
22217    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22218        self.focus_handle.clone()
22219    }
22220}
22221
22222impl Render for Editor {
22223    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22224        let settings = ThemeSettings::get_global(cx);
22225
22226        let mut text_style = match self.mode {
22227            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22228                color: cx.theme().colors().editor_foreground,
22229                font_family: settings.ui_font.family.clone(),
22230                font_features: settings.ui_font.features.clone(),
22231                font_fallbacks: settings.ui_font.fallbacks.clone(),
22232                font_size: rems(0.875).into(),
22233                font_weight: settings.ui_font.weight,
22234                line_height: relative(settings.buffer_line_height.value()),
22235                ..Default::default()
22236            },
22237            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22238                color: cx.theme().colors().editor_foreground,
22239                font_family: settings.buffer_font.family.clone(),
22240                font_features: settings.buffer_font.features.clone(),
22241                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22242                font_size: settings.buffer_font_size(cx).into(),
22243                font_weight: settings.buffer_font.weight,
22244                line_height: relative(settings.buffer_line_height.value()),
22245                ..Default::default()
22246            },
22247        };
22248        if let Some(text_style_refinement) = &self.text_style_refinement {
22249            text_style.refine(text_style_refinement)
22250        }
22251
22252        let background = match self.mode {
22253            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22254            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22255            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22256            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22257        };
22258
22259        EditorElement::new(
22260            &cx.entity(),
22261            EditorStyle {
22262                background,
22263                local_player: cx.theme().players().local(),
22264                text: text_style,
22265                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22266                syntax: cx.theme().syntax().clone(),
22267                status: cx.theme().status().clone(),
22268                inlay_hints_style: make_inlay_hints_style(cx),
22269                inline_completion_styles: make_suggestion_styles(cx),
22270                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22271                show_underlines: self.diagnostics_enabled(),
22272            },
22273        )
22274    }
22275}
22276
22277impl EntityInputHandler for Editor {
22278    fn text_for_range(
22279        &mut self,
22280        range_utf16: Range<usize>,
22281        adjusted_range: &mut Option<Range<usize>>,
22282        _: &mut Window,
22283        cx: &mut Context<Self>,
22284    ) -> Option<String> {
22285        let snapshot = self.buffer.read(cx).read(cx);
22286        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22287        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22288        if (start.0..end.0) != range_utf16 {
22289            adjusted_range.replace(start.0..end.0);
22290        }
22291        Some(snapshot.text_for_range(start..end).collect())
22292    }
22293
22294    fn selected_text_range(
22295        &mut self,
22296        ignore_disabled_input: bool,
22297        _: &mut Window,
22298        cx: &mut Context<Self>,
22299    ) -> Option<UTF16Selection> {
22300        // Prevent the IME menu from appearing when holding down an alphabetic key
22301        // while input is disabled.
22302        if !ignore_disabled_input && !self.input_enabled {
22303            return None;
22304        }
22305
22306        let selection = self.selections.newest::<OffsetUtf16>(cx);
22307        let range = selection.range();
22308
22309        Some(UTF16Selection {
22310            range: range.start.0..range.end.0,
22311            reversed: selection.reversed,
22312        })
22313    }
22314
22315    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22316        let snapshot = self.buffer.read(cx).read(cx);
22317        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22318        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22319    }
22320
22321    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22322        self.clear_highlights::<InputComposition>(cx);
22323        self.ime_transaction.take();
22324    }
22325
22326    fn replace_text_in_range(
22327        &mut self,
22328        range_utf16: Option<Range<usize>>,
22329        text: &str,
22330        window: &mut Window,
22331        cx: &mut Context<Self>,
22332    ) {
22333        if !self.input_enabled {
22334            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22335            return;
22336        }
22337
22338        self.transact(window, cx, |this, window, cx| {
22339            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22340                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22341                Some(this.selection_replacement_ranges(range_utf16, cx))
22342            } else {
22343                this.marked_text_ranges(cx)
22344            };
22345
22346            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22347                let newest_selection_id = this.selections.newest_anchor().id;
22348                this.selections
22349                    .all::<OffsetUtf16>(cx)
22350                    .iter()
22351                    .zip(ranges_to_replace.iter())
22352                    .find_map(|(selection, range)| {
22353                        if selection.id == newest_selection_id {
22354                            Some(
22355                                (range.start.0 as isize - selection.head().0 as isize)
22356                                    ..(range.end.0 as isize - selection.head().0 as isize),
22357                            )
22358                        } else {
22359                            None
22360                        }
22361                    })
22362            });
22363
22364            cx.emit(EditorEvent::InputHandled {
22365                utf16_range_to_replace: range_to_replace,
22366                text: text.into(),
22367            });
22368
22369            if let Some(new_selected_ranges) = new_selected_ranges {
22370                this.change_selections(None, window, cx, |selections| {
22371                    selections.select_ranges(new_selected_ranges)
22372                });
22373                this.backspace(&Default::default(), window, cx);
22374            }
22375
22376            this.handle_input(text, window, cx);
22377        });
22378
22379        if let Some(transaction) = self.ime_transaction {
22380            self.buffer.update(cx, |buffer, cx| {
22381                buffer.group_until_transaction(transaction, cx);
22382            });
22383        }
22384
22385        self.unmark_text(window, cx);
22386    }
22387
22388    fn replace_and_mark_text_in_range(
22389        &mut self,
22390        range_utf16: Option<Range<usize>>,
22391        text: &str,
22392        new_selected_range_utf16: Option<Range<usize>>,
22393        window: &mut Window,
22394        cx: &mut Context<Self>,
22395    ) {
22396        if !self.input_enabled {
22397            return;
22398        }
22399
22400        let transaction = self.transact(window, cx, |this, window, cx| {
22401            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22402                let snapshot = this.buffer.read(cx).read(cx);
22403                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22404                    for marked_range in &mut marked_ranges {
22405                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22406                        marked_range.start.0 += relative_range_utf16.start;
22407                        marked_range.start =
22408                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22409                        marked_range.end =
22410                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22411                    }
22412                }
22413                Some(marked_ranges)
22414            } else if let Some(range_utf16) = range_utf16 {
22415                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22416                Some(this.selection_replacement_ranges(range_utf16, cx))
22417            } else {
22418                None
22419            };
22420
22421            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22422                let newest_selection_id = this.selections.newest_anchor().id;
22423                this.selections
22424                    .all::<OffsetUtf16>(cx)
22425                    .iter()
22426                    .zip(ranges_to_replace.iter())
22427                    .find_map(|(selection, range)| {
22428                        if selection.id == newest_selection_id {
22429                            Some(
22430                                (range.start.0 as isize - selection.head().0 as isize)
22431                                    ..(range.end.0 as isize - selection.head().0 as isize),
22432                            )
22433                        } else {
22434                            None
22435                        }
22436                    })
22437            });
22438
22439            cx.emit(EditorEvent::InputHandled {
22440                utf16_range_to_replace: range_to_replace,
22441                text: text.into(),
22442            });
22443
22444            if let Some(ranges) = ranges_to_replace {
22445                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22446            }
22447
22448            let marked_ranges = {
22449                let snapshot = this.buffer.read(cx).read(cx);
22450                this.selections
22451                    .disjoint_anchors()
22452                    .iter()
22453                    .map(|selection| {
22454                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22455                    })
22456                    .collect::<Vec<_>>()
22457            };
22458
22459            if text.is_empty() {
22460                this.unmark_text(window, cx);
22461            } else {
22462                this.highlight_text::<InputComposition>(
22463                    marked_ranges.clone(),
22464                    HighlightStyle {
22465                        underline: Some(UnderlineStyle {
22466                            thickness: px(1.),
22467                            color: None,
22468                            wavy: false,
22469                        }),
22470                        ..Default::default()
22471                    },
22472                    cx,
22473                );
22474            }
22475
22476            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22477            let use_autoclose = this.use_autoclose;
22478            let use_auto_surround = this.use_auto_surround;
22479            this.set_use_autoclose(false);
22480            this.set_use_auto_surround(false);
22481            this.handle_input(text, window, cx);
22482            this.set_use_autoclose(use_autoclose);
22483            this.set_use_auto_surround(use_auto_surround);
22484
22485            if let Some(new_selected_range) = new_selected_range_utf16 {
22486                let snapshot = this.buffer.read(cx).read(cx);
22487                let new_selected_ranges = marked_ranges
22488                    .into_iter()
22489                    .map(|marked_range| {
22490                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22491                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22492                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22493                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22494                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22495                    })
22496                    .collect::<Vec<_>>();
22497
22498                drop(snapshot);
22499                this.change_selections(None, window, cx, |selections| {
22500                    selections.select_ranges(new_selected_ranges)
22501                });
22502            }
22503        });
22504
22505        self.ime_transaction = self.ime_transaction.or(transaction);
22506        if let Some(transaction) = self.ime_transaction {
22507            self.buffer.update(cx, |buffer, cx| {
22508                buffer.group_until_transaction(transaction, cx);
22509            });
22510        }
22511
22512        if self.text_highlights::<InputComposition>(cx).is_none() {
22513            self.ime_transaction.take();
22514        }
22515    }
22516
22517    fn bounds_for_range(
22518        &mut self,
22519        range_utf16: Range<usize>,
22520        element_bounds: gpui::Bounds<Pixels>,
22521        window: &mut Window,
22522        cx: &mut Context<Self>,
22523    ) -> Option<gpui::Bounds<Pixels>> {
22524        let text_layout_details = self.text_layout_details(window);
22525        let gpui::Size {
22526            width: em_width,
22527            height: line_height,
22528        } = self.character_size(window);
22529
22530        let snapshot = self.snapshot(window, cx);
22531        let scroll_position = snapshot.scroll_position();
22532        let scroll_left = scroll_position.x * em_width;
22533
22534        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22535        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22536            + self.gutter_dimensions.width
22537            + self.gutter_dimensions.margin;
22538        let y = line_height * (start.row().as_f32() - scroll_position.y);
22539
22540        Some(Bounds {
22541            origin: element_bounds.origin + point(x, y),
22542            size: size(em_width, line_height),
22543        })
22544    }
22545
22546    fn character_index_for_point(
22547        &mut self,
22548        point: gpui::Point<Pixels>,
22549        _window: &mut Window,
22550        _cx: &mut Context<Self>,
22551    ) -> Option<usize> {
22552        let position_map = self.last_position_map.as_ref()?;
22553        if !position_map.text_hitbox.contains(&point) {
22554            return None;
22555        }
22556        let display_point = position_map.point_for_position(point).previous_valid;
22557        let anchor = position_map
22558            .snapshot
22559            .display_point_to_anchor(display_point, Bias::Left);
22560        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22561        Some(utf16_offset.0)
22562    }
22563}
22564
22565trait SelectionExt {
22566    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22567    fn spanned_rows(
22568        &self,
22569        include_end_if_at_line_start: bool,
22570        map: &DisplaySnapshot,
22571    ) -> Range<MultiBufferRow>;
22572}
22573
22574impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22575    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22576        let start = self
22577            .start
22578            .to_point(&map.buffer_snapshot)
22579            .to_display_point(map);
22580        let end = self
22581            .end
22582            .to_point(&map.buffer_snapshot)
22583            .to_display_point(map);
22584        if self.reversed {
22585            end..start
22586        } else {
22587            start..end
22588        }
22589    }
22590
22591    fn spanned_rows(
22592        &self,
22593        include_end_if_at_line_start: bool,
22594        map: &DisplaySnapshot,
22595    ) -> Range<MultiBufferRow> {
22596        let start = self.start.to_point(&map.buffer_snapshot);
22597        let mut end = self.end.to_point(&map.buffer_snapshot);
22598        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22599            end.row -= 1;
22600        }
22601
22602        let buffer_start = map.prev_line_boundary(start).0;
22603        let buffer_end = map.next_line_boundary(end).0;
22604        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22605    }
22606}
22607
22608impl<T: InvalidationRegion> InvalidationStack<T> {
22609    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22610    where
22611        S: Clone + ToOffset,
22612    {
22613        while let Some(region) = self.last() {
22614            let all_selections_inside_invalidation_ranges =
22615                if selections.len() == region.ranges().len() {
22616                    selections
22617                        .iter()
22618                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22619                        .all(|(selection, invalidation_range)| {
22620                            let head = selection.head().to_offset(buffer);
22621                            invalidation_range.start <= head && invalidation_range.end >= head
22622                        })
22623                } else {
22624                    false
22625                };
22626
22627            if all_selections_inside_invalidation_ranges {
22628                break;
22629            } else {
22630                self.pop();
22631            }
22632        }
22633    }
22634}
22635
22636impl<T> Default for InvalidationStack<T> {
22637    fn default() -> Self {
22638        Self(Default::default())
22639    }
22640}
22641
22642impl<T> Deref for InvalidationStack<T> {
22643    type Target = Vec<T>;
22644
22645    fn deref(&self) -> &Self::Target {
22646        &self.0
22647    }
22648}
22649
22650impl<T> DerefMut for InvalidationStack<T> {
22651    fn deref_mut(&mut self) -> &mut Self::Target {
22652        &mut self.0
22653    }
22654}
22655
22656impl InvalidationRegion for SnippetState {
22657    fn ranges(&self) -> &[Range<Anchor>] {
22658        &self.ranges[self.active_index]
22659    }
22660}
22661
22662fn inline_completion_edit_text(
22663    current_snapshot: &BufferSnapshot,
22664    edits: &[(Range<Anchor>, String)],
22665    edit_preview: &EditPreview,
22666    include_deletions: bool,
22667    cx: &App,
22668) -> HighlightedText {
22669    let edits = edits
22670        .iter()
22671        .map(|(anchor, text)| {
22672            (
22673                anchor.start.text_anchor..anchor.end.text_anchor,
22674                text.clone(),
22675            )
22676        })
22677        .collect::<Vec<_>>();
22678
22679    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22680}
22681
22682pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22683    match severity {
22684        lsp::DiagnosticSeverity::ERROR => colors.error,
22685        lsp::DiagnosticSeverity::WARNING => colors.warning,
22686        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22687        lsp::DiagnosticSeverity::HINT => colors.info,
22688        _ => colors.ignored,
22689    }
22690}
22691
22692pub fn styled_runs_for_code_label<'a>(
22693    label: &'a CodeLabel,
22694    syntax_theme: &'a theme::SyntaxTheme,
22695) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22696    let fade_out = HighlightStyle {
22697        fade_out: Some(0.35),
22698        ..Default::default()
22699    };
22700
22701    let mut prev_end = label.filter_range.end;
22702    label
22703        .runs
22704        .iter()
22705        .enumerate()
22706        .flat_map(move |(ix, (range, highlight_id))| {
22707            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22708                style
22709            } else {
22710                return Default::default();
22711            };
22712            let mut muted_style = style;
22713            muted_style.highlight(fade_out);
22714
22715            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22716            if range.start >= label.filter_range.end {
22717                if range.start > prev_end {
22718                    runs.push((prev_end..range.start, fade_out));
22719                }
22720                runs.push((range.clone(), muted_style));
22721            } else if range.end <= label.filter_range.end {
22722                runs.push((range.clone(), style));
22723            } else {
22724                runs.push((range.start..label.filter_range.end, style));
22725                runs.push((label.filter_range.end..range.end, muted_style));
22726            }
22727            prev_end = cmp::max(prev_end, range.end);
22728
22729            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22730                runs.push((prev_end..label.text.len(), fade_out));
22731            }
22732
22733            runs
22734        })
22735}
22736
22737pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22738    let mut prev_index = 0;
22739    let mut prev_codepoint: Option<char> = None;
22740    text.char_indices()
22741        .chain([(text.len(), '\0')])
22742        .filter_map(move |(index, codepoint)| {
22743            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22744            let is_boundary = index == text.len()
22745                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22746                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22747            if is_boundary {
22748                let chunk = &text[prev_index..index];
22749                prev_index = index;
22750                Some(chunk)
22751            } else {
22752                None
22753            }
22754        })
22755}
22756
22757pub trait RangeToAnchorExt: Sized {
22758    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22759
22760    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22761        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22762        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22763    }
22764}
22765
22766impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22767    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22768        let start_offset = self.start.to_offset(snapshot);
22769        let end_offset = self.end.to_offset(snapshot);
22770        if start_offset == end_offset {
22771            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22772        } else {
22773            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22774        }
22775    }
22776}
22777
22778pub trait RowExt {
22779    fn as_f32(&self) -> f32;
22780
22781    fn next_row(&self) -> Self;
22782
22783    fn previous_row(&self) -> Self;
22784
22785    fn minus(&self, other: Self) -> u32;
22786}
22787
22788impl RowExt for DisplayRow {
22789    fn as_f32(&self) -> f32 {
22790        self.0 as f32
22791    }
22792
22793    fn next_row(&self) -> Self {
22794        Self(self.0 + 1)
22795    }
22796
22797    fn previous_row(&self) -> Self {
22798        Self(self.0.saturating_sub(1))
22799    }
22800
22801    fn minus(&self, other: Self) -> u32 {
22802        self.0 - other.0
22803    }
22804}
22805
22806impl RowExt for MultiBufferRow {
22807    fn as_f32(&self) -> f32 {
22808        self.0 as f32
22809    }
22810
22811    fn next_row(&self) -> Self {
22812        Self(self.0 + 1)
22813    }
22814
22815    fn previous_row(&self) -> Self {
22816        Self(self.0.saturating_sub(1))
22817    }
22818
22819    fn minus(&self, other: Self) -> u32 {
22820        self.0 - other.0
22821    }
22822}
22823
22824trait RowRangeExt {
22825    type Row;
22826
22827    fn len(&self) -> usize;
22828
22829    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22830}
22831
22832impl RowRangeExt for Range<MultiBufferRow> {
22833    type Row = MultiBufferRow;
22834
22835    fn len(&self) -> usize {
22836        (self.end.0 - self.start.0) as usize
22837    }
22838
22839    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22840        (self.start.0..self.end.0).map(MultiBufferRow)
22841    }
22842}
22843
22844impl RowRangeExt for Range<DisplayRow> {
22845    type Row = DisplayRow;
22846
22847    fn len(&self) -> usize {
22848        (self.end.0 - self.start.0) as usize
22849    }
22850
22851    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22852        (self.start.0..self.end.0).map(DisplayRow)
22853    }
22854}
22855
22856/// If select range has more than one line, we
22857/// just point the cursor to range.start.
22858fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22859    if range.start.row == range.end.row {
22860        range
22861    } else {
22862        range.start..range.start
22863    }
22864}
22865pub struct KillRing(ClipboardItem);
22866impl Global for KillRing {}
22867
22868const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22869
22870enum BreakpointPromptEditAction {
22871    Log,
22872    Condition,
22873    HitCondition,
22874}
22875
22876struct BreakpointPromptEditor {
22877    pub(crate) prompt: Entity<Editor>,
22878    editor: WeakEntity<Editor>,
22879    breakpoint_anchor: Anchor,
22880    breakpoint: Breakpoint,
22881    edit_action: BreakpointPromptEditAction,
22882    block_ids: HashSet<CustomBlockId>,
22883    editor_margins: Arc<Mutex<EditorMargins>>,
22884    _subscriptions: Vec<Subscription>,
22885}
22886
22887impl BreakpointPromptEditor {
22888    const MAX_LINES: u8 = 4;
22889
22890    fn new(
22891        editor: WeakEntity<Editor>,
22892        breakpoint_anchor: Anchor,
22893        breakpoint: Breakpoint,
22894        edit_action: BreakpointPromptEditAction,
22895        window: &mut Window,
22896        cx: &mut Context<Self>,
22897    ) -> Self {
22898        let base_text = match edit_action {
22899            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22900            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22901            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22902        }
22903        .map(|msg| msg.to_string())
22904        .unwrap_or_default();
22905
22906        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22907        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22908
22909        let prompt = cx.new(|cx| {
22910            let mut prompt = Editor::new(
22911                EditorMode::AutoHeight {
22912                    min_lines: 1,
22913                    max_lines: Some(Self::MAX_LINES as usize),
22914                },
22915                buffer,
22916                None,
22917                window,
22918                cx,
22919            );
22920            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22921            prompt.set_show_cursor_when_unfocused(false, cx);
22922            prompt.set_placeholder_text(
22923                match edit_action {
22924                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22925                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22926                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22927                },
22928                cx,
22929            );
22930
22931            prompt
22932        });
22933
22934        Self {
22935            prompt,
22936            editor,
22937            breakpoint_anchor,
22938            breakpoint,
22939            edit_action,
22940            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22941            block_ids: Default::default(),
22942            _subscriptions: vec![],
22943        }
22944    }
22945
22946    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22947        self.block_ids.extend(block_ids)
22948    }
22949
22950    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22951        if let Some(editor) = self.editor.upgrade() {
22952            let message = self
22953                .prompt
22954                .read(cx)
22955                .buffer
22956                .read(cx)
22957                .as_singleton()
22958                .expect("A multi buffer in breakpoint prompt isn't possible")
22959                .read(cx)
22960                .as_rope()
22961                .to_string();
22962
22963            editor.update(cx, |editor, cx| {
22964                editor.edit_breakpoint_at_anchor(
22965                    self.breakpoint_anchor,
22966                    self.breakpoint.clone(),
22967                    match self.edit_action {
22968                        BreakpointPromptEditAction::Log => {
22969                            BreakpointEditAction::EditLogMessage(message.into())
22970                        }
22971                        BreakpointPromptEditAction::Condition => {
22972                            BreakpointEditAction::EditCondition(message.into())
22973                        }
22974                        BreakpointPromptEditAction::HitCondition => {
22975                            BreakpointEditAction::EditHitCondition(message.into())
22976                        }
22977                    },
22978                    cx,
22979                );
22980
22981                editor.remove_blocks(self.block_ids.clone(), None, cx);
22982                cx.focus_self(window);
22983            });
22984        }
22985    }
22986
22987    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22988        self.editor
22989            .update(cx, |editor, cx| {
22990                editor.remove_blocks(self.block_ids.clone(), None, cx);
22991                window.focus(&editor.focus_handle);
22992            })
22993            .log_err();
22994    }
22995
22996    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22997        let settings = ThemeSettings::get_global(cx);
22998        let text_style = TextStyle {
22999            color: if self.prompt.read(cx).read_only(cx) {
23000                cx.theme().colors().text_disabled
23001            } else {
23002                cx.theme().colors().text
23003            },
23004            font_family: settings.buffer_font.family.clone(),
23005            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23006            font_size: settings.buffer_font_size(cx).into(),
23007            font_weight: settings.buffer_font.weight,
23008            line_height: relative(settings.buffer_line_height.value()),
23009            ..Default::default()
23010        };
23011        EditorElement::new(
23012            &self.prompt,
23013            EditorStyle {
23014                background: cx.theme().colors().editor_background,
23015                local_player: cx.theme().players().local(),
23016                text: text_style,
23017                ..Default::default()
23018            },
23019        )
23020    }
23021}
23022
23023impl Render for BreakpointPromptEditor {
23024    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23025        let editor_margins = *self.editor_margins.lock();
23026        let gutter_dimensions = editor_margins.gutter;
23027        h_flex()
23028            .key_context("Editor")
23029            .bg(cx.theme().colors().editor_background)
23030            .border_y_1()
23031            .border_color(cx.theme().status().info_border)
23032            .size_full()
23033            .py(window.line_height() / 2.5)
23034            .on_action(cx.listener(Self::confirm))
23035            .on_action(cx.listener(Self::cancel))
23036            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23037            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23038    }
23039}
23040
23041impl Focusable for BreakpointPromptEditor {
23042    fn focus_handle(&self, cx: &App) -> FocusHandle {
23043        self.prompt.focus_handle(cx)
23044    }
23045}
23046
23047fn all_edits_insertions_or_deletions(
23048    edits: &Vec<(Range<Anchor>, String)>,
23049    snapshot: &MultiBufferSnapshot,
23050) -> bool {
23051    let mut all_insertions = true;
23052    let mut all_deletions = true;
23053
23054    for (range, new_text) in edits.iter() {
23055        let range_is_empty = range.to_offset(&snapshot).is_empty();
23056        let text_is_empty = new_text.is_empty();
23057
23058        if range_is_empty != text_is_empty {
23059            if range_is_empty {
23060                all_deletions = false;
23061            } else {
23062                all_insertions = false;
23063            }
23064        } else {
23065            return false;
23066        }
23067
23068        if !all_insertions && !all_deletions {
23069            return false;
23070        }
23071    }
23072    all_insertions || all_deletions
23073}
23074
23075struct MissingEditPredictionKeybindingTooltip;
23076
23077impl Render for MissingEditPredictionKeybindingTooltip {
23078    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23079        ui::tooltip_container(window, cx, |container, _, cx| {
23080            container
23081                .flex_shrink_0()
23082                .max_w_80()
23083                .min_h(rems_from_px(124.))
23084                .justify_between()
23085                .child(
23086                    v_flex()
23087                        .flex_1()
23088                        .text_ui_sm(cx)
23089                        .child(Label::new("Conflict with Accept Keybinding"))
23090                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23091                )
23092                .child(
23093                    h_flex()
23094                        .pb_1()
23095                        .gap_1()
23096                        .items_end()
23097                        .w_full()
23098                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23099                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23100                        }))
23101                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23102                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23103                        })),
23104                )
23105        })
23106    }
23107}
23108
23109#[derive(Debug, Clone, Copy, PartialEq)]
23110pub struct LineHighlight {
23111    pub background: Background,
23112    pub border: Option<gpui::Hsla>,
23113    pub include_gutter: bool,
23114    pub type_id: Option<TypeId>,
23115}
23116
23117struct LineManipulationResult {
23118    pub new_text: String,
23119    pub line_count_before: usize,
23120    pub line_count_after: usize,
23121}
23122
23123fn render_diff_hunk_controls(
23124    row: u32,
23125    status: &DiffHunkStatus,
23126    hunk_range: Range<Anchor>,
23127    is_created_file: bool,
23128    line_height: Pixels,
23129    editor: &Entity<Editor>,
23130    _window: &mut Window,
23131    cx: &mut App,
23132) -> AnyElement {
23133    h_flex()
23134        .h(line_height)
23135        .mr_1()
23136        .gap_1()
23137        .px_0p5()
23138        .pb_1()
23139        .border_x_1()
23140        .border_b_1()
23141        .border_color(cx.theme().colors().border_variant)
23142        .rounded_b_lg()
23143        .bg(cx.theme().colors().editor_background)
23144        .gap_1()
23145        .block_mouse_except_scroll()
23146        .shadow_md()
23147        .child(if status.has_secondary_hunk() {
23148            Button::new(("stage", row as u64), "Stage")
23149                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23150                .tooltip({
23151                    let focus_handle = editor.focus_handle(cx);
23152                    move |window, cx| {
23153                        Tooltip::for_action_in(
23154                            "Stage Hunk",
23155                            &::git::ToggleStaged,
23156                            &focus_handle,
23157                            window,
23158                            cx,
23159                        )
23160                    }
23161                })
23162                .on_click({
23163                    let editor = editor.clone();
23164                    move |_event, _window, cx| {
23165                        editor.update(cx, |editor, cx| {
23166                            editor.stage_or_unstage_diff_hunks(
23167                                true,
23168                                vec![hunk_range.start..hunk_range.start],
23169                                cx,
23170                            );
23171                        });
23172                    }
23173                })
23174        } else {
23175            Button::new(("unstage", row as u64), "Unstage")
23176                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23177                .tooltip({
23178                    let focus_handle = editor.focus_handle(cx);
23179                    move |window, cx| {
23180                        Tooltip::for_action_in(
23181                            "Unstage Hunk",
23182                            &::git::ToggleStaged,
23183                            &focus_handle,
23184                            window,
23185                            cx,
23186                        )
23187                    }
23188                })
23189                .on_click({
23190                    let editor = editor.clone();
23191                    move |_event, _window, cx| {
23192                        editor.update(cx, |editor, cx| {
23193                            editor.stage_or_unstage_diff_hunks(
23194                                false,
23195                                vec![hunk_range.start..hunk_range.start],
23196                                cx,
23197                            );
23198                        });
23199                    }
23200                })
23201        })
23202        .child(
23203            Button::new(("restore", row as u64), "Restore")
23204                .tooltip({
23205                    let focus_handle = editor.focus_handle(cx);
23206                    move |window, cx| {
23207                        Tooltip::for_action_in(
23208                            "Restore Hunk",
23209                            &::git::Restore,
23210                            &focus_handle,
23211                            window,
23212                            cx,
23213                        )
23214                    }
23215                })
23216                .on_click({
23217                    let editor = editor.clone();
23218                    move |_event, window, cx| {
23219                        editor.update(cx, |editor, cx| {
23220                            let snapshot = editor.snapshot(window, cx);
23221                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23222                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23223                        });
23224                    }
23225                })
23226                .disabled(is_created_file),
23227        )
23228        .when(
23229            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23230            |el| {
23231                el.child(
23232                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23233                        .shape(IconButtonShape::Square)
23234                        .icon_size(IconSize::Small)
23235                        // .disabled(!has_multiple_hunks)
23236                        .tooltip({
23237                            let focus_handle = editor.focus_handle(cx);
23238                            move |window, cx| {
23239                                Tooltip::for_action_in(
23240                                    "Next Hunk",
23241                                    &GoToHunk,
23242                                    &focus_handle,
23243                                    window,
23244                                    cx,
23245                                )
23246                            }
23247                        })
23248                        .on_click({
23249                            let editor = editor.clone();
23250                            move |_event, window, cx| {
23251                                editor.update(cx, |editor, cx| {
23252                                    let snapshot = editor.snapshot(window, cx);
23253                                    let position =
23254                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23255                                    editor.go_to_hunk_before_or_after_position(
23256                                        &snapshot,
23257                                        position,
23258                                        Direction::Next,
23259                                        window,
23260                                        cx,
23261                                    );
23262                                    editor.expand_selected_diff_hunks(cx);
23263                                });
23264                            }
23265                        }),
23266                )
23267                .child(
23268                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23269                        .shape(IconButtonShape::Square)
23270                        .icon_size(IconSize::Small)
23271                        // .disabled(!has_multiple_hunks)
23272                        .tooltip({
23273                            let focus_handle = editor.focus_handle(cx);
23274                            move |window, cx| {
23275                                Tooltip::for_action_in(
23276                                    "Previous Hunk",
23277                                    &GoToPreviousHunk,
23278                                    &focus_handle,
23279                                    window,
23280                                    cx,
23281                                )
23282                            }
23283                        })
23284                        .on_click({
23285                            let editor = editor.clone();
23286                            move |_event, window, cx| {
23287                                editor.update(cx, |editor, cx| {
23288                                    let snapshot = editor.snapshot(window, cx);
23289                                    let point =
23290                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23291                                    editor.go_to_hunk_before_or_after_position(
23292                                        &snapshot,
23293                                        point,
23294                                        Direction::Prev,
23295                                        window,
23296                                        cx,
23297                                    );
23298                                    editor.expand_selected_diff_hunks(cx);
23299                                });
23300                            }
23301                        }),
23302                )
23303            },
23304        )
23305        .into_any_element()
23306}