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    pub 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                        HashSet::default(),
16179                        cx,
16180                    );
16181                });
16182            })
16183        }
16184    }
16185
16186    pub fn stop_language_server(
16187        &mut self,
16188        _: &StopLanguageServer,
16189        _: &mut Window,
16190        cx: &mut Context<Self>,
16191    ) {
16192        if let Some(project) = self.project.clone() {
16193            self.buffer.update(cx, |multi_buffer, cx| {
16194                project.update(cx, |project, cx| {
16195                    project.stop_language_servers_for_buffers(
16196                        multi_buffer.all_buffers().into_iter().collect(),
16197                        HashSet::default(),
16198                        cx,
16199                    );
16200                    cx.emit(project::Event::RefreshInlayHints);
16201                });
16202            });
16203        }
16204    }
16205
16206    fn cancel_language_server_work(
16207        workspace: &mut Workspace,
16208        _: &actions::CancelLanguageServerWork,
16209        _: &mut Window,
16210        cx: &mut Context<Workspace>,
16211    ) {
16212        let project = workspace.project();
16213        let buffers = workspace
16214            .active_item(cx)
16215            .and_then(|item| item.act_as::<Editor>(cx))
16216            .map_or(HashSet::default(), |editor| {
16217                editor.read(cx).buffer.read(cx).all_buffers()
16218            });
16219        project.update(cx, |project, cx| {
16220            project.cancel_language_server_work_for_buffers(buffers, cx);
16221        });
16222    }
16223
16224    fn show_character_palette(
16225        &mut self,
16226        _: &ShowCharacterPalette,
16227        window: &mut Window,
16228        _: &mut Context<Self>,
16229    ) {
16230        window.show_character_palette();
16231    }
16232
16233    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16234        if !self.diagnostics_enabled() {
16235            return;
16236        }
16237
16238        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16239            let buffer = self.buffer.read(cx).snapshot(cx);
16240            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16241            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16242            let is_valid = buffer
16243                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16244                .any(|entry| {
16245                    entry.diagnostic.is_primary
16246                        && !entry.range.is_empty()
16247                        && entry.range.start == primary_range_start
16248                        && entry.diagnostic.message == active_diagnostics.active_message
16249                });
16250
16251            if !is_valid {
16252                self.dismiss_diagnostics(cx);
16253            }
16254        }
16255    }
16256
16257    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16258        match &self.active_diagnostics {
16259            ActiveDiagnostic::Group(group) => Some(group),
16260            _ => None,
16261        }
16262    }
16263
16264    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16265        if !self.diagnostics_enabled() {
16266            return;
16267        }
16268        self.dismiss_diagnostics(cx);
16269        self.active_diagnostics = ActiveDiagnostic::All;
16270    }
16271
16272    fn activate_diagnostics(
16273        &mut self,
16274        buffer_id: BufferId,
16275        diagnostic: DiagnosticEntry<usize>,
16276        window: &mut Window,
16277        cx: &mut Context<Self>,
16278    ) {
16279        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16280            return;
16281        }
16282        self.dismiss_diagnostics(cx);
16283        let snapshot = self.snapshot(window, cx);
16284        let buffer = self.buffer.read(cx).snapshot(cx);
16285        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16286            return;
16287        };
16288
16289        let diagnostic_group = buffer
16290            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16291            .collect::<Vec<_>>();
16292
16293        let blocks =
16294            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16295
16296        let blocks = self.display_map.update(cx, |display_map, cx| {
16297            display_map.insert_blocks(blocks, cx).into_iter().collect()
16298        });
16299        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16300            active_range: buffer.anchor_before(diagnostic.range.start)
16301                ..buffer.anchor_after(diagnostic.range.end),
16302            active_message: diagnostic.diagnostic.message.clone(),
16303            group_id: diagnostic.diagnostic.group_id,
16304            blocks,
16305        });
16306        cx.notify();
16307    }
16308
16309    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16310        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16311            return;
16312        };
16313
16314        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16315        if let ActiveDiagnostic::Group(group) = prev {
16316            self.display_map.update(cx, |display_map, cx| {
16317                display_map.remove_blocks(group.blocks, cx);
16318            });
16319            cx.notify();
16320        }
16321    }
16322
16323    /// Disable inline diagnostics rendering for this editor.
16324    pub fn disable_inline_diagnostics(&mut self) {
16325        self.inline_diagnostics_enabled = false;
16326        self.inline_diagnostics_update = Task::ready(());
16327        self.inline_diagnostics.clear();
16328    }
16329
16330    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16331        self.diagnostics_enabled = false;
16332        self.dismiss_diagnostics(cx);
16333        self.inline_diagnostics_update = Task::ready(());
16334        self.inline_diagnostics.clear();
16335    }
16336
16337    pub fn diagnostics_enabled(&self) -> bool {
16338        self.diagnostics_enabled && self.mode.is_full()
16339    }
16340
16341    pub fn inline_diagnostics_enabled(&self) -> bool {
16342        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16343    }
16344
16345    pub fn show_inline_diagnostics(&self) -> bool {
16346        self.show_inline_diagnostics
16347    }
16348
16349    pub fn toggle_inline_diagnostics(
16350        &mut self,
16351        _: &ToggleInlineDiagnostics,
16352        window: &mut Window,
16353        cx: &mut Context<Editor>,
16354    ) {
16355        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16356        self.refresh_inline_diagnostics(false, window, cx);
16357    }
16358
16359    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16360        self.diagnostics_max_severity = severity;
16361        self.display_map.update(cx, |display_map, _| {
16362            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16363        });
16364    }
16365
16366    pub fn toggle_diagnostics(
16367        &mut self,
16368        _: &ToggleDiagnostics,
16369        window: &mut Window,
16370        cx: &mut Context<Editor>,
16371    ) {
16372        if !self.diagnostics_enabled() {
16373            return;
16374        }
16375
16376        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16377            EditorSettings::get_global(cx)
16378                .diagnostics_max_severity
16379                .filter(|severity| severity != &DiagnosticSeverity::Off)
16380                .unwrap_or(DiagnosticSeverity::Hint)
16381        } else {
16382            DiagnosticSeverity::Off
16383        };
16384        self.set_max_diagnostics_severity(new_severity, cx);
16385        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16386            self.active_diagnostics = ActiveDiagnostic::None;
16387            self.inline_diagnostics_update = Task::ready(());
16388            self.inline_diagnostics.clear();
16389        } else {
16390            self.refresh_inline_diagnostics(false, window, cx);
16391        }
16392
16393        cx.notify();
16394    }
16395
16396    pub fn toggle_minimap(
16397        &mut self,
16398        _: &ToggleMinimap,
16399        window: &mut Window,
16400        cx: &mut Context<Editor>,
16401    ) {
16402        if self.supports_minimap(cx) {
16403            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16404        }
16405    }
16406
16407    fn refresh_inline_diagnostics(
16408        &mut self,
16409        debounce: bool,
16410        window: &mut Window,
16411        cx: &mut Context<Self>,
16412    ) {
16413        let max_severity = ProjectSettings::get_global(cx)
16414            .diagnostics
16415            .inline
16416            .max_severity
16417            .unwrap_or(self.diagnostics_max_severity);
16418
16419        if !self.inline_diagnostics_enabled()
16420            || !self.show_inline_diagnostics
16421            || max_severity == DiagnosticSeverity::Off
16422        {
16423            self.inline_diagnostics_update = Task::ready(());
16424            self.inline_diagnostics.clear();
16425            return;
16426        }
16427
16428        let debounce_ms = ProjectSettings::get_global(cx)
16429            .diagnostics
16430            .inline
16431            .update_debounce_ms;
16432        let debounce = if debounce && debounce_ms > 0 {
16433            Some(Duration::from_millis(debounce_ms))
16434        } else {
16435            None
16436        };
16437        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16438            if let Some(debounce) = debounce {
16439                cx.background_executor().timer(debounce).await;
16440            }
16441            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16442                editor
16443                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16444                    .ok()
16445            }) else {
16446                return;
16447            };
16448
16449            let new_inline_diagnostics = cx
16450                .background_spawn(async move {
16451                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16452                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16453                        let message = diagnostic_entry
16454                            .diagnostic
16455                            .message
16456                            .split_once('\n')
16457                            .map(|(line, _)| line)
16458                            .map(SharedString::new)
16459                            .unwrap_or_else(|| {
16460                                SharedString::from(diagnostic_entry.diagnostic.message)
16461                            });
16462                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16463                        let (Ok(i) | Err(i)) = inline_diagnostics
16464                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16465                        inline_diagnostics.insert(
16466                            i,
16467                            (
16468                                start_anchor,
16469                                InlineDiagnostic {
16470                                    message,
16471                                    group_id: diagnostic_entry.diagnostic.group_id,
16472                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16473                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16474                                    severity: diagnostic_entry.diagnostic.severity,
16475                                },
16476                            ),
16477                        );
16478                    }
16479                    inline_diagnostics
16480                })
16481                .await;
16482
16483            editor
16484                .update(cx, |editor, cx| {
16485                    editor.inline_diagnostics = new_inline_diagnostics;
16486                    cx.notify();
16487                })
16488                .ok();
16489        });
16490    }
16491
16492    fn pull_diagnostics(
16493        &mut self,
16494        buffer_id: Option<BufferId>,
16495        window: &Window,
16496        cx: &mut Context<Self>,
16497    ) -> Option<()> {
16498        if !self.mode().is_full() {
16499            return None;
16500        }
16501        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16502            .diagnostics
16503            .lsp_pull_diagnostics;
16504        if !pull_diagnostics_settings.enabled {
16505            return None;
16506        }
16507        let project = self.project.as_ref()?.downgrade();
16508        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16509        let mut buffers = self.buffer.read(cx).all_buffers();
16510        if let Some(buffer_id) = buffer_id {
16511            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16512        }
16513
16514        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16515            cx.background_executor().timer(debounce).await;
16516
16517            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16518                buffers
16519                    .into_iter()
16520                    .filter_map(|buffer| {
16521                        project
16522                            .update(cx, |project, cx| {
16523                                project.lsp_store().update(cx, |lsp_store, cx| {
16524                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16525                                })
16526                            })
16527                            .ok()
16528                    })
16529                    .collect::<FuturesUnordered<_>>()
16530            }) else {
16531                return;
16532            };
16533
16534            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16535                match pull_task {
16536                    Ok(()) => {
16537                        if editor
16538                            .update_in(cx, |editor, window, cx| {
16539                                editor.update_diagnostics_state(window, cx);
16540                            })
16541                            .is_err()
16542                        {
16543                            return;
16544                        }
16545                    }
16546                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16547                }
16548            }
16549        });
16550
16551        Some(())
16552    }
16553
16554    pub fn set_selections_from_remote(
16555        &mut self,
16556        selections: Vec<Selection<Anchor>>,
16557        pending_selection: Option<Selection<Anchor>>,
16558        window: &mut Window,
16559        cx: &mut Context<Self>,
16560    ) {
16561        let old_cursor_position = self.selections.newest_anchor().head();
16562        self.selections.change_with(cx, |s| {
16563            s.select_anchors(selections);
16564            if let Some(pending_selection) = pending_selection {
16565                s.set_pending(pending_selection, SelectMode::Character);
16566            } else {
16567                s.clear_pending();
16568            }
16569        });
16570        self.selections_did_change(
16571            false,
16572            &old_cursor_position,
16573            SelectionEffects::default(),
16574            window,
16575            cx,
16576        );
16577    }
16578
16579    pub fn transact(
16580        &mut self,
16581        window: &mut Window,
16582        cx: &mut Context<Self>,
16583        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16584    ) -> Option<TransactionId> {
16585        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16586            this.start_transaction_at(Instant::now(), window, cx);
16587            update(this, window, cx);
16588            this.end_transaction_at(Instant::now(), cx)
16589        })
16590    }
16591
16592    pub fn start_transaction_at(
16593        &mut self,
16594        now: Instant,
16595        window: &mut Window,
16596        cx: &mut Context<Self>,
16597    ) {
16598        self.end_selection(window, cx);
16599        if let Some(tx_id) = self
16600            .buffer
16601            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16602        {
16603            self.selection_history
16604                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16605            cx.emit(EditorEvent::TransactionBegun {
16606                transaction_id: tx_id,
16607            })
16608        }
16609    }
16610
16611    pub fn end_transaction_at(
16612        &mut self,
16613        now: Instant,
16614        cx: &mut Context<Self>,
16615    ) -> Option<TransactionId> {
16616        if let Some(transaction_id) = self
16617            .buffer
16618            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16619        {
16620            if let Some((_, end_selections)) =
16621                self.selection_history.transaction_mut(transaction_id)
16622            {
16623                *end_selections = Some(self.selections.disjoint_anchors());
16624            } else {
16625                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16626            }
16627
16628            cx.emit(EditorEvent::Edited { transaction_id });
16629            Some(transaction_id)
16630        } else {
16631            None
16632        }
16633    }
16634
16635    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16636        if self.selection_mark_mode {
16637            self.change_selections(None, window, cx, |s| {
16638                s.move_with(|_, sel| {
16639                    sel.collapse_to(sel.head(), SelectionGoal::None);
16640                });
16641            })
16642        }
16643        self.selection_mark_mode = true;
16644        cx.notify();
16645    }
16646
16647    pub fn swap_selection_ends(
16648        &mut self,
16649        _: &actions::SwapSelectionEnds,
16650        window: &mut Window,
16651        cx: &mut Context<Self>,
16652    ) {
16653        self.change_selections(None, window, cx, |s| {
16654            s.move_with(|_, sel| {
16655                if sel.start != sel.end {
16656                    sel.reversed = !sel.reversed
16657                }
16658            });
16659        });
16660        self.request_autoscroll(Autoscroll::newest(), cx);
16661        cx.notify();
16662    }
16663
16664    pub fn toggle_fold(
16665        &mut self,
16666        _: &actions::ToggleFold,
16667        window: &mut Window,
16668        cx: &mut Context<Self>,
16669    ) {
16670        if self.is_singleton(cx) {
16671            let selection = self.selections.newest::<Point>(cx);
16672
16673            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16674            let range = if selection.is_empty() {
16675                let point = selection.head().to_display_point(&display_map);
16676                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16677                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16678                    .to_point(&display_map);
16679                start..end
16680            } else {
16681                selection.range()
16682            };
16683            if display_map.folds_in_range(range).next().is_some() {
16684                self.unfold_lines(&Default::default(), window, cx)
16685            } else {
16686                self.fold(&Default::default(), window, cx)
16687            }
16688        } else {
16689            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16690            let buffer_ids: HashSet<_> = self
16691                .selections
16692                .disjoint_anchor_ranges()
16693                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16694                .collect();
16695
16696            let should_unfold = buffer_ids
16697                .iter()
16698                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16699
16700            for buffer_id in buffer_ids {
16701                if should_unfold {
16702                    self.unfold_buffer(buffer_id, cx);
16703                } else {
16704                    self.fold_buffer(buffer_id, cx);
16705                }
16706            }
16707        }
16708    }
16709
16710    pub fn toggle_fold_recursive(
16711        &mut self,
16712        _: &actions::ToggleFoldRecursive,
16713        window: &mut Window,
16714        cx: &mut Context<Self>,
16715    ) {
16716        let selection = self.selections.newest::<Point>(cx);
16717
16718        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16719        let range = if selection.is_empty() {
16720            let point = selection.head().to_display_point(&display_map);
16721            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16722            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16723                .to_point(&display_map);
16724            start..end
16725        } else {
16726            selection.range()
16727        };
16728        if display_map.folds_in_range(range).next().is_some() {
16729            self.unfold_recursive(&Default::default(), window, cx)
16730        } else {
16731            self.fold_recursive(&Default::default(), window, cx)
16732        }
16733    }
16734
16735    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16736        if self.is_singleton(cx) {
16737            let mut to_fold = Vec::new();
16738            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16739            let selections = self.selections.all_adjusted(cx);
16740
16741            for selection in selections {
16742                let range = selection.range().sorted();
16743                let buffer_start_row = range.start.row;
16744
16745                if range.start.row != range.end.row {
16746                    let mut found = false;
16747                    let mut row = range.start.row;
16748                    while row <= range.end.row {
16749                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16750                        {
16751                            found = true;
16752                            row = crease.range().end.row + 1;
16753                            to_fold.push(crease);
16754                        } else {
16755                            row += 1
16756                        }
16757                    }
16758                    if found {
16759                        continue;
16760                    }
16761                }
16762
16763                for row in (0..=range.start.row).rev() {
16764                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16765                        if crease.range().end.row >= buffer_start_row {
16766                            to_fold.push(crease);
16767                            if row <= range.start.row {
16768                                break;
16769                            }
16770                        }
16771                    }
16772                }
16773            }
16774
16775            self.fold_creases(to_fold, true, window, cx);
16776        } else {
16777            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16778            let buffer_ids = self
16779                .selections
16780                .disjoint_anchor_ranges()
16781                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16782                .collect::<HashSet<_>>();
16783            for buffer_id in buffer_ids {
16784                self.fold_buffer(buffer_id, cx);
16785            }
16786        }
16787    }
16788
16789    fn fold_at_level(
16790        &mut self,
16791        fold_at: &FoldAtLevel,
16792        window: &mut Window,
16793        cx: &mut Context<Self>,
16794    ) {
16795        if !self.buffer.read(cx).is_singleton() {
16796            return;
16797        }
16798
16799        let fold_at_level = fold_at.0;
16800        let snapshot = self.buffer.read(cx).snapshot(cx);
16801        let mut to_fold = Vec::new();
16802        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16803
16804        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16805            while start_row < end_row {
16806                match self
16807                    .snapshot(window, cx)
16808                    .crease_for_buffer_row(MultiBufferRow(start_row))
16809                {
16810                    Some(crease) => {
16811                        let nested_start_row = crease.range().start.row + 1;
16812                        let nested_end_row = crease.range().end.row;
16813
16814                        if current_level < fold_at_level {
16815                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16816                        } else if current_level == fold_at_level {
16817                            to_fold.push(crease);
16818                        }
16819
16820                        start_row = nested_end_row + 1;
16821                    }
16822                    None => start_row += 1,
16823                }
16824            }
16825        }
16826
16827        self.fold_creases(to_fold, true, window, cx);
16828    }
16829
16830    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16831        if self.buffer.read(cx).is_singleton() {
16832            let mut fold_ranges = Vec::new();
16833            let snapshot = self.buffer.read(cx).snapshot(cx);
16834
16835            for row in 0..snapshot.max_row().0 {
16836                if let Some(foldable_range) = self
16837                    .snapshot(window, cx)
16838                    .crease_for_buffer_row(MultiBufferRow(row))
16839                {
16840                    fold_ranges.push(foldable_range);
16841                }
16842            }
16843
16844            self.fold_creases(fold_ranges, true, window, cx);
16845        } else {
16846            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16847                editor
16848                    .update_in(cx, |editor, _, cx| {
16849                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16850                            editor.fold_buffer(buffer_id, cx);
16851                        }
16852                    })
16853                    .ok();
16854            });
16855        }
16856    }
16857
16858    pub fn fold_function_bodies(
16859        &mut self,
16860        _: &actions::FoldFunctionBodies,
16861        window: &mut Window,
16862        cx: &mut Context<Self>,
16863    ) {
16864        let snapshot = self.buffer.read(cx).snapshot(cx);
16865
16866        let ranges = snapshot
16867            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16868            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16869            .collect::<Vec<_>>();
16870
16871        let creases = ranges
16872            .into_iter()
16873            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16874            .collect();
16875
16876        self.fold_creases(creases, true, window, cx);
16877    }
16878
16879    pub fn fold_recursive(
16880        &mut self,
16881        _: &actions::FoldRecursive,
16882        window: &mut Window,
16883        cx: &mut Context<Self>,
16884    ) {
16885        let mut to_fold = Vec::new();
16886        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16887        let selections = self.selections.all_adjusted(cx);
16888
16889        for selection in selections {
16890            let range = selection.range().sorted();
16891            let buffer_start_row = range.start.row;
16892
16893            if range.start.row != range.end.row {
16894                let mut found = false;
16895                for row in range.start.row..=range.end.row {
16896                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16897                        found = true;
16898                        to_fold.push(crease);
16899                    }
16900                }
16901                if found {
16902                    continue;
16903                }
16904            }
16905
16906            for row in (0..=range.start.row).rev() {
16907                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16908                    if crease.range().end.row >= buffer_start_row {
16909                        to_fold.push(crease);
16910                    } else {
16911                        break;
16912                    }
16913                }
16914            }
16915        }
16916
16917        self.fold_creases(to_fold, true, window, cx);
16918    }
16919
16920    pub fn fold_at(
16921        &mut self,
16922        buffer_row: MultiBufferRow,
16923        window: &mut Window,
16924        cx: &mut Context<Self>,
16925    ) {
16926        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16927
16928        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16929            let autoscroll = self
16930                .selections
16931                .all::<Point>(cx)
16932                .iter()
16933                .any(|selection| crease.range().overlaps(&selection.range()));
16934
16935            self.fold_creases(vec![crease], autoscroll, window, cx);
16936        }
16937    }
16938
16939    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16940        if self.is_singleton(cx) {
16941            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16942            let buffer = &display_map.buffer_snapshot;
16943            let selections = self.selections.all::<Point>(cx);
16944            let ranges = selections
16945                .iter()
16946                .map(|s| {
16947                    let range = s.display_range(&display_map).sorted();
16948                    let mut start = range.start.to_point(&display_map);
16949                    let mut end = range.end.to_point(&display_map);
16950                    start.column = 0;
16951                    end.column = buffer.line_len(MultiBufferRow(end.row));
16952                    start..end
16953                })
16954                .collect::<Vec<_>>();
16955
16956            self.unfold_ranges(&ranges, true, true, cx);
16957        } else {
16958            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16959            let buffer_ids = self
16960                .selections
16961                .disjoint_anchor_ranges()
16962                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16963                .collect::<HashSet<_>>();
16964            for buffer_id in buffer_ids {
16965                self.unfold_buffer(buffer_id, cx);
16966            }
16967        }
16968    }
16969
16970    pub fn unfold_recursive(
16971        &mut self,
16972        _: &UnfoldRecursive,
16973        _window: &mut Window,
16974        cx: &mut Context<Self>,
16975    ) {
16976        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16977        let selections = self.selections.all::<Point>(cx);
16978        let ranges = selections
16979            .iter()
16980            .map(|s| {
16981                let mut range = s.display_range(&display_map).sorted();
16982                *range.start.column_mut() = 0;
16983                *range.end.column_mut() = display_map.line_len(range.end.row());
16984                let start = range.start.to_point(&display_map);
16985                let end = range.end.to_point(&display_map);
16986                start..end
16987            })
16988            .collect::<Vec<_>>();
16989
16990        self.unfold_ranges(&ranges, true, true, cx);
16991    }
16992
16993    pub fn unfold_at(
16994        &mut self,
16995        buffer_row: MultiBufferRow,
16996        _window: &mut Window,
16997        cx: &mut Context<Self>,
16998    ) {
16999        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17000
17001        let intersection_range = Point::new(buffer_row.0, 0)
17002            ..Point::new(
17003                buffer_row.0,
17004                display_map.buffer_snapshot.line_len(buffer_row),
17005            );
17006
17007        let autoscroll = self
17008            .selections
17009            .all::<Point>(cx)
17010            .iter()
17011            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17012
17013        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17014    }
17015
17016    pub fn unfold_all(
17017        &mut self,
17018        _: &actions::UnfoldAll,
17019        _window: &mut Window,
17020        cx: &mut Context<Self>,
17021    ) {
17022        if self.buffer.read(cx).is_singleton() {
17023            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17024            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17025        } else {
17026            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17027                editor
17028                    .update(cx, |editor, cx| {
17029                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17030                            editor.unfold_buffer(buffer_id, cx);
17031                        }
17032                    })
17033                    .ok();
17034            });
17035        }
17036    }
17037
17038    pub fn fold_selected_ranges(
17039        &mut self,
17040        _: &FoldSelectedRanges,
17041        window: &mut Window,
17042        cx: &mut Context<Self>,
17043    ) {
17044        let selections = self.selections.all_adjusted(cx);
17045        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17046        let ranges = selections
17047            .into_iter()
17048            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17049            .collect::<Vec<_>>();
17050        self.fold_creases(ranges, true, window, cx);
17051    }
17052
17053    pub fn fold_ranges<T: ToOffset + Clone>(
17054        &mut self,
17055        ranges: Vec<Range<T>>,
17056        auto_scroll: bool,
17057        window: &mut Window,
17058        cx: &mut Context<Self>,
17059    ) {
17060        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17061        let ranges = ranges
17062            .into_iter()
17063            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17064            .collect::<Vec<_>>();
17065        self.fold_creases(ranges, auto_scroll, window, cx);
17066    }
17067
17068    pub fn fold_creases<T: ToOffset + Clone>(
17069        &mut self,
17070        creases: Vec<Crease<T>>,
17071        auto_scroll: bool,
17072        _window: &mut Window,
17073        cx: &mut Context<Self>,
17074    ) {
17075        if creases.is_empty() {
17076            return;
17077        }
17078
17079        let mut buffers_affected = HashSet::default();
17080        let multi_buffer = self.buffer().read(cx);
17081        for crease in &creases {
17082            if let Some((_, buffer, _)) =
17083                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
17084            {
17085                buffers_affected.insert(buffer.read(cx).remote_id());
17086            };
17087        }
17088
17089        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17090
17091        if auto_scroll {
17092            self.request_autoscroll(Autoscroll::fit(), cx);
17093        }
17094
17095        cx.notify();
17096
17097        self.scrollbar_marker_state.dirty = true;
17098        self.folds_did_change(cx);
17099    }
17100
17101    /// Removes any folds whose ranges intersect any of the given ranges.
17102    pub fn unfold_ranges<T: ToOffset + Clone>(
17103        &mut self,
17104        ranges: &[Range<T>],
17105        inclusive: bool,
17106        auto_scroll: bool,
17107        cx: &mut Context<Self>,
17108    ) {
17109        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17110            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17111        });
17112        self.folds_did_change(cx);
17113    }
17114
17115    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17116        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17117            return;
17118        }
17119        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17120        self.display_map.update(cx, |display_map, cx| {
17121            display_map.fold_buffers([buffer_id], cx)
17122        });
17123        cx.emit(EditorEvent::BufferFoldToggled {
17124            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17125            folded: true,
17126        });
17127        cx.notify();
17128    }
17129
17130    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17131        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17132            return;
17133        }
17134        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17135        self.display_map.update(cx, |display_map, cx| {
17136            display_map.unfold_buffers([buffer_id], cx);
17137        });
17138        cx.emit(EditorEvent::BufferFoldToggled {
17139            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17140            folded: false,
17141        });
17142        cx.notify();
17143    }
17144
17145    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17146        self.display_map.read(cx).is_buffer_folded(buffer)
17147    }
17148
17149    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17150        self.display_map.read(cx).folded_buffers()
17151    }
17152
17153    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17154        self.display_map.update(cx, |display_map, cx| {
17155            display_map.disable_header_for_buffer(buffer_id, cx);
17156        });
17157        cx.notify();
17158    }
17159
17160    /// Removes any folds with the given ranges.
17161    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17162        &mut self,
17163        ranges: &[Range<T>],
17164        type_id: TypeId,
17165        auto_scroll: bool,
17166        cx: &mut Context<Self>,
17167    ) {
17168        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17169            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17170        });
17171        self.folds_did_change(cx);
17172    }
17173
17174    fn remove_folds_with<T: ToOffset + Clone>(
17175        &mut self,
17176        ranges: &[Range<T>],
17177        auto_scroll: bool,
17178        cx: &mut Context<Self>,
17179        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17180    ) {
17181        if ranges.is_empty() {
17182            return;
17183        }
17184
17185        let mut buffers_affected = HashSet::default();
17186        let multi_buffer = self.buffer().read(cx);
17187        for range in ranges {
17188            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17189                buffers_affected.insert(buffer.read(cx).remote_id());
17190            };
17191        }
17192
17193        self.display_map.update(cx, update);
17194
17195        if auto_scroll {
17196            self.request_autoscroll(Autoscroll::fit(), cx);
17197        }
17198
17199        cx.notify();
17200        self.scrollbar_marker_state.dirty = true;
17201        self.active_indent_guides_state.dirty = true;
17202    }
17203
17204    pub fn update_fold_widths(
17205        &mut self,
17206        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
17207        cx: &mut Context<Self>,
17208    ) -> bool {
17209        self.display_map
17210            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17211    }
17212
17213    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17214        self.display_map.read(cx).fold_placeholder.clone()
17215    }
17216
17217    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17218        self.buffer.update(cx, |buffer, cx| {
17219            buffer.set_all_diff_hunks_expanded(cx);
17220        });
17221    }
17222
17223    pub fn expand_all_diff_hunks(
17224        &mut self,
17225        _: &ExpandAllDiffHunks,
17226        _window: &mut Window,
17227        cx: &mut Context<Self>,
17228    ) {
17229        self.buffer.update(cx, |buffer, cx| {
17230            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17231        });
17232    }
17233
17234    pub fn toggle_selected_diff_hunks(
17235        &mut self,
17236        _: &ToggleSelectedDiffHunks,
17237        _window: &mut Window,
17238        cx: &mut Context<Self>,
17239    ) {
17240        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17241        self.toggle_diff_hunks_in_ranges(ranges, cx);
17242    }
17243
17244    pub fn diff_hunks_in_ranges<'a>(
17245        &'a self,
17246        ranges: &'a [Range<Anchor>],
17247        buffer: &'a MultiBufferSnapshot,
17248    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17249        ranges.iter().flat_map(move |range| {
17250            let end_excerpt_id = range.end.excerpt_id;
17251            let range = range.to_point(buffer);
17252            let mut peek_end = range.end;
17253            if range.end.row < buffer.max_row().0 {
17254                peek_end = Point::new(range.end.row + 1, 0);
17255            }
17256            buffer
17257                .diff_hunks_in_range(range.start..peek_end)
17258                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17259        })
17260    }
17261
17262    pub fn has_stageable_diff_hunks_in_ranges(
17263        &self,
17264        ranges: &[Range<Anchor>],
17265        snapshot: &MultiBufferSnapshot,
17266    ) -> bool {
17267        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17268        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17269    }
17270
17271    pub fn toggle_staged_selected_diff_hunks(
17272        &mut self,
17273        _: &::git::ToggleStaged,
17274        _: &mut Window,
17275        cx: &mut Context<Self>,
17276    ) {
17277        let snapshot = self.buffer.read(cx).snapshot(cx);
17278        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17279        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17280        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17281    }
17282
17283    pub fn set_render_diff_hunk_controls(
17284        &mut self,
17285        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17286        cx: &mut Context<Self>,
17287    ) {
17288        self.render_diff_hunk_controls = render_diff_hunk_controls;
17289        cx.notify();
17290    }
17291
17292    pub fn stage_and_next(
17293        &mut self,
17294        _: &::git::StageAndNext,
17295        window: &mut Window,
17296        cx: &mut Context<Self>,
17297    ) {
17298        self.do_stage_or_unstage_and_next(true, window, cx);
17299    }
17300
17301    pub fn unstage_and_next(
17302        &mut self,
17303        _: &::git::UnstageAndNext,
17304        window: &mut Window,
17305        cx: &mut Context<Self>,
17306    ) {
17307        self.do_stage_or_unstage_and_next(false, window, cx);
17308    }
17309
17310    pub fn stage_or_unstage_diff_hunks(
17311        &mut self,
17312        stage: bool,
17313        ranges: Vec<Range<Anchor>>,
17314        cx: &mut Context<Self>,
17315    ) {
17316        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17317        cx.spawn(async move |this, cx| {
17318            task.await?;
17319            this.update(cx, |this, cx| {
17320                let snapshot = this.buffer.read(cx).snapshot(cx);
17321                let chunk_by = this
17322                    .diff_hunks_in_ranges(&ranges, &snapshot)
17323                    .chunk_by(|hunk| hunk.buffer_id);
17324                for (buffer_id, hunks) in &chunk_by {
17325                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17326                }
17327            })
17328        })
17329        .detach_and_log_err(cx);
17330    }
17331
17332    fn save_buffers_for_ranges_if_needed(
17333        &mut self,
17334        ranges: &[Range<Anchor>],
17335        cx: &mut Context<Editor>,
17336    ) -> Task<Result<()>> {
17337        let multibuffer = self.buffer.read(cx);
17338        let snapshot = multibuffer.read(cx);
17339        let buffer_ids: HashSet<_> = ranges
17340            .iter()
17341            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17342            .collect();
17343        drop(snapshot);
17344
17345        let mut buffers = HashSet::default();
17346        for buffer_id in buffer_ids {
17347            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17348                let buffer = buffer_entity.read(cx);
17349                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17350                {
17351                    buffers.insert(buffer_entity);
17352                }
17353            }
17354        }
17355
17356        if let Some(project) = &self.project {
17357            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17358        } else {
17359            Task::ready(Ok(()))
17360        }
17361    }
17362
17363    fn do_stage_or_unstage_and_next(
17364        &mut self,
17365        stage: bool,
17366        window: &mut Window,
17367        cx: &mut Context<Self>,
17368    ) {
17369        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17370
17371        if ranges.iter().any(|range| range.start != range.end) {
17372            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17373            return;
17374        }
17375
17376        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17377        let snapshot = self.snapshot(window, cx);
17378        let position = self.selections.newest::<Point>(cx).head();
17379        let mut row = snapshot
17380            .buffer_snapshot
17381            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17382            .find(|hunk| hunk.row_range.start.0 > position.row)
17383            .map(|hunk| hunk.row_range.start);
17384
17385        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17386        // Outside of the project diff editor, wrap around to the beginning.
17387        if !all_diff_hunks_expanded {
17388            row = row.or_else(|| {
17389                snapshot
17390                    .buffer_snapshot
17391                    .diff_hunks_in_range(Point::zero()..position)
17392                    .find(|hunk| hunk.row_range.end.0 < position.row)
17393                    .map(|hunk| hunk.row_range.start)
17394            });
17395        }
17396
17397        if let Some(row) = row {
17398            let destination = Point::new(row.0, 0);
17399            let autoscroll = Autoscroll::center();
17400
17401            self.unfold_ranges(&[destination..destination], false, false, cx);
17402            self.change_selections(Some(autoscroll), window, cx, |s| {
17403                s.select_ranges([destination..destination]);
17404            });
17405        }
17406    }
17407
17408    fn do_stage_or_unstage(
17409        &self,
17410        stage: bool,
17411        buffer_id: BufferId,
17412        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17413        cx: &mut App,
17414    ) -> Option<()> {
17415        let project = self.project.as_ref()?;
17416        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17417        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17418        let buffer_snapshot = buffer.read(cx).snapshot();
17419        let file_exists = buffer_snapshot
17420            .file()
17421            .is_some_and(|file| file.disk_state().exists());
17422        diff.update(cx, |diff, cx| {
17423            diff.stage_or_unstage_hunks(
17424                stage,
17425                &hunks
17426                    .map(|hunk| buffer_diff::DiffHunk {
17427                        buffer_range: hunk.buffer_range,
17428                        diff_base_byte_range: hunk.diff_base_byte_range,
17429                        secondary_status: hunk.secondary_status,
17430                        range: Point::zero()..Point::zero(), // unused
17431                    })
17432                    .collect::<Vec<_>>(),
17433                &buffer_snapshot,
17434                file_exists,
17435                cx,
17436            )
17437        });
17438        None
17439    }
17440
17441    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17442        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17443        self.buffer
17444            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17445    }
17446
17447    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17448        self.buffer.update(cx, |buffer, cx| {
17449            let ranges = vec![Anchor::min()..Anchor::max()];
17450            if !buffer.all_diff_hunks_expanded()
17451                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17452            {
17453                buffer.collapse_diff_hunks(ranges, cx);
17454                true
17455            } else {
17456                false
17457            }
17458        })
17459    }
17460
17461    fn toggle_diff_hunks_in_ranges(
17462        &mut self,
17463        ranges: Vec<Range<Anchor>>,
17464        cx: &mut Context<Editor>,
17465    ) {
17466        self.buffer.update(cx, |buffer, cx| {
17467            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17468            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17469        })
17470    }
17471
17472    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17473        self.buffer.update(cx, |buffer, cx| {
17474            let snapshot = buffer.snapshot(cx);
17475            let excerpt_id = range.end.excerpt_id;
17476            let point_range = range.to_point(&snapshot);
17477            let expand = !buffer.single_hunk_is_expanded(range, cx);
17478            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17479        })
17480    }
17481
17482    pub(crate) fn apply_all_diff_hunks(
17483        &mut self,
17484        _: &ApplyAllDiffHunks,
17485        window: &mut Window,
17486        cx: &mut Context<Self>,
17487    ) {
17488        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17489
17490        let buffers = self.buffer.read(cx).all_buffers();
17491        for branch_buffer in buffers {
17492            branch_buffer.update(cx, |branch_buffer, cx| {
17493                branch_buffer.merge_into_base(Vec::new(), cx);
17494            });
17495        }
17496
17497        if let Some(project) = self.project.clone() {
17498            self.save(
17499                SaveOptions {
17500                    format: true,
17501                    autosave: false,
17502                },
17503                project,
17504                window,
17505                cx,
17506            )
17507            .detach_and_log_err(cx);
17508        }
17509    }
17510
17511    pub(crate) fn apply_selected_diff_hunks(
17512        &mut self,
17513        _: &ApplyDiffHunk,
17514        window: &mut Window,
17515        cx: &mut Context<Self>,
17516    ) {
17517        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17518        let snapshot = self.snapshot(window, cx);
17519        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17520        let mut ranges_by_buffer = HashMap::default();
17521        self.transact(window, cx, |editor, _window, cx| {
17522            for hunk in hunks {
17523                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17524                    ranges_by_buffer
17525                        .entry(buffer.clone())
17526                        .or_insert_with(Vec::new)
17527                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17528                }
17529            }
17530
17531            for (buffer, ranges) in ranges_by_buffer {
17532                buffer.update(cx, |buffer, cx| {
17533                    buffer.merge_into_base(ranges, cx);
17534                });
17535            }
17536        });
17537
17538        if let Some(project) = self.project.clone() {
17539            self.save(
17540                SaveOptions {
17541                    format: true,
17542                    autosave: false,
17543                },
17544                project,
17545                window,
17546                cx,
17547            )
17548            .detach_and_log_err(cx);
17549        }
17550    }
17551
17552    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17553        if hovered != self.gutter_hovered {
17554            self.gutter_hovered = hovered;
17555            cx.notify();
17556        }
17557    }
17558
17559    pub fn insert_blocks(
17560        &mut self,
17561        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17562        autoscroll: Option<Autoscroll>,
17563        cx: &mut Context<Self>,
17564    ) -> Vec<CustomBlockId> {
17565        let blocks = self
17566            .display_map
17567            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17568        if let Some(autoscroll) = autoscroll {
17569            self.request_autoscroll(autoscroll, cx);
17570        }
17571        cx.notify();
17572        blocks
17573    }
17574
17575    pub fn resize_blocks(
17576        &mut self,
17577        heights: HashMap<CustomBlockId, u32>,
17578        autoscroll: Option<Autoscroll>,
17579        cx: &mut Context<Self>,
17580    ) {
17581        self.display_map
17582            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17583        if let Some(autoscroll) = autoscroll {
17584            self.request_autoscroll(autoscroll, cx);
17585        }
17586        cx.notify();
17587    }
17588
17589    pub fn replace_blocks(
17590        &mut self,
17591        renderers: HashMap<CustomBlockId, RenderBlock>,
17592        autoscroll: Option<Autoscroll>,
17593        cx: &mut Context<Self>,
17594    ) {
17595        self.display_map
17596            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17597        if let Some(autoscroll) = autoscroll {
17598            self.request_autoscroll(autoscroll, cx);
17599        }
17600        cx.notify();
17601    }
17602
17603    pub fn remove_blocks(
17604        &mut self,
17605        block_ids: HashSet<CustomBlockId>,
17606        autoscroll: Option<Autoscroll>,
17607        cx: &mut Context<Self>,
17608    ) {
17609        self.display_map.update(cx, |display_map, cx| {
17610            display_map.remove_blocks(block_ids, cx)
17611        });
17612        if let Some(autoscroll) = autoscroll {
17613            self.request_autoscroll(autoscroll, cx);
17614        }
17615        cx.notify();
17616    }
17617
17618    pub fn row_for_block(
17619        &self,
17620        block_id: CustomBlockId,
17621        cx: &mut Context<Self>,
17622    ) -> Option<DisplayRow> {
17623        self.display_map
17624            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17625    }
17626
17627    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17628        self.focused_block = Some(focused_block);
17629    }
17630
17631    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17632        self.focused_block.take()
17633    }
17634
17635    pub fn insert_creases(
17636        &mut self,
17637        creases: impl IntoIterator<Item = Crease<Anchor>>,
17638        cx: &mut Context<Self>,
17639    ) -> Vec<CreaseId> {
17640        self.display_map
17641            .update(cx, |map, cx| map.insert_creases(creases, cx))
17642    }
17643
17644    pub fn remove_creases(
17645        &mut self,
17646        ids: impl IntoIterator<Item = CreaseId>,
17647        cx: &mut Context<Self>,
17648    ) -> Vec<(CreaseId, Range<Anchor>)> {
17649        self.display_map
17650            .update(cx, |map, cx| map.remove_creases(ids, cx))
17651    }
17652
17653    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17654        self.display_map
17655            .update(cx, |map, cx| map.snapshot(cx))
17656            .longest_row()
17657    }
17658
17659    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17660        self.display_map
17661            .update(cx, |map, cx| map.snapshot(cx))
17662            .max_point()
17663    }
17664
17665    pub fn text(&self, cx: &App) -> String {
17666        self.buffer.read(cx).read(cx).text()
17667    }
17668
17669    pub fn is_empty(&self, cx: &App) -> bool {
17670        self.buffer.read(cx).read(cx).is_empty()
17671    }
17672
17673    pub fn text_option(&self, cx: &App) -> Option<String> {
17674        let text = self.text(cx);
17675        let text = text.trim();
17676
17677        if text.is_empty() {
17678            return None;
17679        }
17680
17681        Some(text.to_string())
17682    }
17683
17684    pub fn set_text(
17685        &mut self,
17686        text: impl Into<Arc<str>>,
17687        window: &mut Window,
17688        cx: &mut Context<Self>,
17689    ) {
17690        self.transact(window, cx, |this, _, cx| {
17691            this.buffer
17692                .read(cx)
17693                .as_singleton()
17694                .expect("you can only call set_text on editors for singleton buffers")
17695                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17696        });
17697    }
17698
17699    pub fn display_text(&self, cx: &mut App) -> String {
17700        self.display_map
17701            .update(cx, |map, cx| map.snapshot(cx))
17702            .text()
17703    }
17704
17705    fn create_minimap(
17706        &self,
17707        minimap_settings: MinimapSettings,
17708        window: &mut Window,
17709        cx: &mut Context<Self>,
17710    ) -> Option<Entity<Self>> {
17711        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17712            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17713    }
17714
17715    fn initialize_new_minimap(
17716        &self,
17717        minimap_settings: MinimapSettings,
17718        window: &mut Window,
17719        cx: &mut Context<Self>,
17720    ) -> Entity<Self> {
17721        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17722
17723        let mut minimap = Editor::new_internal(
17724            EditorMode::Minimap {
17725                parent: cx.weak_entity(),
17726            },
17727            self.buffer.clone(),
17728            self.project.clone(),
17729            Some(self.display_map.clone()),
17730            window,
17731            cx,
17732        );
17733        minimap.scroll_manager.clone_state(&self.scroll_manager);
17734        minimap.set_text_style_refinement(TextStyleRefinement {
17735            font_size: Some(MINIMAP_FONT_SIZE),
17736            font_weight: Some(MINIMAP_FONT_WEIGHT),
17737            ..Default::default()
17738        });
17739        minimap.update_minimap_configuration(minimap_settings, cx);
17740        cx.new(|_| minimap)
17741    }
17742
17743    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17744        let current_line_highlight = minimap_settings
17745            .current_line_highlight
17746            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17747        self.set_current_line_highlight(Some(current_line_highlight));
17748    }
17749
17750    pub fn minimap(&self) -> Option<&Entity<Self>> {
17751        self.minimap
17752            .as_ref()
17753            .filter(|_| self.minimap_visibility.visible())
17754    }
17755
17756    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17757        let mut wrap_guides = smallvec![];
17758
17759        if self.show_wrap_guides == Some(false) {
17760            return wrap_guides;
17761        }
17762
17763        let settings = self.buffer.read(cx).language_settings(cx);
17764        if settings.show_wrap_guides {
17765            match self.soft_wrap_mode(cx) {
17766                SoftWrap::Column(soft_wrap) => {
17767                    wrap_guides.push((soft_wrap as usize, true));
17768                }
17769                SoftWrap::Bounded(soft_wrap) => {
17770                    wrap_guides.push((soft_wrap as usize, true));
17771                }
17772                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17773            }
17774            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17775        }
17776
17777        wrap_guides
17778    }
17779
17780    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17781        let settings = self.buffer.read(cx).language_settings(cx);
17782        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17783        match mode {
17784            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17785                SoftWrap::None
17786            }
17787            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17788            language_settings::SoftWrap::PreferredLineLength => {
17789                SoftWrap::Column(settings.preferred_line_length)
17790            }
17791            language_settings::SoftWrap::Bounded => {
17792                SoftWrap::Bounded(settings.preferred_line_length)
17793            }
17794        }
17795    }
17796
17797    pub fn set_soft_wrap_mode(
17798        &mut self,
17799        mode: language_settings::SoftWrap,
17800
17801        cx: &mut Context<Self>,
17802    ) {
17803        self.soft_wrap_mode_override = Some(mode);
17804        cx.notify();
17805    }
17806
17807    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17808        self.hard_wrap = hard_wrap;
17809        cx.notify();
17810    }
17811
17812    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17813        self.text_style_refinement = Some(style);
17814    }
17815
17816    /// called by the Element so we know what style we were most recently rendered with.
17817    pub(crate) fn set_style(
17818        &mut self,
17819        style: EditorStyle,
17820        window: &mut Window,
17821        cx: &mut Context<Self>,
17822    ) {
17823        // We intentionally do not inform the display map about the minimap style
17824        // so that wrapping is not recalculated and stays consistent for the editor
17825        // and its linked minimap.
17826        if !self.mode.is_minimap() {
17827            let rem_size = window.rem_size();
17828            self.display_map.update(cx, |map, cx| {
17829                map.set_font(
17830                    style.text.font(),
17831                    style.text.font_size.to_pixels(rem_size),
17832                    cx,
17833                )
17834            });
17835        }
17836        self.style = Some(style);
17837    }
17838
17839    pub fn style(&self) -> Option<&EditorStyle> {
17840        self.style.as_ref()
17841    }
17842
17843    // Called by the element. This method is not designed to be called outside of the editor
17844    // element's layout code because it does not notify when rewrapping is computed synchronously.
17845    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17846        self.display_map
17847            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17848    }
17849
17850    pub fn set_soft_wrap(&mut self) {
17851        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17852    }
17853
17854    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17855        if self.soft_wrap_mode_override.is_some() {
17856            self.soft_wrap_mode_override.take();
17857        } else {
17858            let soft_wrap = match self.soft_wrap_mode(cx) {
17859                SoftWrap::GitDiff => return,
17860                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17861                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17862                    language_settings::SoftWrap::None
17863                }
17864            };
17865            self.soft_wrap_mode_override = Some(soft_wrap);
17866        }
17867        cx.notify();
17868    }
17869
17870    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17871        let Some(workspace) = self.workspace() else {
17872            return;
17873        };
17874        let fs = workspace.read(cx).app_state().fs.clone();
17875        let current_show = TabBarSettings::get_global(cx).show;
17876        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17877            setting.show = Some(!current_show);
17878        });
17879    }
17880
17881    pub fn toggle_indent_guides(
17882        &mut self,
17883        _: &ToggleIndentGuides,
17884        _: &mut Window,
17885        cx: &mut Context<Self>,
17886    ) {
17887        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17888            self.buffer
17889                .read(cx)
17890                .language_settings(cx)
17891                .indent_guides
17892                .enabled
17893        });
17894        self.show_indent_guides = Some(!currently_enabled);
17895        cx.notify();
17896    }
17897
17898    fn should_show_indent_guides(&self) -> Option<bool> {
17899        self.show_indent_guides
17900    }
17901
17902    pub fn toggle_line_numbers(
17903        &mut self,
17904        _: &ToggleLineNumbers,
17905        _: &mut Window,
17906        cx: &mut Context<Self>,
17907    ) {
17908        let mut editor_settings = EditorSettings::get_global(cx).clone();
17909        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17910        EditorSettings::override_global(editor_settings, cx);
17911    }
17912
17913    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17914        if let Some(show_line_numbers) = self.show_line_numbers {
17915            return show_line_numbers;
17916        }
17917        EditorSettings::get_global(cx).gutter.line_numbers
17918    }
17919
17920    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17921        self.use_relative_line_numbers
17922            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17923    }
17924
17925    pub fn toggle_relative_line_numbers(
17926        &mut self,
17927        _: &ToggleRelativeLineNumbers,
17928        _: &mut Window,
17929        cx: &mut Context<Self>,
17930    ) {
17931        let is_relative = self.should_use_relative_line_numbers(cx);
17932        self.set_relative_line_number(Some(!is_relative), cx)
17933    }
17934
17935    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17936        self.use_relative_line_numbers = is_relative;
17937        cx.notify();
17938    }
17939
17940    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17941        self.show_gutter = show_gutter;
17942        cx.notify();
17943    }
17944
17945    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17946        self.show_scrollbars = ScrollbarAxes {
17947            horizontal: show,
17948            vertical: show,
17949        };
17950        cx.notify();
17951    }
17952
17953    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17954        self.show_scrollbars.vertical = show;
17955        cx.notify();
17956    }
17957
17958    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17959        self.show_scrollbars.horizontal = show;
17960        cx.notify();
17961    }
17962
17963    pub fn set_minimap_visibility(
17964        &mut self,
17965        minimap_visibility: MinimapVisibility,
17966        window: &mut Window,
17967        cx: &mut Context<Self>,
17968    ) {
17969        if self.minimap_visibility != minimap_visibility {
17970            if minimap_visibility.visible() && self.minimap.is_none() {
17971                let minimap_settings = EditorSettings::get_global(cx).minimap;
17972                self.minimap =
17973                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17974            }
17975            self.minimap_visibility = minimap_visibility;
17976            cx.notify();
17977        }
17978    }
17979
17980    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17981        self.set_show_scrollbars(false, cx);
17982        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17983    }
17984
17985    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17986        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17987    }
17988
17989    /// Normally the text in full mode and auto height editors is padded on the
17990    /// left side by roughly half a character width for improved hit testing.
17991    ///
17992    /// Use this method to disable this for cases where this is not wanted (e.g.
17993    /// if you want to align the editor text with some other text above or below)
17994    /// or if you want to add this padding to single-line editors.
17995    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17996        self.offset_content = offset_content;
17997        cx.notify();
17998    }
17999
18000    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18001        self.show_line_numbers = Some(show_line_numbers);
18002        cx.notify();
18003    }
18004
18005    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18006        self.disable_expand_excerpt_buttons = true;
18007        cx.notify();
18008    }
18009
18010    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18011        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18012        cx.notify();
18013    }
18014
18015    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18016        self.show_code_actions = Some(show_code_actions);
18017        cx.notify();
18018    }
18019
18020    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18021        self.show_runnables = Some(show_runnables);
18022        cx.notify();
18023    }
18024
18025    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18026        self.show_breakpoints = Some(show_breakpoints);
18027        cx.notify();
18028    }
18029
18030    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18031        if self.display_map.read(cx).masked != masked {
18032            self.display_map.update(cx, |map, _| map.masked = masked);
18033        }
18034        cx.notify()
18035    }
18036
18037    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18038        self.show_wrap_guides = Some(show_wrap_guides);
18039        cx.notify();
18040    }
18041
18042    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18043        self.show_indent_guides = Some(show_indent_guides);
18044        cx.notify();
18045    }
18046
18047    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18048        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18049            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18050                if let Some(dir) = file.abs_path(cx).parent() {
18051                    return Some(dir.to_owned());
18052                }
18053            }
18054
18055            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18056                return Some(project_path.path.to_path_buf());
18057            }
18058        }
18059
18060        None
18061    }
18062
18063    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18064        self.active_excerpt(cx)?
18065            .1
18066            .read(cx)
18067            .file()
18068            .and_then(|f| f.as_local())
18069    }
18070
18071    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18072        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18073            let buffer = buffer.read(cx);
18074            if let Some(project_path) = buffer.project_path(cx) {
18075                let project = self.project.as_ref()?.read(cx);
18076                project.absolute_path(&project_path, cx)
18077            } else {
18078                buffer
18079                    .file()
18080                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18081            }
18082        })
18083    }
18084
18085    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18086        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18087            let project_path = buffer.read(cx).project_path(cx)?;
18088            let project = self.project.as_ref()?.read(cx);
18089            let entry = project.entry_for_path(&project_path, cx)?;
18090            let path = entry.path.to_path_buf();
18091            Some(path)
18092        })
18093    }
18094
18095    pub fn reveal_in_finder(
18096        &mut self,
18097        _: &RevealInFileManager,
18098        _window: &mut Window,
18099        cx: &mut Context<Self>,
18100    ) {
18101        if let Some(target) = self.target_file(cx) {
18102            cx.reveal_path(&target.abs_path(cx));
18103        }
18104    }
18105
18106    pub fn copy_path(
18107        &mut self,
18108        _: &zed_actions::workspace::CopyPath,
18109        _window: &mut Window,
18110        cx: &mut Context<Self>,
18111    ) {
18112        if let Some(path) = self.target_file_abs_path(cx) {
18113            if let Some(path) = path.to_str() {
18114                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18115            }
18116        }
18117    }
18118
18119    pub fn copy_relative_path(
18120        &mut self,
18121        _: &zed_actions::workspace::CopyRelativePath,
18122        _window: &mut Window,
18123        cx: &mut Context<Self>,
18124    ) {
18125        if let Some(path) = self.target_file_path(cx) {
18126            if let Some(path) = path.to_str() {
18127                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18128            }
18129        }
18130    }
18131
18132    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18133        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18134            buffer.read(cx).project_path(cx)
18135        } else {
18136            None
18137        }
18138    }
18139
18140    // Returns true if the editor handled a go-to-line request
18141    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18142        maybe!({
18143            let breakpoint_store = self.breakpoint_store.as_ref()?;
18144
18145            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18146            else {
18147                self.clear_row_highlights::<ActiveDebugLine>();
18148                return None;
18149            };
18150
18151            let position = active_stack_frame.position;
18152            let buffer_id = position.buffer_id?;
18153            let snapshot = self
18154                .project
18155                .as_ref()?
18156                .read(cx)
18157                .buffer_for_id(buffer_id, cx)?
18158                .read(cx)
18159                .snapshot();
18160
18161            let mut handled = false;
18162            for (id, ExcerptRange { context, .. }) in
18163                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18164            {
18165                if context.start.cmp(&position, &snapshot).is_ge()
18166                    || context.end.cmp(&position, &snapshot).is_lt()
18167                {
18168                    continue;
18169                }
18170                let snapshot = self.buffer.read(cx).snapshot(cx);
18171                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18172
18173                handled = true;
18174                self.clear_row_highlights::<ActiveDebugLine>();
18175
18176                self.go_to_line::<ActiveDebugLine>(
18177                    multibuffer_anchor,
18178                    Some(cx.theme().colors().editor_debugger_active_line_background),
18179                    window,
18180                    cx,
18181                );
18182
18183                cx.notify();
18184            }
18185
18186            handled.then_some(())
18187        })
18188        .is_some()
18189    }
18190
18191    pub fn copy_file_name_without_extension(
18192        &mut self,
18193        _: &CopyFileNameWithoutExtension,
18194        _: &mut Window,
18195        cx: &mut Context<Self>,
18196    ) {
18197        if let Some(file) = self.target_file(cx) {
18198            if let Some(file_stem) = file.path().file_stem() {
18199                if let Some(name) = file_stem.to_str() {
18200                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18201                }
18202            }
18203        }
18204    }
18205
18206    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18207        if let Some(file) = self.target_file(cx) {
18208            if let Some(file_name) = file.path().file_name() {
18209                if let Some(name) = file_name.to_str() {
18210                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18211                }
18212            }
18213        }
18214    }
18215
18216    pub fn toggle_git_blame(
18217        &mut self,
18218        _: &::git::Blame,
18219        window: &mut Window,
18220        cx: &mut Context<Self>,
18221    ) {
18222        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18223
18224        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18225            self.start_git_blame(true, window, cx);
18226        }
18227
18228        cx.notify();
18229    }
18230
18231    pub fn toggle_git_blame_inline(
18232        &mut self,
18233        _: &ToggleGitBlameInline,
18234        window: &mut Window,
18235        cx: &mut Context<Self>,
18236    ) {
18237        self.toggle_git_blame_inline_internal(true, window, cx);
18238        cx.notify();
18239    }
18240
18241    pub fn open_git_blame_commit(
18242        &mut self,
18243        _: &OpenGitBlameCommit,
18244        window: &mut Window,
18245        cx: &mut Context<Self>,
18246    ) {
18247        self.open_git_blame_commit_internal(window, cx);
18248    }
18249
18250    fn open_git_blame_commit_internal(
18251        &mut self,
18252        window: &mut Window,
18253        cx: &mut Context<Self>,
18254    ) -> Option<()> {
18255        let blame = self.blame.as_ref()?;
18256        let snapshot = self.snapshot(window, cx);
18257        let cursor = self.selections.newest::<Point>(cx).head();
18258        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18259        let blame_entry = blame
18260            .update(cx, |blame, cx| {
18261                blame
18262                    .blame_for_rows(
18263                        &[RowInfo {
18264                            buffer_id: Some(buffer.remote_id()),
18265                            buffer_row: Some(point.row),
18266                            ..Default::default()
18267                        }],
18268                        cx,
18269                    )
18270                    .next()
18271            })
18272            .flatten()?;
18273        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18274        let repo = blame.read(cx).repository(cx)?;
18275        let workspace = self.workspace()?.downgrade();
18276        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18277        None
18278    }
18279
18280    pub fn git_blame_inline_enabled(&self) -> bool {
18281        self.git_blame_inline_enabled
18282    }
18283
18284    pub fn toggle_selection_menu(
18285        &mut self,
18286        _: &ToggleSelectionMenu,
18287        _: &mut Window,
18288        cx: &mut Context<Self>,
18289    ) {
18290        self.show_selection_menu = self
18291            .show_selection_menu
18292            .map(|show_selections_menu| !show_selections_menu)
18293            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18294
18295        cx.notify();
18296    }
18297
18298    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18299        self.show_selection_menu
18300            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18301    }
18302
18303    fn start_git_blame(
18304        &mut self,
18305        user_triggered: bool,
18306        window: &mut Window,
18307        cx: &mut Context<Self>,
18308    ) {
18309        if let Some(project) = self.project.as_ref() {
18310            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18311                return;
18312            };
18313
18314            if buffer.read(cx).file().is_none() {
18315                return;
18316            }
18317
18318            let focused = self.focus_handle(cx).contains_focused(window, cx);
18319
18320            let project = project.clone();
18321            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18322            self.blame_subscription =
18323                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18324            self.blame = Some(blame);
18325        }
18326    }
18327
18328    fn toggle_git_blame_inline_internal(
18329        &mut self,
18330        user_triggered: bool,
18331        window: &mut Window,
18332        cx: &mut Context<Self>,
18333    ) {
18334        if self.git_blame_inline_enabled {
18335            self.git_blame_inline_enabled = false;
18336            self.show_git_blame_inline = false;
18337            self.show_git_blame_inline_delay_task.take();
18338        } else {
18339            self.git_blame_inline_enabled = true;
18340            self.start_git_blame_inline(user_triggered, window, cx);
18341        }
18342
18343        cx.notify();
18344    }
18345
18346    fn start_git_blame_inline(
18347        &mut self,
18348        user_triggered: bool,
18349        window: &mut Window,
18350        cx: &mut Context<Self>,
18351    ) {
18352        self.start_git_blame(user_triggered, window, cx);
18353
18354        if ProjectSettings::get_global(cx)
18355            .git
18356            .inline_blame_delay()
18357            .is_some()
18358        {
18359            self.start_inline_blame_timer(window, cx);
18360        } else {
18361            self.show_git_blame_inline = true
18362        }
18363    }
18364
18365    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18366        self.blame.as_ref()
18367    }
18368
18369    pub fn show_git_blame_gutter(&self) -> bool {
18370        self.show_git_blame_gutter
18371    }
18372
18373    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18374        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18375    }
18376
18377    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18378        self.show_git_blame_inline
18379            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18380            && !self.newest_selection_head_on_empty_line(cx)
18381            && self.has_blame_entries(cx)
18382    }
18383
18384    fn has_blame_entries(&self, cx: &App) -> bool {
18385        self.blame()
18386            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18387    }
18388
18389    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18390        let cursor_anchor = self.selections.newest_anchor().head();
18391
18392        let snapshot = self.buffer.read(cx).snapshot(cx);
18393        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18394
18395        snapshot.line_len(buffer_row) == 0
18396    }
18397
18398    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18399        let buffer_and_selection = maybe!({
18400            let selection = self.selections.newest::<Point>(cx);
18401            let selection_range = selection.range();
18402
18403            let multi_buffer = self.buffer().read(cx);
18404            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18405            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18406
18407            let (buffer, range, _) = if selection.reversed {
18408                buffer_ranges.first()
18409            } else {
18410                buffer_ranges.last()
18411            }?;
18412
18413            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18414                ..text::ToPoint::to_point(&range.end, &buffer).row;
18415            Some((
18416                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18417                selection,
18418            ))
18419        });
18420
18421        let Some((buffer, selection)) = buffer_and_selection else {
18422            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18423        };
18424
18425        let Some(project) = self.project.as_ref() else {
18426            return Task::ready(Err(anyhow!("editor does not have project")));
18427        };
18428
18429        project.update(cx, |project, cx| {
18430            project.get_permalink_to_line(&buffer, selection, cx)
18431        })
18432    }
18433
18434    pub fn copy_permalink_to_line(
18435        &mut self,
18436        _: &CopyPermalinkToLine,
18437        window: &mut Window,
18438        cx: &mut Context<Self>,
18439    ) {
18440        let permalink_task = self.get_permalink_to_line(cx);
18441        let workspace = self.workspace();
18442
18443        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18444            Ok(permalink) => {
18445                cx.update(|_, cx| {
18446                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18447                })
18448                .ok();
18449            }
18450            Err(err) => {
18451                let message = format!("Failed to copy permalink: {err}");
18452
18453                anyhow::Result::<()>::Err(err).log_err();
18454
18455                if let Some(workspace) = workspace {
18456                    workspace
18457                        .update_in(cx, |workspace, _, cx| {
18458                            struct CopyPermalinkToLine;
18459
18460                            workspace.show_toast(
18461                                Toast::new(
18462                                    NotificationId::unique::<CopyPermalinkToLine>(),
18463                                    message,
18464                                ),
18465                                cx,
18466                            )
18467                        })
18468                        .ok();
18469                }
18470            }
18471        })
18472        .detach();
18473    }
18474
18475    pub fn copy_file_location(
18476        &mut self,
18477        _: &CopyFileLocation,
18478        _: &mut Window,
18479        cx: &mut Context<Self>,
18480    ) {
18481        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18482        if let Some(file) = self.target_file(cx) {
18483            if let Some(path) = file.path().to_str() {
18484                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18485            }
18486        }
18487    }
18488
18489    pub fn open_permalink_to_line(
18490        &mut self,
18491        _: &OpenPermalinkToLine,
18492        window: &mut Window,
18493        cx: &mut Context<Self>,
18494    ) {
18495        let permalink_task = self.get_permalink_to_line(cx);
18496        let workspace = self.workspace();
18497
18498        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18499            Ok(permalink) => {
18500                cx.update(|_, cx| {
18501                    cx.open_url(permalink.as_ref());
18502                })
18503                .ok();
18504            }
18505            Err(err) => {
18506                let message = format!("Failed to open permalink: {err}");
18507
18508                anyhow::Result::<()>::Err(err).log_err();
18509
18510                if let Some(workspace) = workspace {
18511                    workspace
18512                        .update(cx, |workspace, cx| {
18513                            struct OpenPermalinkToLine;
18514
18515                            workspace.show_toast(
18516                                Toast::new(
18517                                    NotificationId::unique::<OpenPermalinkToLine>(),
18518                                    message,
18519                                ),
18520                                cx,
18521                            )
18522                        })
18523                        .ok();
18524                }
18525            }
18526        })
18527        .detach();
18528    }
18529
18530    pub fn insert_uuid_v4(
18531        &mut self,
18532        _: &InsertUuidV4,
18533        window: &mut Window,
18534        cx: &mut Context<Self>,
18535    ) {
18536        self.insert_uuid(UuidVersion::V4, window, cx);
18537    }
18538
18539    pub fn insert_uuid_v7(
18540        &mut self,
18541        _: &InsertUuidV7,
18542        window: &mut Window,
18543        cx: &mut Context<Self>,
18544    ) {
18545        self.insert_uuid(UuidVersion::V7, window, cx);
18546    }
18547
18548    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18549        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18550        self.transact(window, cx, |this, window, cx| {
18551            let edits = this
18552                .selections
18553                .all::<Point>(cx)
18554                .into_iter()
18555                .map(|selection| {
18556                    let uuid = match version {
18557                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18558                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18559                    };
18560
18561                    (selection.range(), uuid.to_string())
18562                });
18563            this.edit(edits, cx);
18564            this.refresh_inline_completion(true, false, window, cx);
18565        });
18566    }
18567
18568    pub fn open_selections_in_multibuffer(
18569        &mut self,
18570        _: &OpenSelectionsInMultibuffer,
18571        window: &mut Window,
18572        cx: &mut Context<Self>,
18573    ) {
18574        let multibuffer = self.buffer.read(cx);
18575
18576        let Some(buffer) = multibuffer.as_singleton() else {
18577            return;
18578        };
18579
18580        let Some(workspace) = self.workspace() else {
18581            return;
18582        };
18583
18584        let title = multibuffer.title(cx).to_string();
18585
18586        let locations = self
18587            .selections
18588            .all_anchors(cx)
18589            .into_iter()
18590            .map(|selection| Location {
18591                buffer: buffer.clone(),
18592                range: selection.start.text_anchor..selection.end.text_anchor,
18593            })
18594            .collect::<Vec<_>>();
18595
18596        cx.spawn_in(window, async move |_, cx| {
18597            workspace.update_in(cx, |workspace, window, cx| {
18598                Self::open_locations_in_multibuffer(
18599                    workspace,
18600                    locations,
18601                    format!("Selections for '{title}'"),
18602                    false,
18603                    MultibufferSelectionMode::All,
18604                    window,
18605                    cx,
18606                );
18607            })
18608        })
18609        .detach();
18610    }
18611
18612    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18613    /// last highlight added will be used.
18614    ///
18615    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18616    pub fn highlight_rows<T: 'static>(
18617        &mut self,
18618        range: Range<Anchor>,
18619        color: Hsla,
18620        options: RowHighlightOptions,
18621        cx: &mut Context<Self>,
18622    ) {
18623        let snapshot = self.buffer().read(cx).snapshot(cx);
18624        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18625        let ix = row_highlights.binary_search_by(|highlight| {
18626            Ordering::Equal
18627                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18628                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18629        });
18630
18631        if let Err(mut ix) = ix {
18632            let index = post_inc(&mut self.highlight_order);
18633
18634            // If this range intersects with the preceding highlight, then merge it with
18635            // the preceding highlight. Otherwise insert a new highlight.
18636            let mut merged = false;
18637            if ix > 0 {
18638                let prev_highlight = &mut row_highlights[ix - 1];
18639                if prev_highlight
18640                    .range
18641                    .end
18642                    .cmp(&range.start, &snapshot)
18643                    .is_ge()
18644                {
18645                    ix -= 1;
18646                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18647                        prev_highlight.range.end = range.end;
18648                    }
18649                    merged = true;
18650                    prev_highlight.index = index;
18651                    prev_highlight.color = color;
18652                    prev_highlight.options = options;
18653                }
18654            }
18655
18656            if !merged {
18657                row_highlights.insert(
18658                    ix,
18659                    RowHighlight {
18660                        range: range.clone(),
18661                        index,
18662                        color,
18663                        options,
18664                        type_id: TypeId::of::<T>(),
18665                    },
18666                );
18667            }
18668
18669            // If any of the following highlights intersect with this one, merge them.
18670            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18671                let highlight = &row_highlights[ix];
18672                if next_highlight
18673                    .range
18674                    .start
18675                    .cmp(&highlight.range.end, &snapshot)
18676                    .is_le()
18677                {
18678                    if next_highlight
18679                        .range
18680                        .end
18681                        .cmp(&highlight.range.end, &snapshot)
18682                        .is_gt()
18683                    {
18684                        row_highlights[ix].range.end = next_highlight.range.end;
18685                    }
18686                    row_highlights.remove(ix + 1);
18687                } else {
18688                    break;
18689                }
18690            }
18691        }
18692    }
18693
18694    /// Remove any highlighted row ranges of the given type that intersect the
18695    /// given ranges.
18696    pub fn remove_highlighted_rows<T: 'static>(
18697        &mut self,
18698        ranges_to_remove: Vec<Range<Anchor>>,
18699        cx: &mut Context<Self>,
18700    ) {
18701        let snapshot = self.buffer().read(cx).snapshot(cx);
18702        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18703        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18704        row_highlights.retain(|highlight| {
18705            while let Some(range_to_remove) = ranges_to_remove.peek() {
18706                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18707                    Ordering::Less | Ordering::Equal => {
18708                        ranges_to_remove.next();
18709                    }
18710                    Ordering::Greater => {
18711                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18712                            Ordering::Less | Ordering::Equal => {
18713                                return false;
18714                            }
18715                            Ordering::Greater => break,
18716                        }
18717                    }
18718                }
18719            }
18720
18721            true
18722        })
18723    }
18724
18725    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18726    pub fn clear_row_highlights<T: 'static>(&mut self) {
18727        self.highlighted_rows.remove(&TypeId::of::<T>());
18728    }
18729
18730    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18731    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18732        self.highlighted_rows
18733            .get(&TypeId::of::<T>())
18734            .map_or(&[] as &[_], |vec| vec.as_slice())
18735            .iter()
18736            .map(|highlight| (highlight.range.clone(), highlight.color))
18737    }
18738
18739    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18740    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18741    /// Allows to ignore certain kinds of highlights.
18742    pub fn highlighted_display_rows(
18743        &self,
18744        window: &mut Window,
18745        cx: &mut App,
18746    ) -> BTreeMap<DisplayRow, LineHighlight> {
18747        let snapshot = self.snapshot(window, cx);
18748        let mut used_highlight_orders = HashMap::default();
18749        self.highlighted_rows
18750            .iter()
18751            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18752            .fold(
18753                BTreeMap::<DisplayRow, LineHighlight>::new(),
18754                |mut unique_rows, highlight| {
18755                    let start = highlight.range.start.to_display_point(&snapshot);
18756                    let end = highlight.range.end.to_display_point(&snapshot);
18757                    let start_row = start.row().0;
18758                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18759                        && end.column() == 0
18760                    {
18761                        end.row().0.saturating_sub(1)
18762                    } else {
18763                        end.row().0
18764                    };
18765                    for row in start_row..=end_row {
18766                        let used_index =
18767                            used_highlight_orders.entry(row).or_insert(highlight.index);
18768                        if highlight.index >= *used_index {
18769                            *used_index = highlight.index;
18770                            unique_rows.insert(
18771                                DisplayRow(row),
18772                                LineHighlight {
18773                                    include_gutter: highlight.options.include_gutter,
18774                                    border: None,
18775                                    background: highlight.color.into(),
18776                                    type_id: Some(highlight.type_id),
18777                                },
18778                            );
18779                        }
18780                    }
18781                    unique_rows
18782                },
18783            )
18784    }
18785
18786    pub fn highlighted_display_row_for_autoscroll(
18787        &self,
18788        snapshot: &DisplaySnapshot,
18789    ) -> Option<DisplayRow> {
18790        self.highlighted_rows
18791            .values()
18792            .flat_map(|highlighted_rows| highlighted_rows.iter())
18793            .filter_map(|highlight| {
18794                if highlight.options.autoscroll {
18795                    Some(highlight.range.start.to_display_point(snapshot).row())
18796                } else {
18797                    None
18798                }
18799            })
18800            .min()
18801    }
18802
18803    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18804        self.highlight_background::<SearchWithinRange>(
18805            ranges,
18806            |colors| colors.colors().editor_document_highlight_read_background,
18807            cx,
18808        )
18809    }
18810
18811    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18812        self.breadcrumb_header = Some(new_header);
18813    }
18814
18815    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18816        self.clear_background_highlights::<SearchWithinRange>(cx);
18817    }
18818
18819    pub fn highlight_background<T: 'static>(
18820        &mut self,
18821        ranges: &[Range<Anchor>],
18822        color_fetcher: fn(&Theme) -> Hsla,
18823        cx: &mut Context<Self>,
18824    ) {
18825        self.background_highlights.insert(
18826            HighlightKey::Type(TypeId::of::<T>()),
18827            (color_fetcher, Arc::from(ranges)),
18828        );
18829        self.scrollbar_marker_state.dirty = true;
18830        cx.notify();
18831    }
18832
18833    pub fn highlight_background_key<T: 'static>(
18834        &mut self,
18835        key: usize,
18836        ranges: &[Range<Anchor>],
18837        color_fetcher: fn(&Theme) -> Hsla,
18838        cx: &mut Context<Self>,
18839    ) {
18840        self.background_highlights.insert(
18841            HighlightKey::TypePlus(TypeId::of::<T>(), key),
18842            (color_fetcher, Arc::from(ranges)),
18843        );
18844        self.scrollbar_marker_state.dirty = true;
18845        cx.notify();
18846    }
18847
18848    pub fn clear_background_highlights<T: 'static>(
18849        &mut self,
18850        cx: &mut Context<Self>,
18851    ) -> Option<BackgroundHighlight> {
18852        let text_highlights = self
18853            .background_highlights
18854            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
18855        if !text_highlights.1.is_empty() {
18856            self.scrollbar_marker_state.dirty = true;
18857            cx.notify();
18858        }
18859        Some(text_highlights)
18860    }
18861
18862    pub fn highlight_gutter<T: 'static>(
18863        &mut self,
18864        ranges: impl Into<Vec<Range<Anchor>>>,
18865        color_fetcher: fn(&App) -> Hsla,
18866        cx: &mut Context<Self>,
18867    ) {
18868        self.gutter_highlights
18869            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18870        cx.notify();
18871    }
18872
18873    pub fn clear_gutter_highlights<T: 'static>(
18874        &mut self,
18875        cx: &mut Context<Self>,
18876    ) -> Option<GutterHighlight> {
18877        cx.notify();
18878        self.gutter_highlights.remove(&TypeId::of::<T>())
18879    }
18880
18881    pub fn insert_gutter_highlight<T: 'static>(
18882        &mut self,
18883        range: Range<Anchor>,
18884        color_fetcher: fn(&App) -> Hsla,
18885        cx: &mut Context<Self>,
18886    ) {
18887        let snapshot = self.buffer().read(cx).snapshot(cx);
18888        let mut highlights = self
18889            .gutter_highlights
18890            .remove(&TypeId::of::<T>())
18891            .map(|(_, highlights)| highlights)
18892            .unwrap_or_default();
18893        let ix = highlights.binary_search_by(|highlight| {
18894            Ordering::Equal
18895                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18896                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18897        });
18898        if let Err(ix) = ix {
18899            highlights.insert(ix, range);
18900        }
18901        self.gutter_highlights
18902            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18903    }
18904
18905    pub fn remove_gutter_highlights<T: 'static>(
18906        &mut self,
18907        ranges_to_remove: Vec<Range<Anchor>>,
18908        cx: &mut Context<Self>,
18909    ) {
18910        let snapshot = self.buffer().read(cx).snapshot(cx);
18911        let Some((color_fetcher, mut gutter_highlights)) =
18912            self.gutter_highlights.remove(&TypeId::of::<T>())
18913        else {
18914            return;
18915        };
18916        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18917        gutter_highlights.retain(|highlight| {
18918            while let Some(range_to_remove) = ranges_to_remove.peek() {
18919                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18920                    Ordering::Less | Ordering::Equal => {
18921                        ranges_to_remove.next();
18922                    }
18923                    Ordering::Greater => {
18924                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18925                            Ordering::Less | Ordering::Equal => {
18926                                return false;
18927                            }
18928                            Ordering::Greater => break,
18929                        }
18930                    }
18931                }
18932            }
18933
18934            true
18935        });
18936        self.gutter_highlights
18937            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18938    }
18939
18940    #[cfg(feature = "test-support")]
18941    pub fn all_text_highlights(
18942        &self,
18943        window: &mut Window,
18944        cx: &mut Context<Self>,
18945    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
18946        let snapshot = self.snapshot(window, cx);
18947        self.display_map.update(cx, |display_map, _| {
18948            display_map
18949                .all_text_highlights()
18950                .map(|highlight| {
18951                    let (style, ranges) = highlight.as_ref();
18952                    (
18953                        *style,
18954                        ranges
18955                            .iter()
18956                            .map(|range| range.clone().to_display_points(&snapshot))
18957                            .collect(),
18958                    )
18959                })
18960                .collect()
18961        })
18962    }
18963
18964    #[cfg(feature = "test-support")]
18965    pub fn all_text_background_highlights(
18966        &self,
18967        window: &mut Window,
18968        cx: &mut Context<Self>,
18969    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18970        let snapshot = self.snapshot(window, cx);
18971        let buffer = &snapshot.buffer_snapshot;
18972        let start = buffer.anchor_before(0);
18973        let end = buffer.anchor_after(buffer.len());
18974        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
18975    }
18976
18977    #[cfg(feature = "test-support")]
18978    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18979        let snapshot = self.buffer().read(cx).snapshot(cx);
18980
18981        let highlights = self
18982            .background_highlights
18983            .get(&HighlightKey::Type(TypeId::of::<
18984                items::BufferSearchHighlights,
18985            >()));
18986
18987        if let Some((_color, ranges)) = highlights {
18988            ranges
18989                .iter()
18990                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18991                .collect_vec()
18992        } else {
18993            vec![]
18994        }
18995    }
18996
18997    fn document_highlights_for_position<'a>(
18998        &'a self,
18999        position: Anchor,
19000        buffer: &'a MultiBufferSnapshot,
19001    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19002        let read_highlights = self
19003            .background_highlights
19004            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19005            .map(|h| &h.1);
19006        let write_highlights = self
19007            .background_highlights
19008            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19009            .map(|h| &h.1);
19010        let left_position = position.bias_left(buffer);
19011        let right_position = position.bias_right(buffer);
19012        read_highlights
19013            .into_iter()
19014            .chain(write_highlights)
19015            .flat_map(move |ranges| {
19016                let start_ix = match ranges.binary_search_by(|probe| {
19017                    let cmp = probe.end.cmp(&left_position, buffer);
19018                    if cmp.is_ge() {
19019                        Ordering::Greater
19020                    } else {
19021                        Ordering::Less
19022                    }
19023                }) {
19024                    Ok(i) | Err(i) => i,
19025                };
19026
19027                ranges[start_ix..]
19028                    .iter()
19029                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19030            })
19031    }
19032
19033    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19034        self.background_highlights
19035            .get(&HighlightKey::Type(TypeId::of::<T>()))
19036            .map_or(false, |(_, highlights)| !highlights.is_empty())
19037    }
19038
19039    pub fn background_highlights_in_range(
19040        &self,
19041        search_range: Range<Anchor>,
19042        display_snapshot: &DisplaySnapshot,
19043        theme: &Theme,
19044    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19045        let mut results = Vec::new();
19046        for (color_fetcher, ranges) in self.background_highlights.values() {
19047            let color = color_fetcher(theme);
19048            let start_ix = match ranges.binary_search_by(|probe| {
19049                let cmp = probe
19050                    .end
19051                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19052                if cmp.is_gt() {
19053                    Ordering::Greater
19054                } else {
19055                    Ordering::Less
19056                }
19057            }) {
19058                Ok(i) | Err(i) => i,
19059            };
19060            for range in &ranges[start_ix..] {
19061                if range
19062                    .start
19063                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19064                    .is_ge()
19065                {
19066                    break;
19067                }
19068
19069                let start = range.start.to_display_point(display_snapshot);
19070                let end = range.end.to_display_point(display_snapshot);
19071                results.push((start..end, color))
19072            }
19073        }
19074        results
19075    }
19076
19077    pub fn background_highlight_row_ranges<T: 'static>(
19078        &self,
19079        search_range: Range<Anchor>,
19080        display_snapshot: &DisplaySnapshot,
19081        count: usize,
19082    ) -> Vec<RangeInclusive<DisplayPoint>> {
19083        let mut results = Vec::new();
19084        let Some((_, ranges)) = self
19085            .background_highlights
19086            .get(&HighlightKey::Type(TypeId::of::<T>()))
19087        else {
19088            return vec![];
19089        };
19090
19091        let start_ix = match ranges.binary_search_by(|probe| {
19092            let cmp = probe
19093                .end
19094                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19095            if cmp.is_gt() {
19096                Ordering::Greater
19097            } else {
19098                Ordering::Less
19099            }
19100        }) {
19101            Ok(i) | Err(i) => i,
19102        };
19103        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19104            if let (Some(start_display), Some(end_display)) = (start, end) {
19105                results.push(
19106                    start_display.to_display_point(display_snapshot)
19107                        ..=end_display.to_display_point(display_snapshot),
19108                );
19109            }
19110        };
19111        let mut start_row: Option<Point> = None;
19112        let mut end_row: Option<Point> = None;
19113        if ranges.len() > count {
19114            return Vec::new();
19115        }
19116        for range in &ranges[start_ix..] {
19117            if range
19118                .start
19119                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19120                .is_ge()
19121            {
19122                break;
19123            }
19124            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19125            if let Some(current_row) = &end_row {
19126                if end.row == current_row.row {
19127                    continue;
19128                }
19129            }
19130            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19131            if start_row.is_none() {
19132                assert_eq!(end_row, None);
19133                start_row = Some(start);
19134                end_row = Some(end);
19135                continue;
19136            }
19137            if let Some(current_end) = end_row.as_mut() {
19138                if start.row > current_end.row + 1 {
19139                    push_region(start_row, end_row);
19140                    start_row = Some(start);
19141                    end_row = Some(end);
19142                } else {
19143                    // Merge two hunks.
19144                    *current_end = end;
19145                }
19146            } else {
19147                unreachable!();
19148            }
19149        }
19150        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19151        push_region(start_row, end_row);
19152        results
19153    }
19154
19155    pub fn gutter_highlights_in_range(
19156        &self,
19157        search_range: Range<Anchor>,
19158        display_snapshot: &DisplaySnapshot,
19159        cx: &App,
19160    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19161        let mut results = Vec::new();
19162        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19163            let color = color_fetcher(cx);
19164            let start_ix = match ranges.binary_search_by(|probe| {
19165                let cmp = probe
19166                    .end
19167                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19168                if cmp.is_gt() {
19169                    Ordering::Greater
19170                } else {
19171                    Ordering::Less
19172                }
19173            }) {
19174                Ok(i) | Err(i) => i,
19175            };
19176            for range in &ranges[start_ix..] {
19177                if range
19178                    .start
19179                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19180                    .is_ge()
19181                {
19182                    break;
19183                }
19184
19185                let start = range.start.to_display_point(display_snapshot);
19186                let end = range.end.to_display_point(display_snapshot);
19187                results.push((start..end, color))
19188            }
19189        }
19190        results
19191    }
19192
19193    /// Get the text ranges corresponding to the redaction query
19194    pub fn redacted_ranges(
19195        &self,
19196        search_range: Range<Anchor>,
19197        display_snapshot: &DisplaySnapshot,
19198        cx: &App,
19199    ) -> Vec<Range<DisplayPoint>> {
19200        display_snapshot
19201            .buffer_snapshot
19202            .redacted_ranges(search_range, |file| {
19203                if let Some(file) = file {
19204                    file.is_private()
19205                        && EditorSettings::get(
19206                            Some(SettingsLocation {
19207                                worktree_id: file.worktree_id(cx),
19208                                path: file.path().as_ref(),
19209                            }),
19210                            cx,
19211                        )
19212                        .redact_private_values
19213                } else {
19214                    false
19215                }
19216            })
19217            .map(|range| {
19218                range.start.to_display_point(display_snapshot)
19219                    ..range.end.to_display_point(display_snapshot)
19220            })
19221            .collect()
19222    }
19223
19224    pub fn highlight_text_key<T: 'static>(
19225        &mut self,
19226        key: usize,
19227        ranges: Vec<Range<Anchor>>,
19228        style: HighlightStyle,
19229        cx: &mut Context<Self>,
19230    ) {
19231        self.display_map.update(cx, |map, _| {
19232            map.highlight_text(
19233                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19234                ranges,
19235                style,
19236            );
19237        });
19238        cx.notify();
19239    }
19240
19241    pub fn highlight_text<T: 'static>(
19242        &mut self,
19243        ranges: Vec<Range<Anchor>>,
19244        style: HighlightStyle,
19245        cx: &mut Context<Self>,
19246    ) {
19247        self.display_map.update(cx, |map, _| {
19248            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19249        });
19250        cx.notify();
19251    }
19252
19253    pub(crate) fn highlight_inlays<T: 'static>(
19254        &mut self,
19255        highlights: Vec<InlayHighlight>,
19256        style: HighlightStyle,
19257        cx: &mut Context<Self>,
19258    ) {
19259        self.display_map.update(cx, |map, _| {
19260            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19261        });
19262        cx.notify();
19263    }
19264
19265    pub fn text_highlights<'a, T: 'static>(
19266        &'a self,
19267        cx: &'a App,
19268    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19269        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19270    }
19271
19272    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19273        let cleared = self
19274            .display_map
19275            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19276        if cleared {
19277            cx.notify();
19278        }
19279    }
19280
19281    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19282        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19283            && self.focus_handle.is_focused(window)
19284    }
19285
19286    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19287        self.show_cursor_when_unfocused = is_enabled;
19288        cx.notify();
19289    }
19290
19291    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19292        cx.notify();
19293    }
19294
19295    fn on_debug_session_event(
19296        &mut self,
19297        _session: Entity<Session>,
19298        event: &SessionEvent,
19299        cx: &mut Context<Self>,
19300    ) {
19301        match event {
19302            SessionEvent::InvalidateInlineValue => {
19303                self.refresh_inline_values(cx);
19304            }
19305            _ => {}
19306        }
19307    }
19308
19309    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19310        let Some(project) = self.project.clone() else {
19311            return;
19312        };
19313
19314        if !self.inline_value_cache.enabled {
19315            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19316            self.splice_inlays(&inlays, Vec::new(), cx);
19317            return;
19318        }
19319
19320        let current_execution_position = self
19321            .highlighted_rows
19322            .get(&TypeId::of::<ActiveDebugLine>())
19323            .and_then(|lines| lines.last().map(|line| line.range.end));
19324
19325        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19326            let inline_values = editor
19327                .update(cx, |editor, cx| {
19328                    let Some(current_execution_position) = current_execution_position else {
19329                        return Some(Task::ready(Ok(Vec::new())));
19330                    };
19331
19332                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19333                        let snapshot = buffer.snapshot(cx);
19334
19335                        let excerpt = snapshot.excerpt_containing(
19336                            current_execution_position..current_execution_position,
19337                        )?;
19338
19339                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19340                    })?;
19341
19342                    let range =
19343                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19344
19345                    project.inline_values(buffer, range, cx)
19346                })
19347                .ok()
19348                .flatten()?
19349                .await
19350                .context("refreshing debugger inlays")
19351                .log_err()?;
19352
19353            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19354
19355            for (buffer_id, inline_value) in inline_values
19356                .into_iter()
19357                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19358            {
19359                buffer_inline_values
19360                    .entry(buffer_id)
19361                    .or_default()
19362                    .push(inline_value);
19363            }
19364
19365            editor
19366                .update(cx, |editor, cx| {
19367                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19368                    let mut new_inlays = Vec::default();
19369
19370                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19371                        let buffer_id = buffer_snapshot.remote_id();
19372                        buffer_inline_values
19373                            .get(&buffer_id)
19374                            .into_iter()
19375                            .flatten()
19376                            .for_each(|hint| {
19377                                let inlay = Inlay::debugger(
19378                                    post_inc(&mut editor.next_inlay_id),
19379                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19380                                    hint.text(),
19381                                );
19382
19383                                new_inlays.push(inlay);
19384                            });
19385                    }
19386
19387                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19388                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19389
19390                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19391                })
19392                .ok()?;
19393            Some(())
19394        });
19395    }
19396
19397    fn on_buffer_event(
19398        &mut self,
19399        multibuffer: &Entity<MultiBuffer>,
19400        event: &multi_buffer::Event,
19401        window: &mut Window,
19402        cx: &mut Context<Self>,
19403    ) {
19404        match event {
19405            multi_buffer::Event::Edited {
19406                singleton_buffer_edited,
19407                edited_buffer,
19408            } => {
19409                self.scrollbar_marker_state.dirty = true;
19410                self.active_indent_guides_state.dirty = true;
19411                self.refresh_active_diagnostics(cx);
19412                self.refresh_code_actions(window, cx);
19413                self.refresh_selected_text_highlights(true, window, cx);
19414                refresh_matching_bracket_highlights(self, window, cx);
19415                if self.has_active_inline_completion() {
19416                    self.update_visible_inline_completion(window, cx);
19417                }
19418                if let Some(project) = self.project.as_ref() {
19419                    if let Some(edited_buffer) = edited_buffer {
19420                        project.update(cx, |project, cx| {
19421                            self.registered_buffers
19422                                .entry(edited_buffer.read(cx).remote_id())
19423                                .or_insert_with(|| {
19424                                    project
19425                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19426                                });
19427                        });
19428                    }
19429                }
19430                cx.emit(EditorEvent::BufferEdited);
19431                cx.emit(SearchEvent::MatchesInvalidated);
19432
19433                if let Some(buffer) = edited_buffer {
19434                    self.update_lsp_data(None, Some(buffer.read(cx).remote_id()), window, cx);
19435                }
19436
19437                if *singleton_buffer_edited {
19438                    if let Some(buffer) = edited_buffer {
19439                        if buffer.read(cx).file().is_none() {
19440                            cx.emit(EditorEvent::TitleChanged);
19441                        }
19442                    }
19443                    if let Some(project) = &self.project {
19444                        #[allow(clippy::mutable_key_type)]
19445                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19446                            multibuffer
19447                                .all_buffers()
19448                                .into_iter()
19449                                .filter_map(|buffer| {
19450                                    buffer.update(cx, |buffer, cx| {
19451                                        let language = buffer.language()?;
19452                                        let should_discard = project.update(cx, |project, cx| {
19453                                            project.is_local()
19454                                                && !project.has_language_servers_for(buffer, cx)
19455                                        });
19456                                        should_discard.not().then_some(language.clone())
19457                                    })
19458                                })
19459                                .collect::<HashSet<_>>()
19460                        });
19461                        if !languages_affected.is_empty() {
19462                            self.refresh_inlay_hints(
19463                                InlayHintRefreshReason::BufferEdited(languages_affected),
19464                                cx,
19465                            );
19466                        }
19467                    }
19468                }
19469
19470                let Some(project) = &self.project else { return };
19471                let (telemetry, is_via_ssh) = {
19472                    let project = project.read(cx);
19473                    let telemetry = project.client().telemetry().clone();
19474                    let is_via_ssh = project.is_via_ssh();
19475                    (telemetry, is_via_ssh)
19476                };
19477                refresh_linked_ranges(self, window, cx);
19478                telemetry.log_edit_event("editor", is_via_ssh);
19479            }
19480            multi_buffer::Event::ExcerptsAdded {
19481                buffer,
19482                predecessor,
19483                excerpts,
19484            } => {
19485                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19486                let buffer_id = buffer.read(cx).remote_id();
19487                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19488                    if let Some(project) = &self.project {
19489                        update_uncommitted_diff_for_buffer(
19490                            cx.entity(),
19491                            project,
19492                            [buffer.clone()],
19493                            self.buffer.clone(),
19494                            cx,
19495                        )
19496                        .detach();
19497                    }
19498                }
19499                self.update_lsp_data(None, Some(buffer_id), window, cx);
19500                cx.emit(EditorEvent::ExcerptsAdded {
19501                    buffer: buffer.clone(),
19502                    predecessor: *predecessor,
19503                    excerpts: excerpts.clone(),
19504                });
19505                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19506            }
19507            multi_buffer::Event::ExcerptsRemoved {
19508                ids,
19509                removed_buffer_ids,
19510            } => {
19511                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19512                let buffer = self.buffer.read(cx);
19513                self.registered_buffers
19514                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19515                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19516                cx.emit(EditorEvent::ExcerptsRemoved {
19517                    ids: ids.clone(),
19518                    removed_buffer_ids: removed_buffer_ids.clone(),
19519                });
19520            }
19521            multi_buffer::Event::ExcerptsEdited {
19522                excerpt_ids,
19523                buffer_ids,
19524            } => {
19525                self.display_map.update(cx, |map, cx| {
19526                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19527                });
19528                cx.emit(EditorEvent::ExcerptsEdited {
19529                    ids: excerpt_ids.clone(),
19530                });
19531            }
19532            multi_buffer::Event::ExcerptsExpanded { ids } => {
19533                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19534                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19535            }
19536            multi_buffer::Event::Reparsed(buffer_id) => {
19537                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19538                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19539
19540                cx.emit(EditorEvent::Reparsed(*buffer_id));
19541            }
19542            multi_buffer::Event::DiffHunksToggled => {
19543                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19544            }
19545            multi_buffer::Event::LanguageChanged(buffer_id) => {
19546                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19547                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19548                cx.emit(EditorEvent::Reparsed(*buffer_id));
19549                cx.notify();
19550            }
19551            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19552            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19553            multi_buffer::Event::FileHandleChanged
19554            | multi_buffer::Event::Reloaded
19555            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19556            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19557            multi_buffer::Event::DiagnosticsUpdated => {
19558                self.update_diagnostics_state(window, cx);
19559            }
19560            _ => {}
19561        };
19562    }
19563
19564    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19565        if !self.diagnostics_enabled() {
19566            return;
19567        }
19568        self.refresh_active_diagnostics(cx);
19569        self.refresh_inline_diagnostics(true, window, cx);
19570        self.scrollbar_marker_state.dirty = true;
19571        cx.notify();
19572    }
19573
19574    pub fn start_temporary_diff_override(&mut self) {
19575        self.load_diff_task.take();
19576        self.temporary_diff_override = true;
19577    }
19578
19579    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19580        self.temporary_diff_override = false;
19581        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19582        self.buffer.update(cx, |buffer, cx| {
19583            buffer.set_all_diff_hunks_collapsed(cx);
19584        });
19585
19586        if let Some(project) = self.project.clone() {
19587            self.load_diff_task = Some(
19588                update_uncommitted_diff_for_buffer(
19589                    cx.entity(),
19590                    &project,
19591                    self.buffer.read(cx).all_buffers(),
19592                    self.buffer.clone(),
19593                    cx,
19594                )
19595                .shared(),
19596            );
19597        }
19598    }
19599
19600    fn on_display_map_changed(
19601        &mut self,
19602        _: Entity<DisplayMap>,
19603        _: &mut Window,
19604        cx: &mut Context<Self>,
19605    ) {
19606        cx.notify();
19607    }
19608
19609    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19610        let new_severity = if self.diagnostics_enabled() {
19611            EditorSettings::get_global(cx)
19612                .diagnostics_max_severity
19613                .unwrap_or(DiagnosticSeverity::Hint)
19614        } else {
19615            DiagnosticSeverity::Off
19616        };
19617        self.set_max_diagnostics_severity(new_severity, cx);
19618        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19619        self.update_edit_prediction_settings(cx);
19620        self.refresh_inline_completion(true, false, window, cx);
19621        self.refresh_inlay_hints(
19622            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19623                self.selections.newest_anchor().head(),
19624                &self.buffer.read(cx).snapshot(cx),
19625                cx,
19626            )),
19627            cx,
19628        );
19629
19630        let old_cursor_shape = self.cursor_shape;
19631
19632        {
19633            let editor_settings = EditorSettings::get_global(cx);
19634            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19635            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19636            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19637            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19638            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19639        }
19640
19641        if old_cursor_shape != self.cursor_shape {
19642            cx.emit(EditorEvent::CursorShapeChanged);
19643        }
19644
19645        let project_settings = ProjectSettings::get_global(cx);
19646        self.serialize_dirty_buffers =
19647            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19648
19649        if self.mode.is_full() {
19650            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19651            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19652            if self.show_inline_diagnostics != show_inline_diagnostics {
19653                self.show_inline_diagnostics = show_inline_diagnostics;
19654                self.refresh_inline_diagnostics(false, window, cx);
19655            }
19656
19657            if self.git_blame_inline_enabled != inline_blame_enabled {
19658                self.toggle_git_blame_inline_internal(false, window, cx);
19659            }
19660
19661            let minimap_settings = EditorSettings::get_global(cx).minimap;
19662            if self.minimap_visibility != MinimapVisibility::Disabled {
19663                if self.minimap_visibility.settings_visibility()
19664                    != minimap_settings.minimap_enabled()
19665                {
19666                    self.set_minimap_visibility(
19667                        MinimapVisibility::for_mode(self.mode(), cx),
19668                        window,
19669                        cx,
19670                    );
19671                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19672                    minimap_entity.update(cx, |minimap_editor, cx| {
19673                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19674                    })
19675                }
19676            }
19677        }
19678
19679        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19680            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19681        }) {
19682            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19683                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19684            }
19685            self.refresh_colors(None, None, window, cx);
19686        }
19687
19688        cx.notify();
19689    }
19690
19691    pub fn set_searchable(&mut self, searchable: bool) {
19692        self.searchable = searchable;
19693    }
19694
19695    pub fn searchable(&self) -> bool {
19696        self.searchable
19697    }
19698
19699    fn open_proposed_changes_editor(
19700        &mut self,
19701        _: &OpenProposedChangesEditor,
19702        window: &mut Window,
19703        cx: &mut Context<Self>,
19704    ) {
19705        let Some(workspace) = self.workspace() else {
19706            cx.propagate();
19707            return;
19708        };
19709
19710        let selections = self.selections.all::<usize>(cx);
19711        let multi_buffer = self.buffer.read(cx);
19712        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19713        let mut new_selections_by_buffer = HashMap::default();
19714        for selection in selections {
19715            for (buffer, range, _) in
19716                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19717            {
19718                let mut range = range.to_point(buffer);
19719                range.start.column = 0;
19720                range.end.column = buffer.line_len(range.end.row);
19721                new_selections_by_buffer
19722                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19723                    .or_insert(Vec::new())
19724                    .push(range)
19725            }
19726        }
19727
19728        let proposed_changes_buffers = new_selections_by_buffer
19729            .into_iter()
19730            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19731            .collect::<Vec<_>>();
19732        let proposed_changes_editor = cx.new(|cx| {
19733            ProposedChangesEditor::new(
19734                "Proposed changes",
19735                proposed_changes_buffers,
19736                self.project.clone(),
19737                window,
19738                cx,
19739            )
19740        });
19741
19742        window.defer(cx, move |window, cx| {
19743            workspace.update(cx, |workspace, cx| {
19744                workspace.active_pane().update(cx, |pane, cx| {
19745                    pane.add_item(
19746                        Box::new(proposed_changes_editor),
19747                        true,
19748                        true,
19749                        None,
19750                        window,
19751                        cx,
19752                    );
19753                });
19754            });
19755        });
19756    }
19757
19758    pub fn open_excerpts_in_split(
19759        &mut self,
19760        _: &OpenExcerptsSplit,
19761        window: &mut Window,
19762        cx: &mut Context<Self>,
19763    ) {
19764        self.open_excerpts_common(None, true, window, cx)
19765    }
19766
19767    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19768        self.open_excerpts_common(None, false, window, cx)
19769    }
19770
19771    fn open_excerpts_common(
19772        &mut self,
19773        jump_data: Option<JumpData>,
19774        split: bool,
19775        window: &mut Window,
19776        cx: &mut Context<Self>,
19777    ) {
19778        let Some(workspace) = self.workspace() else {
19779            cx.propagate();
19780            return;
19781        };
19782
19783        if self.buffer.read(cx).is_singleton() {
19784            cx.propagate();
19785            return;
19786        }
19787
19788        let mut new_selections_by_buffer = HashMap::default();
19789        match &jump_data {
19790            Some(JumpData::MultiBufferPoint {
19791                excerpt_id,
19792                position,
19793                anchor,
19794                line_offset_from_top,
19795            }) => {
19796                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19797                if let Some(buffer) = multi_buffer_snapshot
19798                    .buffer_id_for_excerpt(*excerpt_id)
19799                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19800                {
19801                    let buffer_snapshot = buffer.read(cx).snapshot();
19802                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19803                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19804                    } else {
19805                        buffer_snapshot.clip_point(*position, Bias::Left)
19806                    };
19807                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19808                    new_selections_by_buffer.insert(
19809                        buffer,
19810                        (
19811                            vec![jump_to_offset..jump_to_offset],
19812                            Some(*line_offset_from_top),
19813                        ),
19814                    );
19815                }
19816            }
19817            Some(JumpData::MultiBufferRow {
19818                row,
19819                line_offset_from_top,
19820            }) => {
19821                let point = MultiBufferPoint::new(row.0, 0);
19822                if let Some((buffer, buffer_point, _)) =
19823                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19824                {
19825                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19826                    new_selections_by_buffer
19827                        .entry(buffer)
19828                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19829                        .0
19830                        .push(buffer_offset..buffer_offset)
19831                }
19832            }
19833            None => {
19834                let selections = self.selections.all::<usize>(cx);
19835                let multi_buffer = self.buffer.read(cx);
19836                for selection in selections {
19837                    for (snapshot, range, _, anchor) in multi_buffer
19838                        .snapshot(cx)
19839                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19840                    {
19841                        if let Some(anchor) = anchor {
19842                            // selection is in a deleted hunk
19843                            let Some(buffer_id) = anchor.buffer_id else {
19844                                continue;
19845                            };
19846                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19847                                continue;
19848                            };
19849                            let offset = text::ToOffset::to_offset(
19850                                &anchor.text_anchor,
19851                                &buffer_handle.read(cx).snapshot(),
19852                            );
19853                            let range = offset..offset;
19854                            new_selections_by_buffer
19855                                .entry(buffer_handle)
19856                                .or_insert((Vec::new(), None))
19857                                .0
19858                                .push(range)
19859                        } else {
19860                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19861                            else {
19862                                continue;
19863                            };
19864                            new_selections_by_buffer
19865                                .entry(buffer_handle)
19866                                .or_insert((Vec::new(), None))
19867                                .0
19868                                .push(range)
19869                        }
19870                    }
19871                }
19872            }
19873        }
19874
19875        new_selections_by_buffer
19876            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19877
19878        if new_selections_by_buffer.is_empty() {
19879            return;
19880        }
19881
19882        // We defer the pane interaction because we ourselves are a workspace item
19883        // and activating a new item causes the pane to call a method on us reentrantly,
19884        // which panics if we're on the stack.
19885        window.defer(cx, move |window, cx| {
19886            workspace.update(cx, |workspace, cx| {
19887                let pane = if split {
19888                    workspace.adjacent_pane(window, cx)
19889                } else {
19890                    workspace.active_pane().clone()
19891                };
19892
19893                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19894                    let editor = buffer
19895                        .read(cx)
19896                        .file()
19897                        .is_none()
19898                        .then(|| {
19899                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19900                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19901                            // Instead, we try to activate the existing editor in the pane first.
19902                            let (editor, pane_item_index) =
19903                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19904                                    let editor = item.downcast::<Editor>()?;
19905                                    let singleton_buffer =
19906                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19907                                    if singleton_buffer == buffer {
19908                                        Some((editor, i))
19909                                    } else {
19910                                        None
19911                                    }
19912                                })?;
19913                            pane.update(cx, |pane, cx| {
19914                                pane.activate_item(pane_item_index, true, true, window, cx)
19915                            });
19916                            Some(editor)
19917                        })
19918                        .flatten()
19919                        .unwrap_or_else(|| {
19920                            workspace.open_project_item::<Self>(
19921                                pane.clone(),
19922                                buffer,
19923                                true,
19924                                true,
19925                                window,
19926                                cx,
19927                            )
19928                        });
19929
19930                    editor.update(cx, |editor, cx| {
19931                        let autoscroll = match scroll_offset {
19932                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19933                            None => Autoscroll::newest(),
19934                        };
19935                        let nav_history = editor.nav_history.take();
19936                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19937                            s.select_ranges(ranges);
19938                        });
19939                        editor.nav_history = nav_history;
19940                    });
19941                }
19942            })
19943        });
19944    }
19945
19946    // For now, don't allow opening excerpts in buffers that aren't backed by
19947    // regular project files.
19948    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19949        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19950    }
19951
19952    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19953        let snapshot = self.buffer.read(cx).read(cx);
19954        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19955        Some(
19956            ranges
19957                .iter()
19958                .map(move |range| {
19959                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19960                })
19961                .collect(),
19962        )
19963    }
19964
19965    fn selection_replacement_ranges(
19966        &self,
19967        range: Range<OffsetUtf16>,
19968        cx: &mut App,
19969    ) -> Vec<Range<OffsetUtf16>> {
19970        let selections = self.selections.all::<OffsetUtf16>(cx);
19971        let newest_selection = selections
19972            .iter()
19973            .max_by_key(|selection| selection.id)
19974            .unwrap();
19975        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19976        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19977        let snapshot = self.buffer.read(cx).read(cx);
19978        selections
19979            .into_iter()
19980            .map(|mut selection| {
19981                selection.start.0 =
19982                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19983                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19984                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19985                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19986            })
19987            .collect()
19988    }
19989
19990    fn report_editor_event(
19991        &self,
19992        event_type: &'static str,
19993        file_extension: Option<String>,
19994        cx: &App,
19995    ) {
19996        if cfg!(any(test, feature = "test-support")) {
19997            return;
19998        }
19999
20000        let Some(project) = &self.project else { return };
20001
20002        // If None, we are in a file without an extension
20003        let file = self
20004            .buffer
20005            .read(cx)
20006            .as_singleton()
20007            .and_then(|b| b.read(cx).file());
20008        let file_extension = file_extension.or(file
20009            .as_ref()
20010            .and_then(|file| Path::new(file.file_name(cx)).extension())
20011            .and_then(|e| e.to_str())
20012            .map(|a| a.to_string()));
20013
20014        let vim_mode = vim_enabled(cx);
20015
20016        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20017        let copilot_enabled = edit_predictions_provider
20018            == language::language_settings::EditPredictionProvider::Copilot;
20019        let copilot_enabled_for_language = self
20020            .buffer
20021            .read(cx)
20022            .language_settings(cx)
20023            .show_edit_predictions;
20024
20025        let project = project.read(cx);
20026        telemetry::event!(
20027            event_type,
20028            file_extension,
20029            vim_mode,
20030            copilot_enabled,
20031            copilot_enabled_for_language,
20032            edit_predictions_provider,
20033            is_via_ssh = project.is_via_ssh(),
20034        );
20035    }
20036
20037    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20038    /// with each line being an array of {text, highlight} objects.
20039    fn copy_highlight_json(
20040        &mut self,
20041        _: &CopyHighlightJson,
20042        window: &mut Window,
20043        cx: &mut Context<Self>,
20044    ) {
20045        #[derive(Serialize)]
20046        struct Chunk<'a> {
20047            text: String,
20048            highlight: Option<&'a str>,
20049        }
20050
20051        let snapshot = self.buffer.read(cx).snapshot(cx);
20052        let range = self
20053            .selected_text_range(false, window, cx)
20054            .and_then(|selection| {
20055                if selection.range.is_empty() {
20056                    None
20057                } else {
20058                    Some(selection.range)
20059                }
20060            })
20061            .unwrap_or_else(|| 0..snapshot.len());
20062
20063        let chunks = snapshot.chunks(range, true);
20064        let mut lines = Vec::new();
20065        let mut line: VecDeque<Chunk> = VecDeque::new();
20066
20067        let Some(style) = self.style.as_ref() else {
20068            return;
20069        };
20070
20071        for chunk in chunks {
20072            let highlight = chunk
20073                .syntax_highlight_id
20074                .and_then(|id| id.name(&style.syntax));
20075            let mut chunk_lines = chunk.text.split('\n').peekable();
20076            while let Some(text) = chunk_lines.next() {
20077                let mut merged_with_last_token = false;
20078                if let Some(last_token) = line.back_mut() {
20079                    if last_token.highlight == highlight {
20080                        last_token.text.push_str(text);
20081                        merged_with_last_token = true;
20082                    }
20083                }
20084
20085                if !merged_with_last_token {
20086                    line.push_back(Chunk {
20087                        text: text.into(),
20088                        highlight,
20089                    });
20090                }
20091
20092                if chunk_lines.peek().is_some() {
20093                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20094                        line.pop_front();
20095                    }
20096                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20097                        line.pop_back();
20098                    }
20099
20100                    lines.push(mem::take(&mut line));
20101                }
20102            }
20103        }
20104
20105        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20106            return;
20107        };
20108        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20109    }
20110
20111    pub fn open_context_menu(
20112        &mut self,
20113        _: &OpenContextMenu,
20114        window: &mut Window,
20115        cx: &mut Context<Self>,
20116    ) {
20117        self.request_autoscroll(Autoscroll::newest(), cx);
20118        let position = self.selections.newest_display(cx).start;
20119        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20120    }
20121
20122    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20123        &self.inlay_hint_cache
20124    }
20125
20126    pub fn replay_insert_event(
20127        &mut self,
20128        text: &str,
20129        relative_utf16_range: Option<Range<isize>>,
20130        window: &mut Window,
20131        cx: &mut Context<Self>,
20132    ) {
20133        if !self.input_enabled {
20134            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20135            return;
20136        }
20137        if let Some(relative_utf16_range) = relative_utf16_range {
20138            let selections = self.selections.all::<OffsetUtf16>(cx);
20139            self.change_selections(None, window, cx, |s| {
20140                let new_ranges = selections.into_iter().map(|range| {
20141                    let start = OffsetUtf16(
20142                        range
20143                            .head()
20144                            .0
20145                            .saturating_add_signed(relative_utf16_range.start),
20146                    );
20147                    let end = OffsetUtf16(
20148                        range
20149                            .head()
20150                            .0
20151                            .saturating_add_signed(relative_utf16_range.end),
20152                    );
20153                    start..end
20154                });
20155                s.select_ranges(new_ranges);
20156            });
20157        }
20158
20159        self.handle_input(text, window, cx);
20160    }
20161
20162    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20163        let Some(provider) = self.semantics_provider.as_ref() else {
20164            return false;
20165        };
20166
20167        let mut supports = false;
20168        self.buffer().update(cx, |this, cx| {
20169            this.for_each_buffer(|buffer| {
20170                supports |= provider.supports_inlay_hints(buffer, cx);
20171            });
20172        });
20173
20174        supports
20175    }
20176
20177    pub fn is_focused(&self, window: &Window) -> bool {
20178        self.focus_handle.is_focused(window)
20179    }
20180
20181    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20182        cx.emit(EditorEvent::Focused);
20183
20184        if let Some(descendant) = self
20185            .last_focused_descendant
20186            .take()
20187            .and_then(|descendant| descendant.upgrade())
20188        {
20189            window.focus(&descendant);
20190        } else {
20191            if let Some(blame) = self.blame.as_ref() {
20192                blame.update(cx, GitBlame::focus)
20193            }
20194
20195            self.blink_manager.update(cx, BlinkManager::enable);
20196            self.show_cursor_names(window, cx);
20197            self.buffer.update(cx, |buffer, cx| {
20198                buffer.finalize_last_transaction(cx);
20199                if self.leader_id.is_none() {
20200                    buffer.set_active_selections(
20201                        &self.selections.disjoint_anchors(),
20202                        self.selections.line_mode,
20203                        self.cursor_shape,
20204                        cx,
20205                    );
20206                }
20207            });
20208        }
20209    }
20210
20211    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20212        cx.emit(EditorEvent::FocusedIn)
20213    }
20214
20215    fn handle_focus_out(
20216        &mut self,
20217        event: FocusOutEvent,
20218        _window: &mut Window,
20219        cx: &mut Context<Self>,
20220    ) {
20221        if event.blurred != self.focus_handle {
20222            self.last_focused_descendant = Some(event.blurred);
20223        }
20224        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20225    }
20226
20227    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20228        self.blink_manager.update(cx, BlinkManager::disable);
20229        self.buffer
20230            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20231
20232        if let Some(blame) = self.blame.as_ref() {
20233            blame.update(cx, GitBlame::blur)
20234        }
20235        if !self.hover_state.focused(window, cx) {
20236            hide_hover(self, cx);
20237        }
20238        if !self
20239            .context_menu
20240            .borrow()
20241            .as_ref()
20242            .is_some_and(|context_menu| context_menu.focused(window, cx))
20243        {
20244            self.hide_context_menu(window, cx);
20245        }
20246        self.discard_inline_completion(false, cx);
20247        cx.emit(EditorEvent::Blurred);
20248        cx.notify();
20249    }
20250
20251    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20252        let mut pending: String = window
20253            .pending_input_keystrokes()
20254            .into_iter()
20255            .flatten()
20256            .filter_map(|keystroke| {
20257                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20258                    keystroke.key_char.clone()
20259                } else {
20260                    None
20261                }
20262            })
20263            .collect();
20264
20265        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20266            pending = "".to_string();
20267        }
20268
20269        let existing_pending = self
20270            .text_highlights::<PendingInput>(cx)
20271            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20272        if existing_pending.is_none() && pending.is_empty() {
20273            return;
20274        }
20275        let transaction =
20276            self.transact(window, cx, |this, window, cx| {
20277                let selections = this.selections.all::<usize>(cx);
20278                let edits = selections
20279                    .iter()
20280                    .map(|selection| (selection.end..selection.end, pending.clone()));
20281                this.edit(edits, cx);
20282                this.change_selections(None, window, cx, |s| {
20283                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20284                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20285                    }));
20286                });
20287                if let Some(existing_ranges) = existing_pending {
20288                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20289                    this.edit(edits, cx);
20290                }
20291            });
20292
20293        let snapshot = self.snapshot(window, cx);
20294        let ranges = self
20295            .selections
20296            .all::<usize>(cx)
20297            .into_iter()
20298            .map(|selection| {
20299                snapshot.buffer_snapshot.anchor_after(selection.end)
20300                    ..snapshot
20301                        .buffer_snapshot
20302                        .anchor_before(selection.end + pending.len())
20303            })
20304            .collect();
20305
20306        if pending.is_empty() {
20307            self.clear_highlights::<PendingInput>(cx);
20308        } else {
20309            self.highlight_text::<PendingInput>(
20310                ranges,
20311                HighlightStyle {
20312                    underline: Some(UnderlineStyle {
20313                        thickness: px(1.),
20314                        color: None,
20315                        wavy: false,
20316                    }),
20317                    ..Default::default()
20318                },
20319                cx,
20320            );
20321        }
20322
20323        self.ime_transaction = self.ime_transaction.or(transaction);
20324        if let Some(transaction) = self.ime_transaction {
20325            self.buffer.update(cx, |buffer, cx| {
20326                buffer.group_until_transaction(transaction, cx);
20327            });
20328        }
20329
20330        if self.text_highlights::<PendingInput>(cx).is_none() {
20331            self.ime_transaction.take();
20332        }
20333    }
20334
20335    pub fn register_action_renderer(
20336        &mut self,
20337        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20338    ) -> Subscription {
20339        let id = self.next_editor_action_id.post_inc();
20340        self.editor_actions
20341            .borrow_mut()
20342            .insert(id, Box::new(listener));
20343
20344        let editor_actions = self.editor_actions.clone();
20345        Subscription::new(move || {
20346            editor_actions.borrow_mut().remove(&id);
20347        })
20348    }
20349
20350    pub fn register_action<A: Action>(
20351        &mut self,
20352        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20353    ) -> Subscription {
20354        let id = self.next_editor_action_id.post_inc();
20355        let listener = Arc::new(listener);
20356        self.editor_actions.borrow_mut().insert(
20357            id,
20358            Box::new(move |_, window, _| {
20359                let listener = listener.clone();
20360                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20361                    let action = action.downcast_ref().unwrap();
20362                    if phase == DispatchPhase::Bubble {
20363                        listener(action, window, cx)
20364                    }
20365                })
20366            }),
20367        );
20368
20369        let editor_actions = self.editor_actions.clone();
20370        Subscription::new(move || {
20371            editor_actions.borrow_mut().remove(&id);
20372        })
20373    }
20374
20375    pub fn file_header_size(&self) -> u32 {
20376        FILE_HEADER_HEIGHT
20377    }
20378
20379    pub fn restore(
20380        &mut self,
20381        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20382        window: &mut Window,
20383        cx: &mut Context<Self>,
20384    ) {
20385        let workspace = self.workspace();
20386        let project = self.project.as_ref();
20387        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20388            let mut tasks = Vec::new();
20389            for (buffer_id, changes) in revert_changes {
20390                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20391                    buffer.update(cx, |buffer, cx| {
20392                        buffer.edit(
20393                            changes
20394                                .into_iter()
20395                                .map(|(range, text)| (range, text.to_string())),
20396                            None,
20397                            cx,
20398                        );
20399                    });
20400
20401                    if let Some(project) =
20402                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20403                    {
20404                        project.update(cx, |project, cx| {
20405                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20406                        })
20407                    }
20408                }
20409            }
20410            tasks
20411        });
20412        cx.spawn_in(window, async move |_, cx| {
20413            for (buffer, task) in save_tasks {
20414                let result = task.await;
20415                if result.is_err() {
20416                    let Some(path) = buffer
20417                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20418                        .ok()
20419                    else {
20420                        continue;
20421                    };
20422                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20423                        let Some(task) = cx
20424                            .update_window_entity(&workspace, |workspace, window, cx| {
20425                                workspace
20426                                    .open_path_preview(path, None, false, false, false, window, cx)
20427                            })
20428                            .ok()
20429                        else {
20430                            continue;
20431                        };
20432                        task.await.log_err();
20433                    }
20434                }
20435            }
20436        })
20437        .detach();
20438        self.change_selections(None, window, cx, |selections| selections.refresh());
20439    }
20440
20441    pub fn to_pixel_point(
20442        &self,
20443        source: multi_buffer::Anchor,
20444        editor_snapshot: &EditorSnapshot,
20445        window: &mut Window,
20446    ) -> Option<gpui::Point<Pixels>> {
20447        let source_point = source.to_display_point(editor_snapshot);
20448        self.display_to_pixel_point(source_point, editor_snapshot, window)
20449    }
20450
20451    pub fn display_to_pixel_point(
20452        &self,
20453        source: DisplayPoint,
20454        editor_snapshot: &EditorSnapshot,
20455        window: &mut Window,
20456    ) -> Option<gpui::Point<Pixels>> {
20457        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20458        let text_layout_details = self.text_layout_details(window);
20459        let scroll_top = text_layout_details
20460            .scroll_anchor
20461            .scroll_position(editor_snapshot)
20462            .y;
20463
20464        if source.row().as_f32() < scroll_top.floor() {
20465            return None;
20466        }
20467        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20468        let source_y = line_height * (source.row().as_f32() - scroll_top);
20469        Some(gpui::Point::new(source_x, source_y))
20470    }
20471
20472    pub fn has_visible_completions_menu(&self) -> bool {
20473        !self.edit_prediction_preview_is_active()
20474            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20475                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20476            })
20477    }
20478
20479    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20480        if self.mode.is_minimap() {
20481            return;
20482        }
20483        self.addons
20484            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20485    }
20486
20487    pub fn unregister_addon<T: Addon>(&mut self) {
20488        self.addons.remove(&std::any::TypeId::of::<T>());
20489    }
20490
20491    pub fn addon<T: Addon>(&self) -> Option<&T> {
20492        let type_id = std::any::TypeId::of::<T>();
20493        self.addons
20494            .get(&type_id)
20495            .and_then(|item| item.to_any().downcast_ref::<T>())
20496    }
20497
20498    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20499        let type_id = std::any::TypeId::of::<T>();
20500        self.addons
20501            .get_mut(&type_id)
20502            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20503    }
20504
20505    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20506        let text_layout_details = self.text_layout_details(window);
20507        let style = &text_layout_details.editor_style;
20508        let font_id = window.text_system().resolve_font(&style.text.font());
20509        let font_size = style.text.font_size.to_pixels(window.rem_size());
20510        let line_height = style.text.line_height_in_pixels(window.rem_size());
20511        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20512
20513        gpui::Size::new(em_width, line_height)
20514    }
20515
20516    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20517        self.load_diff_task.clone()
20518    }
20519
20520    fn read_metadata_from_db(
20521        &mut self,
20522        item_id: u64,
20523        workspace_id: WorkspaceId,
20524        window: &mut Window,
20525        cx: &mut Context<Editor>,
20526    ) {
20527        if self.is_singleton(cx)
20528            && !self.mode.is_minimap()
20529            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20530        {
20531            let buffer_snapshot = OnceCell::new();
20532
20533            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20534                if !folds.is_empty() {
20535                    let snapshot =
20536                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20537                    self.fold_ranges(
20538                        folds
20539                            .into_iter()
20540                            .map(|(start, end)| {
20541                                snapshot.clip_offset(start, Bias::Left)
20542                                    ..snapshot.clip_offset(end, Bias::Right)
20543                            })
20544                            .collect(),
20545                        false,
20546                        window,
20547                        cx,
20548                    );
20549                }
20550            }
20551
20552            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20553                if !selections.is_empty() {
20554                    let snapshot =
20555                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20556                    // skip adding the initial selection to selection history
20557                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20558                    self.change_selections(None, window, cx, |s| {
20559                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20560                            snapshot.clip_offset(start, Bias::Left)
20561                                ..snapshot.clip_offset(end, Bias::Right)
20562                        }));
20563                    });
20564                    self.selection_history.mode = SelectionHistoryMode::Normal;
20565                }
20566            };
20567        }
20568
20569        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20570    }
20571
20572    fn update_lsp_data(
20573        &mut self,
20574        for_server_id: Option<LanguageServerId>,
20575        for_buffer: Option<BufferId>,
20576        window: &mut Window,
20577        cx: &mut Context<'_, Self>,
20578    ) {
20579        self.pull_diagnostics(for_buffer, window, cx);
20580        self.refresh_colors(for_server_id, for_buffer, window, cx);
20581    }
20582}
20583
20584fn vim_enabled(cx: &App) -> bool {
20585    cx.global::<SettingsStore>()
20586        .raw_user_settings()
20587        .get("vim_mode")
20588        == Some(&serde_json::Value::Bool(true))
20589}
20590
20591fn process_completion_for_edit(
20592    completion: &Completion,
20593    intent: CompletionIntent,
20594    buffer: &Entity<Buffer>,
20595    cursor_position: &text::Anchor,
20596    cx: &mut Context<Editor>,
20597) -> CompletionEdit {
20598    let buffer = buffer.read(cx);
20599    let buffer_snapshot = buffer.snapshot();
20600    let (snippet, new_text) = if completion.is_snippet() {
20601        // Workaround for typescript language server issues so that methods don't expand within
20602        // strings and functions with type expressions. The previous point is used because the query
20603        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20604        let mut snippet_source = completion.new_text.clone();
20605        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20606        previous_point.column = previous_point.column.saturating_sub(1);
20607        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20608            if scope.prefers_label_for_snippet_in_completion() {
20609                if let Some(label) = completion.label() {
20610                    if matches!(
20611                        completion.kind(),
20612                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20613                    ) {
20614                        snippet_source = label;
20615                    }
20616                }
20617            }
20618        }
20619        match Snippet::parse(&snippet_source).log_err() {
20620            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20621            None => (None, completion.new_text.clone()),
20622        }
20623    } else {
20624        (None, completion.new_text.clone())
20625    };
20626
20627    let mut range_to_replace = {
20628        let replace_range = &completion.replace_range;
20629        if let CompletionSource::Lsp {
20630            insert_range: Some(insert_range),
20631            ..
20632        } = &completion.source
20633        {
20634            debug_assert_eq!(
20635                insert_range.start, replace_range.start,
20636                "insert_range and replace_range should start at the same position"
20637            );
20638            debug_assert!(
20639                insert_range
20640                    .start
20641                    .cmp(&cursor_position, &buffer_snapshot)
20642                    .is_le(),
20643                "insert_range should start before or at cursor position"
20644            );
20645            debug_assert!(
20646                replace_range
20647                    .start
20648                    .cmp(&cursor_position, &buffer_snapshot)
20649                    .is_le(),
20650                "replace_range should start before or at cursor position"
20651            );
20652            debug_assert!(
20653                insert_range
20654                    .end
20655                    .cmp(&cursor_position, &buffer_snapshot)
20656                    .is_le(),
20657                "insert_range should end before or at cursor position"
20658            );
20659
20660            let should_replace = match intent {
20661                CompletionIntent::CompleteWithInsert => false,
20662                CompletionIntent::CompleteWithReplace => true,
20663                CompletionIntent::Complete | CompletionIntent::Compose => {
20664                    let insert_mode =
20665                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20666                            .completions
20667                            .lsp_insert_mode;
20668                    match insert_mode {
20669                        LspInsertMode::Insert => false,
20670                        LspInsertMode::Replace => true,
20671                        LspInsertMode::ReplaceSubsequence => {
20672                            let mut text_to_replace = buffer.chars_for_range(
20673                                buffer.anchor_before(replace_range.start)
20674                                    ..buffer.anchor_after(replace_range.end),
20675                            );
20676                            let mut current_needle = text_to_replace.next();
20677                            for haystack_ch in completion.label.text.chars() {
20678                                if let Some(needle_ch) = current_needle {
20679                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20680                                        current_needle = text_to_replace.next();
20681                                    }
20682                                }
20683                            }
20684                            current_needle.is_none()
20685                        }
20686                        LspInsertMode::ReplaceSuffix => {
20687                            if replace_range
20688                                .end
20689                                .cmp(&cursor_position, &buffer_snapshot)
20690                                .is_gt()
20691                            {
20692                                let range_after_cursor = *cursor_position..replace_range.end;
20693                                let text_after_cursor = buffer
20694                                    .text_for_range(
20695                                        buffer.anchor_before(range_after_cursor.start)
20696                                            ..buffer.anchor_after(range_after_cursor.end),
20697                                    )
20698                                    .collect::<String>()
20699                                    .to_ascii_lowercase();
20700                                completion
20701                                    .label
20702                                    .text
20703                                    .to_ascii_lowercase()
20704                                    .ends_with(&text_after_cursor)
20705                            } else {
20706                                true
20707                            }
20708                        }
20709                    }
20710                }
20711            };
20712
20713            if should_replace {
20714                replace_range.clone()
20715            } else {
20716                insert_range.clone()
20717            }
20718        } else {
20719            replace_range.clone()
20720        }
20721    };
20722
20723    if range_to_replace
20724        .end
20725        .cmp(&cursor_position, &buffer_snapshot)
20726        .is_lt()
20727    {
20728        range_to_replace.end = *cursor_position;
20729    }
20730
20731    CompletionEdit {
20732        new_text,
20733        replace_range: range_to_replace.to_offset(&buffer),
20734        snippet,
20735    }
20736}
20737
20738struct CompletionEdit {
20739    new_text: String,
20740    replace_range: Range<usize>,
20741    snippet: Option<Snippet>,
20742}
20743
20744fn insert_extra_newline_brackets(
20745    buffer: &MultiBufferSnapshot,
20746    range: Range<usize>,
20747    language: &language::LanguageScope,
20748) -> bool {
20749    let leading_whitespace_len = buffer
20750        .reversed_chars_at(range.start)
20751        .take_while(|c| c.is_whitespace() && *c != '\n')
20752        .map(|c| c.len_utf8())
20753        .sum::<usize>();
20754    let trailing_whitespace_len = buffer
20755        .chars_at(range.end)
20756        .take_while(|c| c.is_whitespace() && *c != '\n')
20757        .map(|c| c.len_utf8())
20758        .sum::<usize>();
20759    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20760
20761    language.brackets().any(|(pair, enabled)| {
20762        let pair_start = pair.start.trim_end();
20763        let pair_end = pair.end.trim_start();
20764
20765        enabled
20766            && pair.newline
20767            && buffer.contains_str_at(range.end, pair_end)
20768            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20769    })
20770}
20771
20772fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20773    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20774        [(buffer, range, _)] => (*buffer, range.clone()),
20775        _ => return false,
20776    };
20777    let pair = {
20778        let mut result: Option<BracketMatch> = None;
20779
20780        for pair in buffer
20781            .all_bracket_ranges(range.clone())
20782            .filter(move |pair| {
20783                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20784            })
20785        {
20786            let len = pair.close_range.end - pair.open_range.start;
20787
20788            if let Some(existing) = &result {
20789                let existing_len = existing.close_range.end - existing.open_range.start;
20790                if len > existing_len {
20791                    continue;
20792                }
20793            }
20794
20795            result = Some(pair);
20796        }
20797
20798        result
20799    };
20800    let Some(pair) = pair else {
20801        return false;
20802    };
20803    pair.newline_only
20804        && buffer
20805            .chars_for_range(pair.open_range.end..range.start)
20806            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20807            .all(|c| c.is_whitespace() && c != '\n')
20808}
20809
20810fn update_uncommitted_diff_for_buffer(
20811    editor: Entity<Editor>,
20812    project: &Entity<Project>,
20813    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20814    buffer: Entity<MultiBuffer>,
20815    cx: &mut App,
20816) -> Task<()> {
20817    let mut tasks = Vec::new();
20818    project.update(cx, |project, cx| {
20819        for buffer in buffers {
20820            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20821                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20822            }
20823        }
20824    });
20825    cx.spawn(async move |cx| {
20826        let diffs = future::join_all(tasks).await;
20827        if editor
20828            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20829            .unwrap_or(false)
20830        {
20831            return;
20832        }
20833
20834        buffer
20835            .update(cx, |buffer, cx| {
20836                for diff in diffs.into_iter().flatten() {
20837                    buffer.add_diff(diff, cx);
20838                }
20839            })
20840            .ok();
20841    })
20842}
20843
20844fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20845    let tab_size = tab_size.get() as usize;
20846    let mut width = offset;
20847
20848    for ch in text.chars() {
20849        width += if ch == '\t' {
20850            tab_size - (width % tab_size)
20851        } else {
20852            1
20853        };
20854    }
20855
20856    width - offset
20857}
20858
20859#[cfg(test)]
20860mod tests {
20861    use super::*;
20862
20863    #[test]
20864    fn test_string_size_with_expanded_tabs() {
20865        let nz = |val| NonZeroU32::new(val).unwrap();
20866        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20867        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20868        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20869        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20870        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20871        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20872        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20873        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20874    }
20875}
20876
20877/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20878struct WordBreakingTokenizer<'a> {
20879    input: &'a str,
20880}
20881
20882impl<'a> WordBreakingTokenizer<'a> {
20883    fn new(input: &'a str) -> Self {
20884        Self { input }
20885    }
20886}
20887
20888fn is_char_ideographic(ch: char) -> bool {
20889    use unicode_script::Script::*;
20890    use unicode_script::UnicodeScript;
20891    matches!(ch.script(), Han | Tangut | Yi)
20892}
20893
20894fn is_grapheme_ideographic(text: &str) -> bool {
20895    text.chars().any(is_char_ideographic)
20896}
20897
20898fn is_grapheme_whitespace(text: &str) -> bool {
20899    text.chars().any(|x| x.is_whitespace())
20900}
20901
20902fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20903    text.chars().next().map_or(false, |ch| {
20904        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20905    })
20906}
20907
20908#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20909enum WordBreakToken<'a> {
20910    Word { token: &'a str, grapheme_len: usize },
20911    InlineWhitespace { token: &'a str, grapheme_len: usize },
20912    Newline,
20913}
20914
20915impl<'a> Iterator for WordBreakingTokenizer<'a> {
20916    /// Yields a span, the count of graphemes in the token, and whether it was
20917    /// whitespace. Note that it also breaks at word boundaries.
20918    type Item = WordBreakToken<'a>;
20919
20920    fn next(&mut self) -> Option<Self::Item> {
20921        use unicode_segmentation::UnicodeSegmentation;
20922        if self.input.is_empty() {
20923            return None;
20924        }
20925
20926        let mut iter = self.input.graphemes(true).peekable();
20927        let mut offset = 0;
20928        let mut grapheme_len = 0;
20929        if let Some(first_grapheme) = iter.next() {
20930            let is_newline = first_grapheme == "\n";
20931            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20932            offset += first_grapheme.len();
20933            grapheme_len += 1;
20934            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20935                if let Some(grapheme) = iter.peek().copied() {
20936                    if should_stay_with_preceding_ideograph(grapheme) {
20937                        offset += grapheme.len();
20938                        grapheme_len += 1;
20939                    }
20940                }
20941            } else {
20942                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20943                let mut next_word_bound = words.peek().copied();
20944                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20945                    next_word_bound = words.next();
20946                }
20947                while let Some(grapheme) = iter.peek().copied() {
20948                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20949                        break;
20950                    };
20951                    if is_grapheme_whitespace(grapheme) != is_whitespace
20952                        || (grapheme == "\n") != is_newline
20953                    {
20954                        break;
20955                    };
20956                    offset += grapheme.len();
20957                    grapheme_len += 1;
20958                    iter.next();
20959                }
20960            }
20961            let token = &self.input[..offset];
20962            self.input = &self.input[offset..];
20963            if token == "\n" {
20964                Some(WordBreakToken::Newline)
20965            } else if is_whitespace {
20966                Some(WordBreakToken::InlineWhitespace {
20967                    token,
20968                    grapheme_len,
20969                })
20970            } else {
20971                Some(WordBreakToken::Word {
20972                    token,
20973                    grapheme_len,
20974                })
20975            }
20976        } else {
20977            None
20978        }
20979    }
20980}
20981
20982#[test]
20983fn test_word_breaking_tokenizer() {
20984    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20985        ("", &[]),
20986        ("  ", &[whitespace("  ", 2)]),
20987        ("Ʒ", &[word("Ʒ", 1)]),
20988        ("Ǽ", &[word("Ǽ", 1)]),
20989        ("", &[word("", 1)]),
20990        ("⋑⋑", &[word("⋑⋑", 2)]),
20991        (
20992            "原理,进而",
20993            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20994        ),
20995        (
20996            "hello world",
20997            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20998        ),
20999        (
21000            "hello, world",
21001            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21002        ),
21003        (
21004            "  hello world",
21005            &[
21006                whitespace("  ", 2),
21007                word("hello", 5),
21008                whitespace(" ", 1),
21009                word("world", 5),
21010            ],
21011        ),
21012        (
21013            "这是什么 \n 钢笔",
21014            &[
21015                word("", 1),
21016                word("", 1),
21017                word("", 1),
21018                word("", 1),
21019                whitespace(" ", 1),
21020                newline(),
21021                whitespace(" ", 1),
21022                word("", 1),
21023                word("", 1),
21024            ],
21025        ),
21026        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21027    ];
21028
21029    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21030        WordBreakToken::Word {
21031            token,
21032            grapheme_len,
21033        }
21034    }
21035
21036    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21037        WordBreakToken::InlineWhitespace {
21038            token,
21039            grapheme_len,
21040        }
21041    }
21042
21043    fn newline() -> WordBreakToken<'static> {
21044        WordBreakToken::Newline
21045    }
21046
21047    for (input, result) in tests {
21048        assert_eq!(
21049            WordBreakingTokenizer::new(input)
21050                .collect::<Vec<_>>()
21051                .as_slice(),
21052            *result,
21053        );
21054    }
21055}
21056
21057fn wrap_with_prefix(
21058    line_prefix: String,
21059    unwrapped_text: String,
21060    wrap_column: usize,
21061    tab_size: NonZeroU32,
21062    preserve_existing_whitespace: bool,
21063) -> String {
21064    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
21065    let mut wrapped_text = String::new();
21066    let mut current_line = line_prefix.clone();
21067
21068    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21069    let mut current_line_len = line_prefix_len;
21070    let mut in_whitespace = false;
21071    for token in tokenizer {
21072        let have_preceding_whitespace = in_whitespace;
21073        match token {
21074            WordBreakToken::Word {
21075                token,
21076                grapheme_len,
21077            } => {
21078                in_whitespace = false;
21079                if current_line_len + grapheme_len > wrap_column
21080                    && current_line_len != line_prefix_len
21081                {
21082                    wrapped_text.push_str(current_line.trim_end());
21083                    wrapped_text.push('\n');
21084                    current_line.truncate(line_prefix.len());
21085                    current_line_len = line_prefix_len;
21086                }
21087                current_line.push_str(token);
21088                current_line_len += grapheme_len;
21089            }
21090            WordBreakToken::InlineWhitespace {
21091                mut token,
21092                mut grapheme_len,
21093            } => {
21094                in_whitespace = true;
21095                if have_preceding_whitespace && !preserve_existing_whitespace {
21096                    continue;
21097                }
21098                if !preserve_existing_whitespace {
21099                    token = " ";
21100                    grapheme_len = 1;
21101                }
21102                if current_line_len + grapheme_len > wrap_column {
21103                    wrapped_text.push_str(current_line.trim_end());
21104                    wrapped_text.push('\n');
21105                    current_line.truncate(line_prefix.len());
21106                    current_line_len = line_prefix_len;
21107                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
21108                    current_line.push_str(token);
21109                    current_line_len += grapheme_len;
21110                }
21111            }
21112            WordBreakToken::Newline => {
21113                in_whitespace = true;
21114                if preserve_existing_whitespace {
21115                    wrapped_text.push_str(current_line.trim_end());
21116                    wrapped_text.push('\n');
21117                    current_line.truncate(line_prefix.len());
21118                    current_line_len = line_prefix_len;
21119                } else if have_preceding_whitespace {
21120                    continue;
21121                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
21122                {
21123                    wrapped_text.push_str(current_line.trim_end());
21124                    wrapped_text.push('\n');
21125                    current_line.truncate(line_prefix.len());
21126                    current_line_len = line_prefix_len;
21127                } else if current_line_len != line_prefix_len {
21128                    current_line.push(' ');
21129                    current_line_len += 1;
21130                }
21131            }
21132        }
21133    }
21134
21135    if !current_line.is_empty() {
21136        wrapped_text.push_str(&current_line);
21137    }
21138    wrapped_text
21139}
21140
21141#[test]
21142fn test_wrap_with_prefix() {
21143    assert_eq!(
21144        wrap_with_prefix(
21145            "# ".to_string(),
21146            "abcdefg".to_string(),
21147            4,
21148            NonZeroU32::new(4).unwrap(),
21149            false,
21150        ),
21151        "# abcdefg"
21152    );
21153    assert_eq!(
21154        wrap_with_prefix(
21155            "".to_string(),
21156            "\thello world".to_string(),
21157            8,
21158            NonZeroU32::new(4).unwrap(),
21159            false,
21160        ),
21161        "hello\nworld"
21162    );
21163    assert_eq!(
21164        wrap_with_prefix(
21165            "// ".to_string(),
21166            "xx \nyy zz aa bb cc".to_string(),
21167            12,
21168            NonZeroU32::new(4).unwrap(),
21169            false,
21170        ),
21171        "// xx yy zz\n// aa bb cc"
21172    );
21173    assert_eq!(
21174        wrap_with_prefix(
21175            String::new(),
21176            "这是什么 \n 钢笔".to_string(),
21177            3,
21178            NonZeroU32::new(4).unwrap(),
21179            false,
21180        ),
21181        "这是什\n么 钢\n"
21182    );
21183}
21184
21185pub trait CollaborationHub {
21186    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21187    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21188    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21189}
21190
21191impl CollaborationHub for Entity<Project> {
21192    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21193        self.read(cx).collaborators()
21194    }
21195
21196    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21197        self.read(cx).user_store().read(cx).participant_indices()
21198    }
21199
21200    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21201        let this = self.read(cx);
21202        let user_ids = this.collaborators().values().map(|c| c.user_id);
21203        this.user_store().read(cx).participant_names(user_ids, cx)
21204    }
21205}
21206
21207pub trait SemanticsProvider {
21208    fn hover(
21209        &self,
21210        buffer: &Entity<Buffer>,
21211        position: text::Anchor,
21212        cx: &mut App,
21213    ) -> Option<Task<Vec<project::Hover>>>;
21214
21215    fn inline_values(
21216        &self,
21217        buffer_handle: Entity<Buffer>,
21218        range: Range<text::Anchor>,
21219        cx: &mut App,
21220    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21221
21222    fn inlay_hints(
21223        &self,
21224        buffer_handle: Entity<Buffer>,
21225        range: Range<text::Anchor>,
21226        cx: &mut App,
21227    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21228
21229    fn resolve_inlay_hint(
21230        &self,
21231        hint: InlayHint,
21232        buffer_handle: Entity<Buffer>,
21233        server_id: LanguageServerId,
21234        cx: &mut App,
21235    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21236
21237    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21238
21239    fn document_highlights(
21240        &self,
21241        buffer: &Entity<Buffer>,
21242        position: text::Anchor,
21243        cx: &mut App,
21244    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21245
21246    fn definitions(
21247        &self,
21248        buffer: &Entity<Buffer>,
21249        position: text::Anchor,
21250        kind: GotoDefinitionKind,
21251        cx: &mut App,
21252    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21253
21254    fn range_for_rename(
21255        &self,
21256        buffer: &Entity<Buffer>,
21257        position: text::Anchor,
21258        cx: &mut App,
21259    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21260
21261    fn perform_rename(
21262        &self,
21263        buffer: &Entity<Buffer>,
21264        position: text::Anchor,
21265        new_name: String,
21266        cx: &mut App,
21267    ) -> Option<Task<Result<ProjectTransaction>>>;
21268}
21269
21270pub trait CompletionProvider {
21271    fn completions(
21272        &self,
21273        excerpt_id: ExcerptId,
21274        buffer: &Entity<Buffer>,
21275        buffer_position: text::Anchor,
21276        trigger: CompletionContext,
21277        window: &mut Window,
21278        cx: &mut Context<Editor>,
21279    ) -> Task<Result<Vec<CompletionResponse>>>;
21280
21281    fn resolve_completions(
21282        &self,
21283        _buffer: Entity<Buffer>,
21284        _completion_indices: Vec<usize>,
21285        _completions: Rc<RefCell<Box<[Completion]>>>,
21286        _cx: &mut Context<Editor>,
21287    ) -> Task<Result<bool>> {
21288        Task::ready(Ok(false))
21289    }
21290
21291    fn apply_additional_edits_for_completion(
21292        &self,
21293        _buffer: Entity<Buffer>,
21294        _completions: Rc<RefCell<Box<[Completion]>>>,
21295        _completion_index: usize,
21296        _push_to_history: bool,
21297        _cx: &mut Context<Editor>,
21298    ) -> Task<Result<Option<language::Transaction>>> {
21299        Task::ready(Ok(None))
21300    }
21301
21302    fn is_completion_trigger(
21303        &self,
21304        buffer: &Entity<Buffer>,
21305        position: language::Anchor,
21306        text: &str,
21307        trigger_in_words: bool,
21308        menu_is_open: bool,
21309        cx: &mut Context<Editor>,
21310    ) -> bool;
21311
21312    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21313
21314    fn sort_completions(&self) -> bool {
21315        true
21316    }
21317
21318    fn filter_completions(&self) -> bool {
21319        true
21320    }
21321}
21322
21323pub trait CodeActionProvider {
21324    fn id(&self) -> Arc<str>;
21325
21326    fn code_actions(
21327        &self,
21328        buffer: &Entity<Buffer>,
21329        range: Range<text::Anchor>,
21330        window: &mut Window,
21331        cx: &mut App,
21332    ) -> Task<Result<Vec<CodeAction>>>;
21333
21334    fn apply_code_action(
21335        &self,
21336        buffer_handle: Entity<Buffer>,
21337        action: CodeAction,
21338        excerpt_id: ExcerptId,
21339        push_to_history: bool,
21340        window: &mut Window,
21341        cx: &mut App,
21342    ) -> Task<Result<ProjectTransaction>>;
21343}
21344
21345impl CodeActionProvider for Entity<Project> {
21346    fn id(&self) -> Arc<str> {
21347        "project".into()
21348    }
21349
21350    fn code_actions(
21351        &self,
21352        buffer: &Entity<Buffer>,
21353        range: Range<text::Anchor>,
21354        _window: &mut Window,
21355        cx: &mut App,
21356    ) -> Task<Result<Vec<CodeAction>>> {
21357        self.update(cx, |project, cx| {
21358            let code_lens = project.code_lens(buffer, range.clone(), cx);
21359            let code_actions = project.code_actions(buffer, range, None, cx);
21360            cx.background_spawn(async move {
21361                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21362                Ok(code_lens
21363                    .context("code lens fetch")?
21364                    .into_iter()
21365                    .chain(code_actions.context("code action fetch")?)
21366                    .collect())
21367            })
21368        })
21369    }
21370
21371    fn apply_code_action(
21372        &self,
21373        buffer_handle: Entity<Buffer>,
21374        action: CodeAction,
21375        _excerpt_id: ExcerptId,
21376        push_to_history: bool,
21377        _window: &mut Window,
21378        cx: &mut App,
21379    ) -> Task<Result<ProjectTransaction>> {
21380        self.update(cx, |project, cx| {
21381            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21382        })
21383    }
21384}
21385
21386fn snippet_completions(
21387    project: &Project,
21388    buffer: &Entity<Buffer>,
21389    buffer_position: text::Anchor,
21390    cx: &mut App,
21391) -> Task<Result<CompletionResponse>> {
21392    let languages = buffer.read(cx).languages_at(buffer_position);
21393    let snippet_store = project.snippets().read(cx);
21394
21395    let scopes: Vec<_> = languages
21396        .iter()
21397        .filter_map(|language| {
21398            let language_name = language.lsp_id();
21399            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21400
21401            if snippets.is_empty() {
21402                None
21403            } else {
21404                Some((language.default_scope(), snippets))
21405            }
21406        })
21407        .collect();
21408
21409    if scopes.is_empty() {
21410        return Task::ready(Ok(CompletionResponse {
21411            completions: vec![],
21412            is_incomplete: false,
21413        }));
21414    }
21415
21416    let snapshot = buffer.read(cx).text_snapshot();
21417    let chars: String = snapshot
21418        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21419        .collect();
21420    let executor = cx.background_executor().clone();
21421
21422    cx.background_spawn(async move {
21423        let mut is_incomplete = false;
21424        let mut completions: Vec<Completion> = Vec::new();
21425        for (scope, snippets) in scopes.into_iter() {
21426            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21427            let mut last_word = chars
21428                .chars()
21429                .take_while(|c| classifier.is_word(*c))
21430                .collect::<String>();
21431            last_word = last_word.chars().rev().collect();
21432
21433            if last_word.is_empty() {
21434                return Ok(CompletionResponse {
21435                    completions: vec![],
21436                    is_incomplete: true,
21437                });
21438            }
21439
21440            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21441            let to_lsp = |point: &text::Anchor| {
21442                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21443                point_to_lsp(end)
21444            };
21445            let lsp_end = to_lsp(&buffer_position);
21446
21447            let candidates = snippets
21448                .iter()
21449                .enumerate()
21450                .flat_map(|(ix, snippet)| {
21451                    snippet
21452                        .prefix
21453                        .iter()
21454                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21455                })
21456                .collect::<Vec<StringMatchCandidate>>();
21457
21458            const MAX_RESULTS: usize = 100;
21459            let mut matches = fuzzy::match_strings(
21460                &candidates,
21461                &last_word,
21462                last_word.chars().any(|c| c.is_uppercase()),
21463                true,
21464                MAX_RESULTS,
21465                &Default::default(),
21466                executor.clone(),
21467            )
21468            .await;
21469
21470            if matches.len() >= MAX_RESULTS {
21471                is_incomplete = true;
21472            }
21473
21474            // Remove all candidates where the query's start does not match the start of any word in the candidate
21475            if let Some(query_start) = last_word.chars().next() {
21476                matches.retain(|string_match| {
21477                    split_words(&string_match.string).any(|word| {
21478                        // Check that the first codepoint of the word as lowercase matches the first
21479                        // codepoint of the query as lowercase
21480                        word.chars()
21481                            .flat_map(|codepoint| codepoint.to_lowercase())
21482                            .zip(query_start.to_lowercase())
21483                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21484                    })
21485                });
21486            }
21487
21488            let matched_strings = matches
21489                .into_iter()
21490                .map(|m| m.string)
21491                .collect::<HashSet<_>>();
21492
21493            completions.extend(snippets.iter().filter_map(|snippet| {
21494                let matching_prefix = snippet
21495                    .prefix
21496                    .iter()
21497                    .find(|prefix| matched_strings.contains(*prefix))?;
21498                let start = as_offset - last_word.len();
21499                let start = snapshot.anchor_before(start);
21500                let range = start..buffer_position;
21501                let lsp_start = to_lsp(&start);
21502                let lsp_range = lsp::Range {
21503                    start: lsp_start,
21504                    end: lsp_end,
21505                };
21506                Some(Completion {
21507                    replace_range: range,
21508                    new_text: snippet.body.clone(),
21509                    source: CompletionSource::Lsp {
21510                        insert_range: None,
21511                        server_id: LanguageServerId(usize::MAX),
21512                        resolved: true,
21513                        lsp_completion: Box::new(lsp::CompletionItem {
21514                            label: snippet.prefix.first().unwrap().clone(),
21515                            kind: Some(CompletionItemKind::SNIPPET),
21516                            label_details: snippet.description.as_ref().map(|description| {
21517                                lsp::CompletionItemLabelDetails {
21518                                    detail: Some(description.clone()),
21519                                    description: None,
21520                                }
21521                            }),
21522                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21523                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21524                                lsp::InsertReplaceEdit {
21525                                    new_text: snippet.body.clone(),
21526                                    insert: lsp_range,
21527                                    replace: lsp_range,
21528                                },
21529                            )),
21530                            filter_text: Some(snippet.body.clone()),
21531                            sort_text: Some(char::MAX.to_string()),
21532                            ..lsp::CompletionItem::default()
21533                        }),
21534                        lsp_defaults: None,
21535                    },
21536                    label: CodeLabel {
21537                        text: matching_prefix.clone(),
21538                        runs: Vec::new(),
21539                        filter_range: 0..matching_prefix.len(),
21540                    },
21541                    icon_path: None,
21542                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21543                        single_line: snippet.name.clone().into(),
21544                        plain_text: snippet
21545                            .description
21546                            .clone()
21547                            .map(|description| description.into()),
21548                    }),
21549                    insert_text_mode: None,
21550                    confirm: None,
21551                })
21552            }))
21553        }
21554
21555        Ok(CompletionResponse {
21556            completions,
21557            is_incomplete,
21558        })
21559    })
21560}
21561
21562impl CompletionProvider for Entity<Project> {
21563    fn completions(
21564        &self,
21565        _excerpt_id: ExcerptId,
21566        buffer: &Entity<Buffer>,
21567        buffer_position: text::Anchor,
21568        options: CompletionContext,
21569        _window: &mut Window,
21570        cx: &mut Context<Editor>,
21571    ) -> Task<Result<Vec<CompletionResponse>>> {
21572        self.update(cx, |project, cx| {
21573            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21574            let project_completions = project.completions(buffer, buffer_position, options, cx);
21575            cx.background_spawn(async move {
21576                let mut responses = project_completions.await?;
21577                let snippets = snippets.await?;
21578                if !snippets.completions.is_empty() {
21579                    responses.push(snippets);
21580                }
21581                Ok(responses)
21582            })
21583        })
21584    }
21585
21586    fn resolve_completions(
21587        &self,
21588        buffer: Entity<Buffer>,
21589        completion_indices: Vec<usize>,
21590        completions: Rc<RefCell<Box<[Completion]>>>,
21591        cx: &mut Context<Editor>,
21592    ) -> Task<Result<bool>> {
21593        self.update(cx, |project, cx| {
21594            project.lsp_store().update(cx, |lsp_store, cx| {
21595                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21596            })
21597        })
21598    }
21599
21600    fn apply_additional_edits_for_completion(
21601        &self,
21602        buffer: Entity<Buffer>,
21603        completions: Rc<RefCell<Box<[Completion]>>>,
21604        completion_index: usize,
21605        push_to_history: bool,
21606        cx: &mut Context<Editor>,
21607    ) -> Task<Result<Option<language::Transaction>>> {
21608        self.update(cx, |project, cx| {
21609            project.lsp_store().update(cx, |lsp_store, cx| {
21610                lsp_store.apply_additional_edits_for_completion(
21611                    buffer,
21612                    completions,
21613                    completion_index,
21614                    push_to_history,
21615                    cx,
21616                )
21617            })
21618        })
21619    }
21620
21621    fn is_completion_trigger(
21622        &self,
21623        buffer: &Entity<Buffer>,
21624        position: language::Anchor,
21625        text: &str,
21626        trigger_in_words: bool,
21627        menu_is_open: bool,
21628        cx: &mut Context<Editor>,
21629    ) -> bool {
21630        let mut chars = text.chars();
21631        let char = if let Some(char) = chars.next() {
21632            char
21633        } else {
21634            return false;
21635        };
21636        if chars.next().is_some() {
21637            return false;
21638        }
21639
21640        let buffer = buffer.read(cx);
21641        let snapshot = buffer.snapshot();
21642        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21643            return false;
21644        }
21645        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21646        if trigger_in_words && classifier.is_word(char) {
21647            return true;
21648        }
21649
21650        buffer.completion_triggers().contains(text)
21651    }
21652}
21653
21654impl SemanticsProvider for Entity<Project> {
21655    fn hover(
21656        &self,
21657        buffer: &Entity<Buffer>,
21658        position: text::Anchor,
21659        cx: &mut App,
21660    ) -> Option<Task<Vec<project::Hover>>> {
21661        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21662    }
21663
21664    fn document_highlights(
21665        &self,
21666        buffer: &Entity<Buffer>,
21667        position: text::Anchor,
21668        cx: &mut App,
21669    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21670        Some(self.update(cx, |project, cx| {
21671            project.document_highlights(buffer, position, cx)
21672        }))
21673    }
21674
21675    fn definitions(
21676        &self,
21677        buffer: &Entity<Buffer>,
21678        position: text::Anchor,
21679        kind: GotoDefinitionKind,
21680        cx: &mut App,
21681    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21682        Some(self.update(cx, |project, cx| match kind {
21683            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21684            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21685            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21686            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21687        }))
21688    }
21689
21690    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21691        // TODO: make this work for remote projects
21692        self.update(cx, |project, cx| {
21693            if project
21694                .active_debug_session(cx)
21695                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21696            {
21697                return true;
21698            }
21699
21700            buffer.update(cx, |buffer, cx| {
21701                project.any_language_server_supports_inlay_hints(buffer, cx)
21702            })
21703        })
21704    }
21705
21706    fn inline_values(
21707        &self,
21708        buffer_handle: Entity<Buffer>,
21709        range: Range<text::Anchor>,
21710        cx: &mut App,
21711    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21712        self.update(cx, |project, cx| {
21713            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21714
21715            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21716        })
21717    }
21718
21719    fn inlay_hints(
21720        &self,
21721        buffer_handle: Entity<Buffer>,
21722        range: Range<text::Anchor>,
21723        cx: &mut App,
21724    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21725        Some(self.update(cx, |project, cx| {
21726            project.inlay_hints(buffer_handle, range, cx)
21727        }))
21728    }
21729
21730    fn resolve_inlay_hint(
21731        &self,
21732        hint: InlayHint,
21733        buffer_handle: Entity<Buffer>,
21734        server_id: LanguageServerId,
21735        cx: &mut App,
21736    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21737        Some(self.update(cx, |project, cx| {
21738            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21739        }))
21740    }
21741
21742    fn range_for_rename(
21743        &self,
21744        buffer: &Entity<Buffer>,
21745        position: text::Anchor,
21746        cx: &mut App,
21747    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21748        Some(self.update(cx, |project, cx| {
21749            let buffer = buffer.clone();
21750            let task = project.prepare_rename(buffer.clone(), position, cx);
21751            cx.spawn(async move |_, cx| {
21752                Ok(match task.await? {
21753                    PrepareRenameResponse::Success(range) => Some(range),
21754                    PrepareRenameResponse::InvalidPosition => None,
21755                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21756                        // Fallback on using TreeSitter info to determine identifier range
21757                        buffer.read_with(cx, |buffer, _| {
21758                            let snapshot = buffer.snapshot();
21759                            let (range, kind) = snapshot.surrounding_word(position);
21760                            if kind != Some(CharKind::Word) {
21761                                return None;
21762                            }
21763                            Some(
21764                                snapshot.anchor_before(range.start)
21765                                    ..snapshot.anchor_after(range.end),
21766                            )
21767                        })?
21768                    }
21769                })
21770            })
21771        }))
21772    }
21773
21774    fn perform_rename(
21775        &self,
21776        buffer: &Entity<Buffer>,
21777        position: text::Anchor,
21778        new_name: String,
21779        cx: &mut App,
21780    ) -> Option<Task<Result<ProjectTransaction>>> {
21781        Some(self.update(cx, |project, cx| {
21782            project.perform_rename(buffer.clone(), position, new_name, cx)
21783        }))
21784    }
21785}
21786
21787fn inlay_hint_settings(
21788    location: Anchor,
21789    snapshot: &MultiBufferSnapshot,
21790    cx: &mut Context<Editor>,
21791) -> InlayHintSettings {
21792    let file = snapshot.file_at(location);
21793    let language = snapshot.language_at(location).map(|l| l.name());
21794    language_settings(language, file, cx).inlay_hints
21795}
21796
21797fn consume_contiguous_rows(
21798    contiguous_row_selections: &mut Vec<Selection<Point>>,
21799    selection: &Selection<Point>,
21800    display_map: &DisplaySnapshot,
21801    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21802) -> (MultiBufferRow, MultiBufferRow) {
21803    contiguous_row_selections.push(selection.clone());
21804    let start_row = MultiBufferRow(selection.start.row);
21805    let mut end_row = ending_row(selection, display_map);
21806
21807    while let Some(next_selection) = selections.peek() {
21808        if next_selection.start.row <= end_row.0 {
21809            end_row = ending_row(next_selection, display_map);
21810            contiguous_row_selections.push(selections.next().unwrap().clone());
21811        } else {
21812            break;
21813        }
21814    }
21815    (start_row, end_row)
21816}
21817
21818fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21819    if next_selection.end.column > 0 || next_selection.is_empty() {
21820        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21821    } else {
21822        MultiBufferRow(next_selection.end.row)
21823    }
21824}
21825
21826impl EditorSnapshot {
21827    pub fn remote_selections_in_range<'a>(
21828        &'a self,
21829        range: &'a Range<Anchor>,
21830        collaboration_hub: &dyn CollaborationHub,
21831        cx: &'a App,
21832    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21833        let participant_names = collaboration_hub.user_names(cx);
21834        let participant_indices = collaboration_hub.user_participant_indices(cx);
21835        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21836        let collaborators_by_replica_id = collaborators_by_peer_id
21837            .values()
21838            .map(|collaborator| (collaborator.replica_id, collaborator))
21839            .collect::<HashMap<_, _>>();
21840        self.buffer_snapshot
21841            .selections_in_range(range, false)
21842            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21843                if replica_id == AGENT_REPLICA_ID {
21844                    Some(RemoteSelection {
21845                        replica_id,
21846                        selection,
21847                        cursor_shape,
21848                        line_mode,
21849                        collaborator_id: CollaboratorId::Agent,
21850                        user_name: Some("Agent".into()),
21851                        color: cx.theme().players().agent(),
21852                    })
21853                } else {
21854                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21855                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21856                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21857                    Some(RemoteSelection {
21858                        replica_id,
21859                        selection,
21860                        cursor_shape,
21861                        line_mode,
21862                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21863                        user_name,
21864                        color: if let Some(index) = participant_index {
21865                            cx.theme().players().color_for_participant(index.0)
21866                        } else {
21867                            cx.theme().players().absent()
21868                        },
21869                    })
21870                }
21871            })
21872    }
21873
21874    pub fn hunks_for_ranges(
21875        &self,
21876        ranges: impl IntoIterator<Item = Range<Point>>,
21877    ) -> Vec<MultiBufferDiffHunk> {
21878        let mut hunks = Vec::new();
21879        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21880            HashMap::default();
21881        for query_range in ranges {
21882            let query_rows =
21883                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21884            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21885                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21886            ) {
21887                // Include deleted hunks that are adjacent to the query range, because
21888                // otherwise they would be missed.
21889                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21890                if hunk.status().is_deleted() {
21891                    intersects_range |= hunk.row_range.start == query_rows.end;
21892                    intersects_range |= hunk.row_range.end == query_rows.start;
21893                }
21894                if intersects_range {
21895                    if !processed_buffer_rows
21896                        .entry(hunk.buffer_id)
21897                        .or_default()
21898                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21899                    {
21900                        continue;
21901                    }
21902                    hunks.push(hunk);
21903                }
21904            }
21905        }
21906
21907        hunks
21908    }
21909
21910    fn display_diff_hunks_for_rows<'a>(
21911        &'a self,
21912        display_rows: Range<DisplayRow>,
21913        folded_buffers: &'a HashSet<BufferId>,
21914    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21915        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21916        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21917
21918        self.buffer_snapshot
21919            .diff_hunks_in_range(buffer_start..buffer_end)
21920            .filter_map(|hunk| {
21921                if folded_buffers.contains(&hunk.buffer_id) {
21922                    return None;
21923                }
21924
21925                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21926                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21927
21928                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21929                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21930
21931                let display_hunk = if hunk_display_start.column() != 0 {
21932                    DisplayDiffHunk::Folded {
21933                        display_row: hunk_display_start.row(),
21934                    }
21935                } else {
21936                    let mut end_row = hunk_display_end.row();
21937                    if hunk_display_end.column() > 0 {
21938                        end_row.0 += 1;
21939                    }
21940                    let is_created_file = hunk.is_created_file();
21941                    DisplayDiffHunk::Unfolded {
21942                        status: hunk.status(),
21943                        diff_base_byte_range: hunk.diff_base_byte_range,
21944                        display_row_range: hunk_display_start.row()..end_row,
21945                        multi_buffer_range: Anchor::range_in_buffer(
21946                            hunk.excerpt_id,
21947                            hunk.buffer_id,
21948                            hunk.buffer_range,
21949                        ),
21950                        is_created_file,
21951                    }
21952                };
21953
21954                Some(display_hunk)
21955            })
21956    }
21957
21958    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21959        self.display_snapshot.buffer_snapshot.language_at(position)
21960    }
21961
21962    pub fn is_focused(&self) -> bool {
21963        self.is_focused
21964    }
21965
21966    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21967        self.placeholder_text.as_ref()
21968    }
21969
21970    pub fn scroll_position(&self) -> gpui::Point<f32> {
21971        self.scroll_anchor.scroll_position(&self.display_snapshot)
21972    }
21973
21974    fn gutter_dimensions(
21975        &self,
21976        font_id: FontId,
21977        font_size: Pixels,
21978        max_line_number_width: Pixels,
21979        cx: &App,
21980    ) -> Option<GutterDimensions> {
21981        if !self.show_gutter {
21982            return None;
21983        }
21984
21985        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21986        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21987
21988        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21989            matches!(
21990                ProjectSettings::get_global(cx).git.git_gutter,
21991                Some(GitGutterSetting::TrackedFiles)
21992            )
21993        });
21994        let gutter_settings = EditorSettings::get_global(cx).gutter;
21995        let show_line_numbers = self
21996            .show_line_numbers
21997            .unwrap_or(gutter_settings.line_numbers);
21998        let line_gutter_width = if show_line_numbers {
21999            // Avoid flicker-like gutter resizes when the line number gains another digit by
22000            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22001            let min_width_for_number_on_gutter =
22002                ch_advance * gutter_settings.min_line_number_digits as f32;
22003            max_line_number_width.max(min_width_for_number_on_gutter)
22004        } else {
22005            0.0.into()
22006        };
22007
22008        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22009        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22010
22011        let git_blame_entries_width =
22012            self.git_blame_gutter_max_author_length
22013                .map(|max_author_length| {
22014                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22015                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22016
22017                    /// The number of characters to dedicate to gaps and margins.
22018                    const SPACING_WIDTH: usize = 4;
22019
22020                    let max_char_count = max_author_length.min(renderer.max_author_length())
22021                        + ::git::SHORT_SHA_LENGTH
22022                        + MAX_RELATIVE_TIMESTAMP.len()
22023                        + SPACING_WIDTH;
22024
22025                    ch_advance * max_char_count
22026                });
22027
22028        let is_singleton = self.buffer_snapshot.is_singleton();
22029
22030        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22031        left_padding += if !is_singleton {
22032            ch_width * 4.0
22033        } else if show_runnables || show_breakpoints {
22034            ch_width * 3.0
22035        } else if show_git_gutter && show_line_numbers {
22036            ch_width * 2.0
22037        } else if show_git_gutter || show_line_numbers {
22038            ch_width
22039        } else {
22040            px(0.)
22041        };
22042
22043        let shows_folds = is_singleton && gutter_settings.folds;
22044
22045        let right_padding = if shows_folds && show_line_numbers {
22046            ch_width * 4.0
22047        } else if shows_folds || (!is_singleton && show_line_numbers) {
22048            ch_width * 3.0
22049        } else if show_line_numbers {
22050            ch_width
22051        } else {
22052            px(0.)
22053        };
22054
22055        Some(GutterDimensions {
22056            left_padding,
22057            right_padding,
22058            width: line_gutter_width + left_padding + right_padding,
22059            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22060            git_blame_entries_width,
22061        })
22062    }
22063
22064    pub fn render_crease_toggle(
22065        &self,
22066        buffer_row: MultiBufferRow,
22067        row_contains_cursor: bool,
22068        editor: Entity<Editor>,
22069        window: &mut Window,
22070        cx: &mut App,
22071    ) -> Option<AnyElement> {
22072        let folded = self.is_line_folded(buffer_row);
22073        let mut is_foldable = false;
22074
22075        if let Some(crease) = self
22076            .crease_snapshot
22077            .query_row(buffer_row, &self.buffer_snapshot)
22078        {
22079            is_foldable = true;
22080            match crease {
22081                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22082                    if let Some(render_toggle) = render_toggle {
22083                        let toggle_callback =
22084                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22085                                if folded {
22086                                    editor.update(cx, |editor, cx| {
22087                                        editor.fold_at(buffer_row, window, cx)
22088                                    });
22089                                } else {
22090                                    editor.update(cx, |editor, cx| {
22091                                        editor.unfold_at(buffer_row, window, cx)
22092                                    });
22093                                }
22094                            });
22095                        return Some((render_toggle)(
22096                            buffer_row,
22097                            folded,
22098                            toggle_callback,
22099                            window,
22100                            cx,
22101                        ));
22102                    }
22103                }
22104            }
22105        }
22106
22107        is_foldable |= self.starts_indent(buffer_row);
22108
22109        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22110            Some(
22111                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22112                    .toggle_state(folded)
22113                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22114                        if folded {
22115                            this.unfold_at(buffer_row, window, cx);
22116                        } else {
22117                            this.fold_at(buffer_row, window, cx);
22118                        }
22119                    }))
22120                    .into_any_element(),
22121            )
22122        } else {
22123            None
22124        }
22125    }
22126
22127    pub fn render_crease_trailer(
22128        &self,
22129        buffer_row: MultiBufferRow,
22130        window: &mut Window,
22131        cx: &mut App,
22132    ) -> Option<AnyElement> {
22133        let folded = self.is_line_folded(buffer_row);
22134        if let Crease::Inline { render_trailer, .. } = self
22135            .crease_snapshot
22136            .query_row(buffer_row, &self.buffer_snapshot)?
22137        {
22138            let render_trailer = render_trailer.as_ref()?;
22139            Some(render_trailer(buffer_row, folded, window, cx))
22140        } else {
22141            None
22142        }
22143    }
22144}
22145
22146impl Deref for EditorSnapshot {
22147    type Target = DisplaySnapshot;
22148
22149    fn deref(&self) -> &Self::Target {
22150        &self.display_snapshot
22151    }
22152}
22153
22154#[derive(Clone, Debug, PartialEq, Eq)]
22155pub enum EditorEvent {
22156    InputIgnored {
22157        text: Arc<str>,
22158    },
22159    InputHandled {
22160        utf16_range_to_replace: Option<Range<isize>>,
22161        text: Arc<str>,
22162    },
22163    ExcerptsAdded {
22164        buffer: Entity<Buffer>,
22165        predecessor: ExcerptId,
22166        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22167    },
22168    ExcerptsRemoved {
22169        ids: Vec<ExcerptId>,
22170        removed_buffer_ids: Vec<BufferId>,
22171    },
22172    BufferFoldToggled {
22173        ids: Vec<ExcerptId>,
22174        folded: bool,
22175    },
22176    ExcerptsEdited {
22177        ids: Vec<ExcerptId>,
22178    },
22179    ExcerptsExpanded {
22180        ids: Vec<ExcerptId>,
22181    },
22182    BufferEdited,
22183    Edited {
22184        transaction_id: clock::Lamport,
22185    },
22186    Reparsed(BufferId),
22187    Focused,
22188    FocusedIn,
22189    Blurred,
22190    DirtyChanged,
22191    Saved,
22192    TitleChanged,
22193    DiffBaseChanged,
22194    SelectionsChanged {
22195        local: bool,
22196    },
22197    ScrollPositionChanged {
22198        local: bool,
22199        autoscroll: bool,
22200    },
22201    Closed,
22202    TransactionUndone {
22203        transaction_id: clock::Lamport,
22204    },
22205    TransactionBegun {
22206        transaction_id: clock::Lamport,
22207    },
22208    Reloaded,
22209    CursorShapeChanged,
22210    PushedToNavHistory {
22211        anchor: Anchor,
22212        is_deactivate: bool,
22213    },
22214}
22215
22216impl EventEmitter<EditorEvent> for Editor {}
22217
22218impl Focusable for Editor {
22219    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22220        self.focus_handle.clone()
22221    }
22222}
22223
22224impl Render for Editor {
22225    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22226        let settings = ThemeSettings::get_global(cx);
22227
22228        let mut text_style = match self.mode {
22229            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22230                color: cx.theme().colors().editor_foreground,
22231                font_family: settings.ui_font.family.clone(),
22232                font_features: settings.ui_font.features.clone(),
22233                font_fallbacks: settings.ui_font.fallbacks.clone(),
22234                font_size: rems(0.875).into(),
22235                font_weight: settings.ui_font.weight,
22236                line_height: relative(settings.buffer_line_height.value()),
22237                ..Default::default()
22238            },
22239            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22240                color: cx.theme().colors().editor_foreground,
22241                font_family: settings.buffer_font.family.clone(),
22242                font_features: settings.buffer_font.features.clone(),
22243                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22244                font_size: settings.buffer_font_size(cx).into(),
22245                font_weight: settings.buffer_font.weight,
22246                line_height: relative(settings.buffer_line_height.value()),
22247                ..Default::default()
22248            },
22249        };
22250        if let Some(text_style_refinement) = &self.text_style_refinement {
22251            text_style.refine(text_style_refinement)
22252        }
22253
22254        let background = match self.mode {
22255            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22256            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22257            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22258            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22259        };
22260
22261        EditorElement::new(
22262            &cx.entity(),
22263            EditorStyle {
22264                background,
22265                local_player: cx.theme().players().local(),
22266                text: text_style,
22267                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22268                syntax: cx.theme().syntax().clone(),
22269                status: cx.theme().status().clone(),
22270                inlay_hints_style: make_inlay_hints_style(cx),
22271                inline_completion_styles: make_suggestion_styles(cx),
22272                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22273                show_underlines: self.diagnostics_enabled(),
22274            },
22275        )
22276    }
22277}
22278
22279impl EntityInputHandler for Editor {
22280    fn text_for_range(
22281        &mut self,
22282        range_utf16: Range<usize>,
22283        adjusted_range: &mut Option<Range<usize>>,
22284        _: &mut Window,
22285        cx: &mut Context<Self>,
22286    ) -> Option<String> {
22287        let snapshot = self.buffer.read(cx).read(cx);
22288        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22289        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22290        if (start.0..end.0) != range_utf16 {
22291            adjusted_range.replace(start.0..end.0);
22292        }
22293        Some(snapshot.text_for_range(start..end).collect())
22294    }
22295
22296    fn selected_text_range(
22297        &mut self,
22298        ignore_disabled_input: bool,
22299        _: &mut Window,
22300        cx: &mut Context<Self>,
22301    ) -> Option<UTF16Selection> {
22302        // Prevent the IME menu from appearing when holding down an alphabetic key
22303        // while input is disabled.
22304        if !ignore_disabled_input && !self.input_enabled {
22305            return None;
22306        }
22307
22308        let selection = self.selections.newest::<OffsetUtf16>(cx);
22309        let range = selection.range();
22310
22311        Some(UTF16Selection {
22312            range: range.start.0..range.end.0,
22313            reversed: selection.reversed,
22314        })
22315    }
22316
22317    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22318        let snapshot = self.buffer.read(cx).read(cx);
22319        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22320        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22321    }
22322
22323    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22324        self.clear_highlights::<InputComposition>(cx);
22325        self.ime_transaction.take();
22326    }
22327
22328    fn replace_text_in_range(
22329        &mut self,
22330        range_utf16: Option<Range<usize>>,
22331        text: &str,
22332        window: &mut Window,
22333        cx: &mut Context<Self>,
22334    ) {
22335        if !self.input_enabled {
22336            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22337            return;
22338        }
22339
22340        self.transact(window, cx, |this, window, cx| {
22341            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22342                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22343                Some(this.selection_replacement_ranges(range_utf16, cx))
22344            } else {
22345                this.marked_text_ranges(cx)
22346            };
22347
22348            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22349                let newest_selection_id = this.selections.newest_anchor().id;
22350                this.selections
22351                    .all::<OffsetUtf16>(cx)
22352                    .iter()
22353                    .zip(ranges_to_replace.iter())
22354                    .find_map(|(selection, range)| {
22355                        if selection.id == newest_selection_id {
22356                            Some(
22357                                (range.start.0 as isize - selection.head().0 as isize)
22358                                    ..(range.end.0 as isize - selection.head().0 as isize),
22359                            )
22360                        } else {
22361                            None
22362                        }
22363                    })
22364            });
22365
22366            cx.emit(EditorEvent::InputHandled {
22367                utf16_range_to_replace: range_to_replace,
22368                text: text.into(),
22369            });
22370
22371            if let Some(new_selected_ranges) = new_selected_ranges {
22372                this.change_selections(None, window, cx, |selections| {
22373                    selections.select_ranges(new_selected_ranges)
22374                });
22375                this.backspace(&Default::default(), window, cx);
22376            }
22377
22378            this.handle_input(text, window, cx);
22379        });
22380
22381        if let Some(transaction) = self.ime_transaction {
22382            self.buffer.update(cx, |buffer, cx| {
22383                buffer.group_until_transaction(transaction, cx);
22384            });
22385        }
22386
22387        self.unmark_text(window, cx);
22388    }
22389
22390    fn replace_and_mark_text_in_range(
22391        &mut self,
22392        range_utf16: Option<Range<usize>>,
22393        text: &str,
22394        new_selected_range_utf16: Option<Range<usize>>,
22395        window: &mut Window,
22396        cx: &mut Context<Self>,
22397    ) {
22398        if !self.input_enabled {
22399            return;
22400        }
22401
22402        let transaction = self.transact(window, cx, |this, window, cx| {
22403            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22404                let snapshot = this.buffer.read(cx).read(cx);
22405                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22406                    for marked_range in &mut marked_ranges {
22407                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22408                        marked_range.start.0 += relative_range_utf16.start;
22409                        marked_range.start =
22410                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22411                        marked_range.end =
22412                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22413                    }
22414                }
22415                Some(marked_ranges)
22416            } else if let Some(range_utf16) = range_utf16 {
22417                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22418                Some(this.selection_replacement_ranges(range_utf16, cx))
22419            } else {
22420                None
22421            };
22422
22423            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22424                let newest_selection_id = this.selections.newest_anchor().id;
22425                this.selections
22426                    .all::<OffsetUtf16>(cx)
22427                    .iter()
22428                    .zip(ranges_to_replace.iter())
22429                    .find_map(|(selection, range)| {
22430                        if selection.id == newest_selection_id {
22431                            Some(
22432                                (range.start.0 as isize - selection.head().0 as isize)
22433                                    ..(range.end.0 as isize - selection.head().0 as isize),
22434                            )
22435                        } else {
22436                            None
22437                        }
22438                    })
22439            });
22440
22441            cx.emit(EditorEvent::InputHandled {
22442                utf16_range_to_replace: range_to_replace,
22443                text: text.into(),
22444            });
22445
22446            if let Some(ranges) = ranges_to_replace {
22447                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22448            }
22449
22450            let marked_ranges = {
22451                let snapshot = this.buffer.read(cx).read(cx);
22452                this.selections
22453                    .disjoint_anchors()
22454                    .iter()
22455                    .map(|selection| {
22456                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22457                    })
22458                    .collect::<Vec<_>>()
22459            };
22460
22461            if text.is_empty() {
22462                this.unmark_text(window, cx);
22463            } else {
22464                this.highlight_text::<InputComposition>(
22465                    marked_ranges.clone(),
22466                    HighlightStyle {
22467                        underline: Some(UnderlineStyle {
22468                            thickness: px(1.),
22469                            color: None,
22470                            wavy: false,
22471                        }),
22472                        ..Default::default()
22473                    },
22474                    cx,
22475                );
22476            }
22477
22478            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22479            let use_autoclose = this.use_autoclose;
22480            let use_auto_surround = this.use_auto_surround;
22481            this.set_use_autoclose(false);
22482            this.set_use_auto_surround(false);
22483            this.handle_input(text, window, cx);
22484            this.set_use_autoclose(use_autoclose);
22485            this.set_use_auto_surround(use_auto_surround);
22486
22487            if let Some(new_selected_range) = new_selected_range_utf16 {
22488                let snapshot = this.buffer.read(cx).read(cx);
22489                let new_selected_ranges = marked_ranges
22490                    .into_iter()
22491                    .map(|marked_range| {
22492                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22493                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22494                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22495                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22496                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22497                    })
22498                    .collect::<Vec<_>>();
22499
22500                drop(snapshot);
22501                this.change_selections(None, window, cx, |selections| {
22502                    selections.select_ranges(new_selected_ranges)
22503                });
22504            }
22505        });
22506
22507        self.ime_transaction = self.ime_transaction.or(transaction);
22508        if let Some(transaction) = self.ime_transaction {
22509            self.buffer.update(cx, |buffer, cx| {
22510                buffer.group_until_transaction(transaction, cx);
22511            });
22512        }
22513
22514        if self.text_highlights::<InputComposition>(cx).is_none() {
22515            self.ime_transaction.take();
22516        }
22517    }
22518
22519    fn bounds_for_range(
22520        &mut self,
22521        range_utf16: Range<usize>,
22522        element_bounds: gpui::Bounds<Pixels>,
22523        window: &mut Window,
22524        cx: &mut Context<Self>,
22525    ) -> Option<gpui::Bounds<Pixels>> {
22526        let text_layout_details = self.text_layout_details(window);
22527        let gpui::Size {
22528            width: em_width,
22529            height: line_height,
22530        } = self.character_size(window);
22531
22532        let snapshot = self.snapshot(window, cx);
22533        let scroll_position = snapshot.scroll_position();
22534        let scroll_left = scroll_position.x * em_width;
22535
22536        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22537        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22538            + self.gutter_dimensions.width
22539            + self.gutter_dimensions.margin;
22540        let y = line_height * (start.row().as_f32() - scroll_position.y);
22541
22542        Some(Bounds {
22543            origin: element_bounds.origin + point(x, y),
22544            size: size(em_width, line_height),
22545        })
22546    }
22547
22548    fn character_index_for_point(
22549        &mut self,
22550        point: gpui::Point<Pixels>,
22551        _window: &mut Window,
22552        _cx: &mut Context<Self>,
22553    ) -> Option<usize> {
22554        let position_map = self.last_position_map.as_ref()?;
22555        if !position_map.text_hitbox.contains(&point) {
22556            return None;
22557        }
22558        let display_point = position_map.point_for_position(point).previous_valid;
22559        let anchor = position_map
22560            .snapshot
22561            .display_point_to_anchor(display_point, Bias::Left);
22562        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22563        Some(utf16_offset.0)
22564    }
22565}
22566
22567trait SelectionExt {
22568    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22569    fn spanned_rows(
22570        &self,
22571        include_end_if_at_line_start: bool,
22572        map: &DisplaySnapshot,
22573    ) -> Range<MultiBufferRow>;
22574}
22575
22576impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22577    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22578        let start = self
22579            .start
22580            .to_point(&map.buffer_snapshot)
22581            .to_display_point(map);
22582        let end = self
22583            .end
22584            .to_point(&map.buffer_snapshot)
22585            .to_display_point(map);
22586        if self.reversed {
22587            end..start
22588        } else {
22589            start..end
22590        }
22591    }
22592
22593    fn spanned_rows(
22594        &self,
22595        include_end_if_at_line_start: bool,
22596        map: &DisplaySnapshot,
22597    ) -> Range<MultiBufferRow> {
22598        let start = self.start.to_point(&map.buffer_snapshot);
22599        let mut end = self.end.to_point(&map.buffer_snapshot);
22600        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22601            end.row -= 1;
22602        }
22603
22604        let buffer_start = map.prev_line_boundary(start).0;
22605        let buffer_end = map.next_line_boundary(end).0;
22606        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22607    }
22608}
22609
22610impl<T: InvalidationRegion> InvalidationStack<T> {
22611    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22612    where
22613        S: Clone + ToOffset,
22614    {
22615        while let Some(region) = self.last() {
22616            let all_selections_inside_invalidation_ranges =
22617                if selections.len() == region.ranges().len() {
22618                    selections
22619                        .iter()
22620                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22621                        .all(|(selection, invalidation_range)| {
22622                            let head = selection.head().to_offset(buffer);
22623                            invalidation_range.start <= head && invalidation_range.end >= head
22624                        })
22625                } else {
22626                    false
22627                };
22628
22629            if all_selections_inside_invalidation_ranges {
22630                break;
22631            } else {
22632                self.pop();
22633            }
22634        }
22635    }
22636}
22637
22638impl<T> Default for InvalidationStack<T> {
22639    fn default() -> Self {
22640        Self(Default::default())
22641    }
22642}
22643
22644impl<T> Deref for InvalidationStack<T> {
22645    type Target = Vec<T>;
22646
22647    fn deref(&self) -> &Self::Target {
22648        &self.0
22649    }
22650}
22651
22652impl<T> DerefMut for InvalidationStack<T> {
22653    fn deref_mut(&mut self) -> &mut Self::Target {
22654        &mut self.0
22655    }
22656}
22657
22658impl InvalidationRegion for SnippetState {
22659    fn ranges(&self) -> &[Range<Anchor>] {
22660        &self.ranges[self.active_index]
22661    }
22662}
22663
22664fn inline_completion_edit_text(
22665    current_snapshot: &BufferSnapshot,
22666    edits: &[(Range<Anchor>, String)],
22667    edit_preview: &EditPreview,
22668    include_deletions: bool,
22669    cx: &App,
22670) -> HighlightedText {
22671    let edits = edits
22672        .iter()
22673        .map(|(anchor, text)| {
22674            (
22675                anchor.start.text_anchor..anchor.end.text_anchor,
22676                text.clone(),
22677            )
22678        })
22679        .collect::<Vec<_>>();
22680
22681    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22682}
22683
22684pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22685    match severity {
22686        lsp::DiagnosticSeverity::ERROR => colors.error,
22687        lsp::DiagnosticSeverity::WARNING => colors.warning,
22688        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22689        lsp::DiagnosticSeverity::HINT => colors.info,
22690        _ => colors.ignored,
22691    }
22692}
22693
22694pub fn styled_runs_for_code_label<'a>(
22695    label: &'a CodeLabel,
22696    syntax_theme: &'a theme::SyntaxTheme,
22697) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22698    let fade_out = HighlightStyle {
22699        fade_out: Some(0.35),
22700        ..Default::default()
22701    };
22702
22703    let mut prev_end = label.filter_range.end;
22704    label
22705        .runs
22706        .iter()
22707        .enumerate()
22708        .flat_map(move |(ix, (range, highlight_id))| {
22709            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22710                style
22711            } else {
22712                return Default::default();
22713            };
22714            let mut muted_style = style;
22715            muted_style.highlight(fade_out);
22716
22717            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22718            if range.start >= label.filter_range.end {
22719                if range.start > prev_end {
22720                    runs.push((prev_end..range.start, fade_out));
22721                }
22722                runs.push((range.clone(), muted_style));
22723            } else if range.end <= label.filter_range.end {
22724                runs.push((range.clone(), style));
22725            } else {
22726                runs.push((range.start..label.filter_range.end, style));
22727                runs.push((label.filter_range.end..range.end, muted_style));
22728            }
22729            prev_end = cmp::max(prev_end, range.end);
22730
22731            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22732                runs.push((prev_end..label.text.len(), fade_out));
22733            }
22734
22735            runs
22736        })
22737}
22738
22739pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22740    let mut prev_index = 0;
22741    let mut prev_codepoint: Option<char> = None;
22742    text.char_indices()
22743        .chain([(text.len(), '\0')])
22744        .filter_map(move |(index, codepoint)| {
22745            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22746            let is_boundary = index == text.len()
22747                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22748                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22749            if is_boundary {
22750                let chunk = &text[prev_index..index];
22751                prev_index = index;
22752                Some(chunk)
22753            } else {
22754                None
22755            }
22756        })
22757}
22758
22759pub trait RangeToAnchorExt: Sized {
22760    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22761
22762    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22763        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22764        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22765    }
22766}
22767
22768impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22769    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22770        let start_offset = self.start.to_offset(snapshot);
22771        let end_offset = self.end.to_offset(snapshot);
22772        if start_offset == end_offset {
22773            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22774        } else {
22775            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22776        }
22777    }
22778}
22779
22780pub trait RowExt {
22781    fn as_f32(&self) -> f32;
22782
22783    fn next_row(&self) -> Self;
22784
22785    fn previous_row(&self) -> Self;
22786
22787    fn minus(&self, other: Self) -> u32;
22788}
22789
22790impl RowExt for DisplayRow {
22791    fn as_f32(&self) -> f32 {
22792        self.0 as f32
22793    }
22794
22795    fn next_row(&self) -> Self {
22796        Self(self.0 + 1)
22797    }
22798
22799    fn previous_row(&self) -> Self {
22800        Self(self.0.saturating_sub(1))
22801    }
22802
22803    fn minus(&self, other: Self) -> u32 {
22804        self.0 - other.0
22805    }
22806}
22807
22808impl RowExt for MultiBufferRow {
22809    fn as_f32(&self) -> f32 {
22810        self.0 as f32
22811    }
22812
22813    fn next_row(&self) -> Self {
22814        Self(self.0 + 1)
22815    }
22816
22817    fn previous_row(&self) -> Self {
22818        Self(self.0.saturating_sub(1))
22819    }
22820
22821    fn minus(&self, other: Self) -> u32 {
22822        self.0 - other.0
22823    }
22824}
22825
22826trait RowRangeExt {
22827    type Row;
22828
22829    fn len(&self) -> usize;
22830
22831    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22832}
22833
22834impl RowRangeExt for Range<MultiBufferRow> {
22835    type Row = MultiBufferRow;
22836
22837    fn len(&self) -> usize {
22838        (self.end.0 - self.start.0) as usize
22839    }
22840
22841    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22842        (self.start.0..self.end.0).map(MultiBufferRow)
22843    }
22844}
22845
22846impl RowRangeExt for Range<DisplayRow> {
22847    type Row = DisplayRow;
22848
22849    fn len(&self) -> usize {
22850        (self.end.0 - self.start.0) as usize
22851    }
22852
22853    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22854        (self.start.0..self.end.0).map(DisplayRow)
22855    }
22856}
22857
22858/// If select range has more than one line, we
22859/// just point the cursor to range.start.
22860fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22861    if range.start.row == range.end.row {
22862        range
22863    } else {
22864        range.start..range.start
22865    }
22866}
22867pub struct KillRing(ClipboardItem);
22868impl Global for KillRing {}
22869
22870const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22871
22872enum BreakpointPromptEditAction {
22873    Log,
22874    Condition,
22875    HitCondition,
22876}
22877
22878struct BreakpointPromptEditor {
22879    pub(crate) prompt: Entity<Editor>,
22880    editor: WeakEntity<Editor>,
22881    breakpoint_anchor: Anchor,
22882    breakpoint: Breakpoint,
22883    edit_action: BreakpointPromptEditAction,
22884    block_ids: HashSet<CustomBlockId>,
22885    editor_margins: Arc<Mutex<EditorMargins>>,
22886    _subscriptions: Vec<Subscription>,
22887}
22888
22889impl BreakpointPromptEditor {
22890    const MAX_LINES: u8 = 4;
22891
22892    fn new(
22893        editor: WeakEntity<Editor>,
22894        breakpoint_anchor: Anchor,
22895        breakpoint: Breakpoint,
22896        edit_action: BreakpointPromptEditAction,
22897        window: &mut Window,
22898        cx: &mut Context<Self>,
22899    ) -> Self {
22900        let base_text = match edit_action {
22901            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22902            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22903            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22904        }
22905        .map(|msg| msg.to_string())
22906        .unwrap_or_default();
22907
22908        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22909        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22910
22911        let prompt = cx.new(|cx| {
22912            let mut prompt = Editor::new(
22913                EditorMode::AutoHeight {
22914                    min_lines: 1,
22915                    max_lines: Some(Self::MAX_LINES as usize),
22916                },
22917                buffer,
22918                None,
22919                window,
22920                cx,
22921            );
22922            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22923            prompt.set_show_cursor_when_unfocused(false, cx);
22924            prompt.set_placeholder_text(
22925                match edit_action {
22926                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22927                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22928                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22929                },
22930                cx,
22931            );
22932
22933            prompt
22934        });
22935
22936        Self {
22937            prompt,
22938            editor,
22939            breakpoint_anchor,
22940            breakpoint,
22941            edit_action,
22942            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22943            block_ids: Default::default(),
22944            _subscriptions: vec![],
22945        }
22946    }
22947
22948    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22949        self.block_ids.extend(block_ids)
22950    }
22951
22952    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22953        if let Some(editor) = self.editor.upgrade() {
22954            let message = self
22955                .prompt
22956                .read(cx)
22957                .buffer
22958                .read(cx)
22959                .as_singleton()
22960                .expect("A multi buffer in breakpoint prompt isn't possible")
22961                .read(cx)
22962                .as_rope()
22963                .to_string();
22964
22965            editor.update(cx, |editor, cx| {
22966                editor.edit_breakpoint_at_anchor(
22967                    self.breakpoint_anchor,
22968                    self.breakpoint.clone(),
22969                    match self.edit_action {
22970                        BreakpointPromptEditAction::Log => {
22971                            BreakpointEditAction::EditLogMessage(message.into())
22972                        }
22973                        BreakpointPromptEditAction::Condition => {
22974                            BreakpointEditAction::EditCondition(message.into())
22975                        }
22976                        BreakpointPromptEditAction::HitCondition => {
22977                            BreakpointEditAction::EditHitCondition(message.into())
22978                        }
22979                    },
22980                    cx,
22981                );
22982
22983                editor.remove_blocks(self.block_ids.clone(), None, cx);
22984                cx.focus_self(window);
22985            });
22986        }
22987    }
22988
22989    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22990        self.editor
22991            .update(cx, |editor, cx| {
22992                editor.remove_blocks(self.block_ids.clone(), None, cx);
22993                window.focus(&editor.focus_handle);
22994            })
22995            .log_err();
22996    }
22997
22998    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22999        let settings = ThemeSettings::get_global(cx);
23000        let text_style = TextStyle {
23001            color: if self.prompt.read(cx).read_only(cx) {
23002                cx.theme().colors().text_disabled
23003            } else {
23004                cx.theme().colors().text
23005            },
23006            font_family: settings.buffer_font.family.clone(),
23007            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23008            font_size: settings.buffer_font_size(cx).into(),
23009            font_weight: settings.buffer_font.weight,
23010            line_height: relative(settings.buffer_line_height.value()),
23011            ..Default::default()
23012        };
23013        EditorElement::new(
23014            &self.prompt,
23015            EditorStyle {
23016                background: cx.theme().colors().editor_background,
23017                local_player: cx.theme().players().local(),
23018                text: text_style,
23019                ..Default::default()
23020            },
23021        )
23022    }
23023}
23024
23025impl Render for BreakpointPromptEditor {
23026    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23027        let editor_margins = *self.editor_margins.lock();
23028        let gutter_dimensions = editor_margins.gutter;
23029        h_flex()
23030            .key_context("Editor")
23031            .bg(cx.theme().colors().editor_background)
23032            .border_y_1()
23033            .border_color(cx.theme().status().info_border)
23034            .size_full()
23035            .py(window.line_height() / 2.5)
23036            .on_action(cx.listener(Self::confirm))
23037            .on_action(cx.listener(Self::cancel))
23038            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23039            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23040    }
23041}
23042
23043impl Focusable for BreakpointPromptEditor {
23044    fn focus_handle(&self, cx: &App) -> FocusHandle {
23045        self.prompt.focus_handle(cx)
23046    }
23047}
23048
23049fn all_edits_insertions_or_deletions(
23050    edits: &Vec<(Range<Anchor>, String)>,
23051    snapshot: &MultiBufferSnapshot,
23052) -> bool {
23053    let mut all_insertions = true;
23054    let mut all_deletions = true;
23055
23056    for (range, new_text) in edits.iter() {
23057        let range_is_empty = range.to_offset(&snapshot).is_empty();
23058        let text_is_empty = new_text.is_empty();
23059
23060        if range_is_empty != text_is_empty {
23061            if range_is_empty {
23062                all_deletions = false;
23063            } else {
23064                all_insertions = false;
23065            }
23066        } else {
23067            return false;
23068        }
23069
23070        if !all_insertions && !all_deletions {
23071            return false;
23072        }
23073    }
23074    all_insertions || all_deletions
23075}
23076
23077struct MissingEditPredictionKeybindingTooltip;
23078
23079impl Render for MissingEditPredictionKeybindingTooltip {
23080    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23081        ui::tooltip_container(window, cx, |container, _, cx| {
23082            container
23083                .flex_shrink_0()
23084                .max_w_80()
23085                .min_h(rems_from_px(124.))
23086                .justify_between()
23087                .child(
23088                    v_flex()
23089                        .flex_1()
23090                        .text_ui_sm(cx)
23091                        .child(Label::new("Conflict with Accept Keybinding"))
23092                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23093                )
23094                .child(
23095                    h_flex()
23096                        .pb_1()
23097                        .gap_1()
23098                        .items_end()
23099                        .w_full()
23100                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23101                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23102                        }))
23103                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23104                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23105                        })),
23106                )
23107        })
23108    }
23109}
23110
23111#[derive(Debug, Clone, Copy, PartialEq)]
23112pub struct LineHighlight {
23113    pub background: Background,
23114    pub border: Option<gpui::Hsla>,
23115    pub include_gutter: bool,
23116    pub type_id: Option<TypeId>,
23117}
23118
23119struct LineManipulationResult {
23120    pub new_text: String,
23121    pub line_count_before: usize,
23122    pub line_count_after: usize,
23123}
23124
23125fn render_diff_hunk_controls(
23126    row: u32,
23127    status: &DiffHunkStatus,
23128    hunk_range: Range<Anchor>,
23129    is_created_file: bool,
23130    line_height: Pixels,
23131    editor: &Entity<Editor>,
23132    _window: &mut Window,
23133    cx: &mut App,
23134) -> AnyElement {
23135    h_flex()
23136        .h(line_height)
23137        .mr_1()
23138        .gap_1()
23139        .px_0p5()
23140        .pb_1()
23141        .border_x_1()
23142        .border_b_1()
23143        .border_color(cx.theme().colors().border_variant)
23144        .rounded_b_lg()
23145        .bg(cx.theme().colors().editor_background)
23146        .gap_1()
23147        .block_mouse_except_scroll()
23148        .shadow_md()
23149        .child(if status.has_secondary_hunk() {
23150            Button::new(("stage", row as u64), "Stage")
23151                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23152                .tooltip({
23153                    let focus_handle = editor.focus_handle(cx);
23154                    move |window, cx| {
23155                        Tooltip::for_action_in(
23156                            "Stage Hunk",
23157                            &::git::ToggleStaged,
23158                            &focus_handle,
23159                            window,
23160                            cx,
23161                        )
23162                    }
23163                })
23164                .on_click({
23165                    let editor = editor.clone();
23166                    move |_event, _window, cx| {
23167                        editor.update(cx, |editor, cx| {
23168                            editor.stage_or_unstage_diff_hunks(
23169                                true,
23170                                vec![hunk_range.start..hunk_range.start],
23171                                cx,
23172                            );
23173                        });
23174                    }
23175                })
23176        } else {
23177            Button::new(("unstage", row as u64), "Unstage")
23178                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23179                .tooltip({
23180                    let focus_handle = editor.focus_handle(cx);
23181                    move |window, cx| {
23182                        Tooltip::for_action_in(
23183                            "Unstage Hunk",
23184                            &::git::ToggleStaged,
23185                            &focus_handle,
23186                            window,
23187                            cx,
23188                        )
23189                    }
23190                })
23191                .on_click({
23192                    let editor = editor.clone();
23193                    move |_event, _window, cx| {
23194                        editor.update(cx, |editor, cx| {
23195                            editor.stage_or_unstage_diff_hunks(
23196                                false,
23197                                vec![hunk_range.start..hunk_range.start],
23198                                cx,
23199                            );
23200                        });
23201                    }
23202                })
23203        })
23204        .child(
23205            Button::new(("restore", row as u64), "Restore")
23206                .tooltip({
23207                    let focus_handle = editor.focus_handle(cx);
23208                    move |window, cx| {
23209                        Tooltip::for_action_in(
23210                            "Restore Hunk",
23211                            &::git::Restore,
23212                            &focus_handle,
23213                            window,
23214                            cx,
23215                        )
23216                    }
23217                })
23218                .on_click({
23219                    let editor = editor.clone();
23220                    move |_event, window, cx| {
23221                        editor.update(cx, |editor, cx| {
23222                            let snapshot = editor.snapshot(window, cx);
23223                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23224                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23225                        });
23226                    }
23227                })
23228                .disabled(is_created_file),
23229        )
23230        .when(
23231            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23232            |el| {
23233                el.child(
23234                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23235                        .shape(IconButtonShape::Square)
23236                        .icon_size(IconSize::Small)
23237                        // .disabled(!has_multiple_hunks)
23238                        .tooltip({
23239                            let focus_handle = editor.focus_handle(cx);
23240                            move |window, cx| {
23241                                Tooltip::for_action_in(
23242                                    "Next Hunk",
23243                                    &GoToHunk,
23244                                    &focus_handle,
23245                                    window,
23246                                    cx,
23247                                )
23248                            }
23249                        })
23250                        .on_click({
23251                            let editor = editor.clone();
23252                            move |_event, window, cx| {
23253                                editor.update(cx, |editor, cx| {
23254                                    let snapshot = editor.snapshot(window, cx);
23255                                    let position =
23256                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23257                                    editor.go_to_hunk_before_or_after_position(
23258                                        &snapshot,
23259                                        position,
23260                                        Direction::Next,
23261                                        window,
23262                                        cx,
23263                                    );
23264                                    editor.expand_selected_diff_hunks(cx);
23265                                });
23266                            }
23267                        }),
23268                )
23269                .child(
23270                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23271                        .shape(IconButtonShape::Square)
23272                        .icon_size(IconSize::Small)
23273                        // .disabled(!has_multiple_hunks)
23274                        .tooltip({
23275                            let focus_handle = editor.focus_handle(cx);
23276                            move |window, cx| {
23277                                Tooltip::for_action_in(
23278                                    "Previous Hunk",
23279                                    &GoToPreviousHunk,
23280                                    &focus_handle,
23281                                    window,
23282                                    cx,
23283                                )
23284                            }
23285                        })
23286                        .on_click({
23287                            let editor = editor.clone();
23288                            move |_event, window, cx| {
23289                                editor.update(cx, |editor, cx| {
23290                                    let snapshot = editor.snapshot(window, cx);
23291                                    let point =
23292                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23293                                    editor.go_to_hunk_before_or_after_position(
23294                                        &snapshot,
23295                                        point,
23296                                        Direction::Prev,
23297                                        window,
23298                                        cx,
23299                                    );
23300                                    editor.expand_selected_diff_hunks(cx);
23301                                });
23302                            }
23303                        }),
23304                )
23305            },
23306        )
23307        .into_any_element()
23308}