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, impl_actions, 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: 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    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  997    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  998    hard_wrap: Option<usize>,
  999
 1000    // TODO: make this a access method
 1001    pub project: Option<Entity<Project>>,
 1002    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1003    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1004    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1005    blink_manager: Entity<BlinkManager>,
 1006    show_cursor_names: bool,
 1007    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1008    pub show_local_selections: bool,
 1009    mode: EditorMode,
 1010    show_breadcrumbs: bool,
 1011    show_gutter: bool,
 1012    show_scrollbars: ScrollbarAxes,
 1013    minimap_visibility: MinimapVisibility,
 1014    offset_content: bool,
 1015    disable_expand_excerpt_buttons: bool,
 1016    show_line_numbers: Option<bool>,
 1017    use_relative_line_numbers: Option<bool>,
 1018    show_git_diff_gutter: Option<bool>,
 1019    show_code_actions: Option<bool>,
 1020    show_runnables: Option<bool>,
 1021    show_breakpoints: Option<bool>,
 1022    show_wrap_guides: Option<bool>,
 1023    show_indent_guides: Option<bool>,
 1024    placeholder_text: Option<Arc<str>>,
 1025    highlight_order: usize,
 1026    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1027    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1028    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1029    scrollbar_marker_state: ScrollbarMarkerState,
 1030    active_indent_guides_state: ActiveIndentGuidesState,
 1031    nav_history: Option<ItemNavHistory>,
 1032    context_menu: RefCell<Option<CodeContextMenu>>,
 1033    context_menu_options: Option<ContextMenuOptions>,
 1034    mouse_context_menu: Option<MouseContextMenu>,
 1035    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1036    inline_blame_popover: Option<InlineBlamePopover>,
 1037    inline_blame_popover_show_task: Option<Task<()>>,
 1038    signature_help_state: SignatureHelpState,
 1039    auto_signature_help: Option<bool>,
 1040    find_all_references_task_sources: Vec<Anchor>,
 1041    next_completion_id: CompletionId,
 1042    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1043    code_actions_task: Option<Task<Result<()>>>,
 1044    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1045    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1046    document_highlights_task: Option<Task<()>>,
 1047    linked_editing_range_task: Option<Task<Option<()>>>,
 1048    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1049    pending_rename: Option<RenameState>,
 1050    searchable: bool,
 1051    cursor_shape: CursorShape,
 1052    current_line_highlight: Option<CurrentLineHighlight>,
 1053    collapse_matches: bool,
 1054    autoindent_mode: Option<AutoindentMode>,
 1055    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1056    input_enabled: bool,
 1057    use_modal_editing: bool,
 1058    read_only: bool,
 1059    leader_id: Option<CollaboratorId>,
 1060    remote_id: Option<ViewId>,
 1061    pub hover_state: HoverState,
 1062    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1063    gutter_hovered: bool,
 1064    hovered_link_state: Option<HoveredLinkState>,
 1065    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1066    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1067    active_inline_completion: Option<InlineCompletionState>,
 1068    /// Used to prevent flickering as the user types while the menu is open
 1069    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1070    edit_prediction_settings: EditPredictionSettings,
 1071    inline_completions_hidden_for_vim_mode: bool,
 1072    show_inline_completions_override: Option<bool>,
 1073    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1074    edit_prediction_preview: EditPredictionPreview,
 1075    edit_prediction_indent_conflict: bool,
 1076    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1077    inlay_hint_cache: InlayHintCache,
 1078    next_inlay_id: usize,
 1079    _subscriptions: Vec<Subscription>,
 1080    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1081    gutter_dimensions: GutterDimensions,
 1082    style: Option<EditorStyle>,
 1083    text_style_refinement: Option<TextStyleRefinement>,
 1084    next_editor_action_id: EditorActionId,
 1085    editor_actions: Rc<
 1086        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1087    >,
 1088    use_autoclose: bool,
 1089    use_auto_surround: bool,
 1090    auto_replace_emoji_shortcode: bool,
 1091    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1092    show_git_blame_gutter: bool,
 1093    show_git_blame_inline: bool,
 1094    show_git_blame_inline_delay_task: Option<Task<()>>,
 1095    git_blame_inline_enabled: bool,
 1096    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1097    serialize_dirty_buffers: bool,
 1098    show_selection_menu: Option<bool>,
 1099    blame: Option<Entity<GitBlame>>,
 1100    blame_subscription: Option<Subscription>,
 1101    custom_context_menu: Option<
 1102        Box<
 1103            dyn 'static
 1104                + Fn(
 1105                    &mut Self,
 1106                    DisplayPoint,
 1107                    &mut Window,
 1108                    &mut Context<Self>,
 1109                ) -> Option<Entity<ui::ContextMenu>>,
 1110        >,
 1111    >,
 1112    last_bounds: Option<Bounds<Pixels>>,
 1113    last_position_map: Option<Rc<PositionMap>>,
 1114    expect_bounds_change: Option<Bounds<Pixels>>,
 1115    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1116    tasks_update_task: Option<Task<()>>,
 1117    breakpoint_store: Option<Entity<BreakpointStore>>,
 1118    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1119    hovered_diff_hunk_row: Option<DisplayRow>,
 1120    pull_diagnostics_task: Task<()>,
 1121    in_project_search: bool,
 1122    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1123    breadcrumb_header: Option<String>,
 1124    focused_block: Option<FocusedBlock>,
 1125    next_scroll_position: NextScrollCursorCenterTopBottom,
 1126    addons: HashMap<TypeId, Box<dyn Addon>>,
 1127    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1128    load_diff_task: Option<Shared<Task<()>>>,
 1129    /// Whether we are temporarily displaying a diff other than git's
 1130    temporary_diff_override: bool,
 1131    selection_mark_mode: bool,
 1132    toggle_fold_multiple_buffers: Task<()>,
 1133    _scroll_cursor_center_top_bottom_task: Task<()>,
 1134    serialize_selections: Task<()>,
 1135    serialize_folds: Task<()>,
 1136    mouse_cursor_hidden: bool,
 1137    minimap: Option<Entity<Self>>,
 1138    hide_mouse_mode: HideMouseMode,
 1139    pub change_list: ChangeList,
 1140    inline_value_cache: InlineValueCache,
 1141    selection_drag_state: SelectionDragState,
 1142    drag_and_drop_selection_enabled: bool,
 1143    next_color_inlay_id: usize,
 1144    colors: Option<LspColorData>,
 1145}
 1146
 1147#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1148enum NextScrollCursorCenterTopBottom {
 1149    #[default]
 1150    Center,
 1151    Top,
 1152    Bottom,
 1153}
 1154
 1155impl NextScrollCursorCenterTopBottom {
 1156    fn next(&self) -> Self {
 1157        match self {
 1158            Self::Center => Self::Top,
 1159            Self::Top => Self::Bottom,
 1160            Self::Bottom => Self::Center,
 1161        }
 1162    }
 1163}
 1164
 1165#[derive(Clone)]
 1166pub struct EditorSnapshot {
 1167    pub mode: EditorMode,
 1168    show_gutter: bool,
 1169    show_line_numbers: Option<bool>,
 1170    show_git_diff_gutter: Option<bool>,
 1171    show_code_actions: Option<bool>,
 1172    show_runnables: Option<bool>,
 1173    show_breakpoints: Option<bool>,
 1174    git_blame_gutter_max_author_length: Option<usize>,
 1175    pub display_snapshot: DisplaySnapshot,
 1176    pub placeholder_text: Option<Arc<str>>,
 1177    is_focused: bool,
 1178    scroll_anchor: ScrollAnchor,
 1179    ongoing_scroll: OngoingScroll,
 1180    current_line_highlight: CurrentLineHighlight,
 1181    gutter_hovered: bool,
 1182}
 1183
 1184#[derive(Default, Debug, Clone, Copy)]
 1185pub struct GutterDimensions {
 1186    pub left_padding: Pixels,
 1187    pub right_padding: Pixels,
 1188    pub width: Pixels,
 1189    pub margin: Pixels,
 1190    pub git_blame_entries_width: Option<Pixels>,
 1191}
 1192
 1193impl GutterDimensions {
 1194    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1195        Self {
 1196            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1197            ..Default::default()
 1198        }
 1199    }
 1200
 1201    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1202        -cx.text_system().descent(font_id, font_size)
 1203    }
 1204    /// The full width of the space taken up by the gutter.
 1205    pub fn full_width(&self) -> Pixels {
 1206        self.margin + self.width
 1207    }
 1208
 1209    /// The width of the space reserved for the fold indicators,
 1210    /// use alongside 'justify_end' and `gutter_width` to
 1211    /// right align content with the line numbers
 1212    pub fn fold_area_width(&self) -> Pixels {
 1213        self.margin + self.right_padding
 1214    }
 1215}
 1216
 1217#[derive(Debug)]
 1218pub struct RemoteSelection {
 1219    pub replica_id: ReplicaId,
 1220    pub selection: Selection<Anchor>,
 1221    pub cursor_shape: CursorShape,
 1222    pub collaborator_id: CollaboratorId,
 1223    pub line_mode: bool,
 1224    pub user_name: Option<SharedString>,
 1225    pub color: PlayerColor,
 1226}
 1227
 1228#[derive(Clone, Debug)]
 1229struct SelectionHistoryEntry {
 1230    selections: Arc<[Selection<Anchor>]>,
 1231    select_next_state: Option<SelectNextState>,
 1232    select_prev_state: Option<SelectNextState>,
 1233    add_selections_state: Option<AddSelectionsState>,
 1234}
 1235
 1236#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1237enum SelectionHistoryMode {
 1238    Normal,
 1239    Undoing,
 1240    Redoing,
 1241    Skipping,
 1242}
 1243
 1244#[derive(Clone, PartialEq, Eq, Hash)]
 1245struct HoveredCursor {
 1246    replica_id: u16,
 1247    selection_id: usize,
 1248}
 1249
 1250impl Default for SelectionHistoryMode {
 1251    fn default() -> Self {
 1252        Self::Normal
 1253    }
 1254}
 1255
 1256#[derive(Debug)]
 1257pub struct SelectionEffects {
 1258    nav_history: bool,
 1259    completions: bool,
 1260    scroll: Option<Autoscroll>,
 1261}
 1262
 1263impl Default for SelectionEffects {
 1264    fn default() -> Self {
 1265        Self {
 1266            nav_history: true,
 1267            completions: true,
 1268            scroll: Some(Autoscroll::fit()),
 1269        }
 1270    }
 1271}
 1272impl SelectionEffects {
 1273    pub fn scroll(scroll: Autoscroll) -> Self {
 1274        Self {
 1275            scroll: Some(scroll),
 1276            ..Default::default()
 1277        }
 1278    }
 1279
 1280    pub fn no_scroll() -> Self {
 1281        Self {
 1282            scroll: None,
 1283            ..Default::default()
 1284        }
 1285    }
 1286
 1287    pub fn completions(self, completions: bool) -> Self {
 1288        Self {
 1289            completions,
 1290            ..self
 1291        }
 1292    }
 1293
 1294    pub fn nav_history(self, nav_history: bool) -> Self {
 1295        Self {
 1296            nav_history,
 1297            ..self
 1298        }
 1299    }
 1300}
 1301
 1302struct DeferredSelectionEffectsState {
 1303    changed: bool,
 1304    effects: SelectionEffects,
 1305    old_cursor_position: Anchor,
 1306    history_entry: SelectionHistoryEntry,
 1307}
 1308
 1309#[derive(Default)]
 1310struct SelectionHistory {
 1311    #[allow(clippy::type_complexity)]
 1312    selections_by_transaction:
 1313        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1314    mode: SelectionHistoryMode,
 1315    undo_stack: VecDeque<SelectionHistoryEntry>,
 1316    redo_stack: VecDeque<SelectionHistoryEntry>,
 1317}
 1318
 1319impl SelectionHistory {
 1320    #[track_caller]
 1321    fn insert_transaction(
 1322        &mut self,
 1323        transaction_id: TransactionId,
 1324        selections: Arc<[Selection<Anchor>]>,
 1325    ) {
 1326        if selections.is_empty() {
 1327            log::error!(
 1328                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1329                std::panic::Location::caller()
 1330            );
 1331            return;
 1332        }
 1333        self.selections_by_transaction
 1334            .insert(transaction_id, (selections, None));
 1335    }
 1336
 1337    #[allow(clippy::type_complexity)]
 1338    fn transaction(
 1339        &self,
 1340        transaction_id: TransactionId,
 1341    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1342        self.selections_by_transaction.get(&transaction_id)
 1343    }
 1344
 1345    #[allow(clippy::type_complexity)]
 1346    fn transaction_mut(
 1347        &mut self,
 1348        transaction_id: TransactionId,
 1349    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1350        self.selections_by_transaction.get_mut(&transaction_id)
 1351    }
 1352
 1353    fn push(&mut self, entry: SelectionHistoryEntry) {
 1354        if !entry.selections.is_empty() {
 1355            match self.mode {
 1356                SelectionHistoryMode::Normal => {
 1357                    self.push_undo(entry);
 1358                    self.redo_stack.clear();
 1359                }
 1360                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1361                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1362                SelectionHistoryMode::Skipping => {}
 1363            }
 1364        }
 1365    }
 1366
 1367    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1368        if self
 1369            .undo_stack
 1370            .back()
 1371            .map_or(true, |e| e.selections != entry.selections)
 1372        {
 1373            self.undo_stack.push_back(entry);
 1374            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1375                self.undo_stack.pop_front();
 1376            }
 1377        }
 1378    }
 1379
 1380    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1381        if self
 1382            .redo_stack
 1383            .back()
 1384            .map_or(true, |e| e.selections != entry.selections)
 1385        {
 1386            self.redo_stack.push_back(entry);
 1387            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1388                self.redo_stack.pop_front();
 1389            }
 1390        }
 1391    }
 1392}
 1393
 1394#[derive(Clone, Copy)]
 1395pub struct RowHighlightOptions {
 1396    pub autoscroll: bool,
 1397    pub include_gutter: bool,
 1398}
 1399
 1400impl Default for RowHighlightOptions {
 1401    fn default() -> Self {
 1402        Self {
 1403            autoscroll: Default::default(),
 1404            include_gutter: true,
 1405        }
 1406    }
 1407}
 1408
 1409struct RowHighlight {
 1410    index: usize,
 1411    range: Range<Anchor>,
 1412    color: Hsla,
 1413    options: RowHighlightOptions,
 1414    type_id: TypeId,
 1415}
 1416
 1417#[derive(Clone, Debug)]
 1418struct AddSelectionsState {
 1419    groups: Vec<AddSelectionsGroup>,
 1420}
 1421
 1422#[derive(Clone, Debug)]
 1423struct AddSelectionsGroup {
 1424    above: bool,
 1425    stack: Vec<usize>,
 1426}
 1427
 1428#[derive(Clone)]
 1429struct SelectNextState {
 1430    query: AhoCorasick,
 1431    wordwise: bool,
 1432    done: bool,
 1433}
 1434
 1435impl std::fmt::Debug for SelectNextState {
 1436    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1437        f.debug_struct(std::any::type_name::<Self>())
 1438            .field("wordwise", &self.wordwise)
 1439            .field("done", &self.done)
 1440            .finish()
 1441    }
 1442}
 1443
 1444#[derive(Debug)]
 1445struct AutocloseRegion {
 1446    selection_id: usize,
 1447    range: Range<Anchor>,
 1448    pair: BracketPair,
 1449}
 1450
 1451#[derive(Debug)]
 1452struct SnippetState {
 1453    ranges: Vec<Vec<Range<Anchor>>>,
 1454    active_index: usize,
 1455    choices: Vec<Option<Vec<String>>>,
 1456}
 1457
 1458#[doc(hidden)]
 1459pub struct RenameState {
 1460    pub range: Range<Anchor>,
 1461    pub old_name: Arc<str>,
 1462    pub editor: Entity<Editor>,
 1463    block_id: CustomBlockId,
 1464}
 1465
 1466struct InvalidationStack<T>(Vec<T>);
 1467
 1468struct RegisteredInlineCompletionProvider {
 1469    provider: Arc<dyn InlineCompletionProviderHandle>,
 1470    _subscription: Subscription,
 1471}
 1472
 1473#[derive(Debug, PartialEq, Eq)]
 1474pub struct ActiveDiagnosticGroup {
 1475    pub active_range: Range<Anchor>,
 1476    pub active_message: String,
 1477    pub group_id: usize,
 1478    pub blocks: HashSet<CustomBlockId>,
 1479}
 1480
 1481#[derive(Debug, PartialEq, Eq)]
 1482
 1483pub(crate) enum ActiveDiagnostic {
 1484    None,
 1485    All,
 1486    Group(ActiveDiagnosticGroup),
 1487}
 1488
 1489#[derive(Serialize, Deserialize, Clone, Debug)]
 1490pub struct ClipboardSelection {
 1491    /// The number of bytes in this selection.
 1492    pub len: usize,
 1493    /// Whether this was a full-line selection.
 1494    pub is_entire_line: bool,
 1495    /// The indentation of the first line when this content was originally copied.
 1496    pub first_line_indent: u32,
 1497}
 1498
 1499// selections, scroll behavior, was newest selection reversed
 1500type SelectSyntaxNodeHistoryState = (
 1501    Box<[Selection<usize>]>,
 1502    SelectSyntaxNodeScrollBehavior,
 1503    bool,
 1504);
 1505
 1506#[derive(Default)]
 1507struct SelectSyntaxNodeHistory {
 1508    stack: Vec<SelectSyntaxNodeHistoryState>,
 1509    // disable temporarily to allow changing selections without losing the stack
 1510    pub disable_clearing: bool,
 1511}
 1512
 1513impl SelectSyntaxNodeHistory {
 1514    pub fn try_clear(&mut self) {
 1515        if !self.disable_clearing {
 1516            self.stack.clear();
 1517        }
 1518    }
 1519
 1520    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1521        self.stack.push(selection);
 1522    }
 1523
 1524    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1525        self.stack.pop()
 1526    }
 1527}
 1528
 1529enum SelectSyntaxNodeScrollBehavior {
 1530    CursorTop,
 1531    FitSelection,
 1532    CursorBottom,
 1533}
 1534
 1535#[derive(Debug)]
 1536pub(crate) struct NavigationData {
 1537    cursor_anchor: Anchor,
 1538    cursor_position: Point,
 1539    scroll_anchor: ScrollAnchor,
 1540    scroll_top_row: u32,
 1541}
 1542
 1543#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1544pub enum GotoDefinitionKind {
 1545    Symbol,
 1546    Declaration,
 1547    Type,
 1548    Implementation,
 1549}
 1550
 1551#[derive(Debug, Clone)]
 1552enum InlayHintRefreshReason {
 1553    ModifiersChanged(bool),
 1554    Toggle(bool),
 1555    SettingsChange(InlayHintSettings),
 1556    NewLinesShown,
 1557    BufferEdited(HashSet<Arc<Language>>),
 1558    RefreshRequested,
 1559    ExcerptsRemoved(Vec<ExcerptId>),
 1560}
 1561
 1562impl InlayHintRefreshReason {
 1563    fn description(&self) -> &'static str {
 1564        match self {
 1565            Self::ModifiersChanged(_) => "modifiers changed",
 1566            Self::Toggle(_) => "toggle",
 1567            Self::SettingsChange(_) => "settings change",
 1568            Self::NewLinesShown => "new lines shown",
 1569            Self::BufferEdited(_) => "buffer edited",
 1570            Self::RefreshRequested => "refresh requested",
 1571            Self::ExcerptsRemoved(_) => "excerpts removed",
 1572        }
 1573    }
 1574}
 1575
 1576pub enum FormatTarget {
 1577    Buffers(HashSet<Entity<Buffer>>),
 1578    Ranges(Vec<Range<MultiBufferPoint>>),
 1579}
 1580
 1581pub(crate) struct FocusedBlock {
 1582    id: BlockId,
 1583    focus_handle: WeakFocusHandle,
 1584}
 1585
 1586#[derive(Clone)]
 1587enum JumpData {
 1588    MultiBufferRow {
 1589        row: MultiBufferRow,
 1590        line_offset_from_top: u32,
 1591    },
 1592    MultiBufferPoint {
 1593        excerpt_id: ExcerptId,
 1594        position: Point,
 1595        anchor: text::Anchor,
 1596        line_offset_from_top: u32,
 1597    },
 1598}
 1599
 1600pub enum MultibufferSelectionMode {
 1601    First,
 1602    All,
 1603}
 1604
 1605#[derive(Clone, Copy, Debug, Default)]
 1606pub struct RewrapOptions {
 1607    pub override_language_settings: bool,
 1608    pub preserve_existing_whitespace: bool,
 1609}
 1610
 1611impl Editor {
 1612    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1613        let buffer = cx.new(|cx| Buffer::local("", cx));
 1614        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1615        Self::new(
 1616            EditorMode::SingleLine { auto_width: false },
 1617            buffer,
 1618            None,
 1619            window,
 1620            cx,
 1621        )
 1622    }
 1623
 1624    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1625        let buffer = cx.new(|cx| Buffer::local("", cx));
 1626        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1627        Self::new(EditorMode::full(), buffer, None, window, cx)
 1628    }
 1629
 1630    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1631        let buffer = cx.new(|cx| Buffer::local("", cx));
 1632        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1633        Self::new(
 1634            EditorMode::SingleLine { auto_width: true },
 1635            buffer,
 1636            None,
 1637            window,
 1638            cx,
 1639        )
 1640    }
 1641
 1642    pub fn auto_height(
 1643        min_lines: usize,
 1644        max_lines: usize,
 1645        window: &mut Window,
 1646        cx: &mut Context<Self>,
 1647    ) -> Self {
 1648        let buffer = cx.new(|cx| Buffer::local("", cx));
 1649        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1650        Self::new(
 1651            EditorMode::AutoHeight {
 1652                min_lines,
 1653                max_lines,
 1654            },
 1655            buffer,
 1656            None,
 1657            window,
 1658            cx,
 1659        )
 1660    }
 1661
 1662    pub fn for_buffer(
 1663        buffer: Entity<Buffer>,
 1664        project: Option<Entity<Project>>,
 1665        window: &mut Window,
 1666        cx: &mut Context<Self>,
 1667    ) -> Self {
 1668        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1669        Self::new(EditorMode::full(), buffer, project, window, cx)
 1670    }
 1671
 1672    pub fn for_multibuffer(
 1673        buffer: Entity<MultiBuffer>,
 1674        project: Option<Entity<Project>>,
 1675        window: &mut Window,
 1676        cx: &mut Context<Self>,
 1677    ) -> Self {
 1678        Self::new(EditorMode::full(), buffer, project, window, cx)
 1679    }
 1680
 1681    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1682        let mut clone = Self::new(
 1683            self.mode.clone(),
 1684            self.buffer.clone(),
 1685            self.project.clone(),
 1686            window,
 1687            cx,
 1688        );
 1689        self.display_map.update(cx, |display_map, cx| {
 1690            let snapshot = display_map.snapshot(cx);
 1691            clone.display_map.update(cx, |display_map, cx| {
 1692                display_map.set_state(&snapshot, cx);
 1693            });
 1694        });
 1695        clone.folds_did_change(cx);
 1696        clone.selections.clone_state(&self.selections);
 1697        clone.scroll_manager.clone_state(&self.scroll_manager);
 1698        clone.searchable = self.searchable;
 1699        clone.read_only = self.read_only;
 1700        clone
 1701    }
 1702
 1703    pub fn new(
 1704        mode: EditorMode,
 1705        buffer: Entity<MultiBuffer>,
 1706        project: Option<Entity<Project>>,
 1707        window: &mut Window,
 1708        cx: &mut Context<Self>,
 1709    ) -> Self {
 1710        Editor::new_internal(mode, buffer, project, None, window, cx)
 1711    }
 1712
 1713    fn new_internal(
 1714        mode: EditorMode,
 1715        buffer: Entity<MultiBuffer>,
 1716        project: Option<Entity<Project>>,
 1717        display_map: Option<Entity<DisplayMap>>,
 1718        window: &mut Window,
 1719        cx: &mut Context<Self>,
 1720    ) -> Self {
 1721        debug_assert!(
 1722            display_map.is_none() || mode.is_minimap(),
 1723            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1724        );
 1725
 1726        let full_mode = mode.is_full();
 1727        let diagnostics_max_severity = if full_mode {
 1728            EditorSettings::get_global(cx)
 1729                .diagnostics_max_severity
 1730                .unwrap_or(DiagnosticSeverity::Hint)
 1731        } else {
 1732            DiagnosticSeverity::Off
 1733        };
 1734        let style = window.text_style();
 1735        let font_size = style.font_size.to_pixels(window.rem_size());
 1736        let editor = cx.entity().downgrade();
 1737        let fold_placeholder = FoldPlaceholder {
 1738            constrain_width: true,
 1739            render: Arc::new(move |fold_id, fold_range, cx| {
 1740                let editor = editor.clone();
 1741                div()
 1742                    .id(fold_id)
 1743                    .bg(cx.theme().colors().ghost_element_background)
 1744                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1745                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1746                    .rounded_xs()
 1747                    .size_full()
 1748                    .cursor_pointer()
 1749                    .child("")
 1750                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1751                    .on_click(move |_, _window, cx| {
 1752                        editor
 1753                            .update(cx, |editor, cx| {
 1754                                editor.unfold_ranges(
 1755                                    &[fold_range.start..fold_range.end],
 1756                                    true,
 1757                                    false,
 1758                                    cx,
 1759                                );
 1760                                cx.stop_propagation();
 1761                            })
 1762                            .ok();
 1763                    })
 1764                    .into_any()
 1765            }),
 1766            merge_adjacent: true,
 1767            ..FoldPlaceholder::default()
 1768        };
 1769        let display_map = display_map.unwrap_or_else(|| {
 1770            cx.new(|cx| {
 1771                DisplayMap::new(
 1772                    buffer.clone(),
 1773                    style.font(),
 1774                    font_size,
 1775                    None,
 1776                    FILE_HEADER_HEIGHT,
 1777                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1778                    fold_placeholder,
 1779                    diagnostics_max_severity,
 1780                    cx,
 1781                )
 1782            })
 1783        });
 1784
 1785        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1786
 1787        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1788
 1789        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1790            .then(|| language_settings::SoftWrap::None);
 1791
 1792        let mut project_subscriptions = Vec::new();
 1793        if mode.is_full() {
 1794            if let Some(project) = project.as_ref() {
 1795                project_subscriptions.push(cx.subscribe_in(
 1796                    project,
 1797                    window,
 1798                    |editor, _, event, window, cx| match event {
 1799                        project::Event::RefreshCodeLens => {
 1800                            // we always query lens with actions, without storing them, always refreshing them
 1801                        }
 1802                        project::Event::RefreshInlayHints => {
 1803                            editor
 1804                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1805                        }
 1806                        project::Event::LanguageServerAdded(server_id, ..)
 1807                        | project::Event::LanguageServerRemoved(server_id) => {
 1808                            if editor.tasks_update_task.is_none() {
 1809                                editor.tasks_update_task =
 1810                                    Some(editor.refresh_runnables(window, cx));
 1811                            }
 1812                            editor.update_lsp_data(Some(*server_id), None, window, cx);
 1813                        }
 1814                        project::Event::SnippetEdit(id, snippet_edits) => {
 1815                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1816                                let focus_handle = editor.focus_handle(cx);
 1817                                if focus_handle.is_focused(window) {
 1818                                    let snapshot = buffer.read(cx).snapshot();
 1819                                    for (range, snippet) in snippet_edits {
 1820                                        let editor_range =
 1821                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1822                                        editor
 1823                                            .insert_snippet(
 1824                                                &[editor_range],
 1825                                                snippet.clone(),
 1826                                                window,
 1827                                                cx,
 1828                                            )
 1829                                            .ok();
 1830                                    }
 1831                                }
 1832                            }
 1833                        }
 1834                        _ => {}
 1835                    },
 1836                ));
 1837                if let Some(task_inventory) = project
 1838                    .read(cx)
 1839                    .task_store()
 1840                    .read(cx)
 1841                    .task_inventory()
 1842                    .cloned()
 1843                {
 1844                    project_subscriptions.push(cx.observe_in(
 1845                        &task_inventory,
 1846                        window,
 1847                        |editor, _, window, cx| {
 1848                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1849                        },
 1850                    ));
 1851                };
 1852
 1853                project_subscriptions.push(cx.subscribe_in(
 1854                    &project.read(cx).breakpoint_store(),
 1855                    window,
 1856                    |editor, _, event, window, cx| match event {
 1857                        BreakpointStoreEvent::ClearDebugLines => {
 1858                            editor.clear_row_highlights::<ActiveDebugLine>();
 1859                            editor.refresh_inline_values(cx);
 1860                        }
 1861                        BreakpointStoreEvent::SetDebugLine => {
 1862                            if editor.go_to_active_debug_line(window, cx) {
 1863                                cx.stop_propagation();
 1864                            }
 1865
 1866                            editor.refresh_inline_values(cx);
 1867                        }
 1868                        _ => {}
 1869                    },
 1870                ));
 1871                let git_store = project.read(cx).git_store().clone();
 1872                let project = project.clone();
 1873                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1874                    match event {
 1875                        GitStoreEvent::RepositoryUpdated(
 1876                            _,
 1877                            RepositoryEvent::Updated {
 1878                                new_instance: true, ..
 1879                            },
 1880                            _,
 1881                        ) => {
 1882                            this.load_diff_task = Some(
 1883                                update_uncommitted_diff_for_buffer(
 1884                                    cx.entity(),
 1885                                    &project,
 1886                                    this.buffer.read(cx).all_buffers(),
 1887                                    this.buffer.clone(),
 1888                                    cx,
 1889                                )
 1890                                .shared(),
 1891                            );
 1892                        }
 1893                        _ => {}
 1894                    }
 1895                }));
 1896            }
 1897        }
 1898
 1899        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1900
 1901        let inlay_hint_settings =
 1902            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1903        let focus_handle = cx.focus_handle();
 1904        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1905            .detach();
 1906        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1907            .detach();
 1908        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1909            .detach();
 1910        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1911            .detach();
 1912        cx.observe_pending_input(window, Self::observe_pending_input)
 1913            .detach();
 1914
 1915        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1916            Some(false)
 1917        } else {
 1918            None
 1919        };
 1920
 1921        let breakpoint_store = match (&mode, project.as_ref()) {
 1922            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1923            _ => None,
 1924        };
 1925
 1926        let mut code_action_providers = Vec::new();
 1927        let mut load_uncommitted_diff = None;
 1928        if let Some(project) = project.clone() {
 1929            load_uncommitted_diff = Some(
 1930                update_uncommitted_diff_for_buffer(
 1931                    cx.entity(),
 1932                    &project,
 1933                    buffer.read(cx).all_buffers(),
 1934                    buffer.clone(),
 1935                    cx,
 1936                )
 1937                .shared(),
 1938            );
 1939            code_action_providers.push(Rc::new(project) as Rc<_>);
 1940        }
 1941
 1942        let mut editor = Self {
 1943            focus_handle,
 1944            show_cursor_when_unfocused: false,
 1945            last_focused_descendant: None,
 1946            buffer: buffer.clone(),
 1947            display_map: display_map.clone(),
 1948            selections,
 1949            scroll_manager: ScrollManager::new(cx),
 1950            columnar_selection_state: None,
 1951            add_selections_state: None,
 1952            select_next_state: None,
 1953            select_prev_state: None,
 1954            selection_history: SelectionHistory::default(),
 1955            defer_selection_effects: false,
 1956            deferred_selection_effects_state: None,
 1957            autoclose_regions: Vec::new(),
 1958            snippet_stack: InvalidationStack::default(),
 1959            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1960            ime_transaction: None,
 1961            active_diagnostics: ActiveDiagnostic::None,
 1962            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1963            inline_diagnostics_update: Task::ready(()),
 1964            inline_diagnostics: Vec::new(),
 1965            soft_wrap_mode_override,
 1966            diagnostics_max_severity,
 1967            hard_wrap: None,
 1968            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1969            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1970            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1971            project,
 1972            blink_manager: blink_manager.clone(),
 1973            show_local_selections: true,
 1974            show_scrollbars: ScrollbarAxes {
 1975                horizontal: full_mode,
 1976                vertical: full_mode,
 1977            },
 1978            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1979            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1980            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1981            show_gutter: mode.is_full(),
 1982            show_line_numbers: None,
 1983            use_relative_line_numbers: None,
 1984            disable_expand_excerpt_buttons: false,
 1985            show_git_diff_gutter: None,
 1986            show_code_actions: None,
 1987            show_runnables: None,
 1988            show_breakpoints: None,
 1989            show_wrap_guides: None,
 1990            show_indent_guides,
 1991            placeholder_text: None,
 1992            highlight_order: 0,
 1993            highlighted_rows: HashMap::default(),
 1994            background_highlights: TreeMap::default(),
 1995            gutter_highlights: TreeMap::default(),
 1996            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1997            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1998            nav_history: None,
 1999            context_menu: RefCell::new(None),
 2000            context_menu_options: None,
 2001            mouse_context_menu: None,
 2002            completion_tasks: Vec::new(),
 2003            inline_blame_popover: None,
 2004            inline_blame_popover_show_task: None,
 2005            signature_help_state: SignatureHelpState::default(),
 2006            auto_signature_help: None,
 2007            find_all_references_task_sources: Vec::new(),
 2008            next_completion_id: 0,
 2009            next_inlay_id: 0,
 2010            code_action_providers,
 2011            available_code_actions: None,
 2012            code_actions_task: None,
 2013            quick_selection_highlight_task: None,
 2014            debounced_selection_highlight_task: None,
 2015            document_highlights_task: None,
 2016            linked_editing_range_task: None,
 2017            pending_rename: None,
 2018            searchable: true,
 2019            cursor_shape: EditorSettings::get_global(cx)
 2020                .cursor_shape
 2021                .unwrap_or_default(),
 2022            current_line_highlight: None,
 2023            autoindent_mode: Some(AutoindentMode::EachLine),
 2024            collapse_matches: false,
 2025            workspace: None,
 2026            input_enabled: true,
 2027            use_modal_editing: mode.is_full(),
 2028            read_only: mode.is_minimap(),
 2029            use_autoclose: true,
 2030            use_auto_surround: true,
 2031            auto_replace_emoji_shortcode: false,
 2032            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2033            leader_id: None,
 2034            remote_id: None,
 2035            hover_state: HoverState::default(),
 2036            pending_mouse_down: None,
 2037            hovered_link_state: None,
 2038            edit_prediction_provider: None,
 2039            active_inline_completion: None,
 2040            stale_inline_completion_in_menu: None,
 2041            edit_prediction_preview: EditPredictionPreview::Inactive {
 2042                released_too_fast: false,
 2043            },
 2044            inline_diagnostics_enabled: mode.is_full(),
 2045            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2046            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2047
 2048            gutter_hovered: false,
 2049            pixel_position_of_newest_cursor: None,
 2050            last_bounds: None,
 2051            last_position_map: None,
 2052            expect_bounds_change: None,
 2053            gutter_dimensions: GutterDimensions::default(),
 2054            style: None,
 2055            show_cursor_names: false,
 2056            hovered_cursors: HashMap::default(),
 2057            next_editor_action_id: EditorActionId::default(),
 2058            editor_actions: Rc::default(),
 2059            inline_completions_hidden_for_vim_mode: false,
 2060            show_inline_completions_override: None,
 2061            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2062            edit_prediction_settings: EditPredictionSettings::Disabled,
 2063            edit_prediction_indent_conflict: false,
 2064            edit_prediction_requires_modifier_in_indent_conflict: true,
 2065            custom_context_menu: None,
 2066            show_git_blame_gutter: false,
 2067            show_git_blame_inline: false,
 2068            show_selection_menu: None,
 2069            show_git_blame_inline_delay_task: None,
 2070            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2071            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2072            serialize_dirty_buffers: !mode.is_minimap()
 2073                && ProjectSettings::get_global(cx)
 2074                    .session
 2075                    .restore_unsaved_buffers,
 2076            blame: None,
 2077            blame_subscription: None,
 2078            tasks: BTreeMap::default(),
 2079
 2080            breakpoint_store,
 2081            gutter_breakpoint_indicator: (None, None),
 2082            hovered_diff_hunk_row: None,
 2083            _subscriptions: vec![
 2084                cx.observe(&buffer, Self::on_buffer_changed),
 2085                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2086                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2087                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2088                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2089                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2090                cx.observe_window_activation(window, |editor, window, cx| {
 2091                    let active = window.is_window_active();
 2092                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2093                        if active {
 2094                            blink_manager.enable(cx);
 2095                        } else {
 2096                            blink_manager.disable(cx);
 2097                        }
 2098                    });
 2099                    if active {
 2100                        editor.show_mouse_cursor(cx);
 2101                    }
 2102                }),
 2103            ],
 2104            tasks_update_task: None,
 2105            pull_diagnostics_task: Task::ready(()),
 2106            colors: None,
 2107            next_color_inlay_id: 0,
 2108            linked_edit_ranges: Default::default(),
 2109            in_project_search: false,
 2110            previous_search_ranges: None,
 2111            breadcrumb_header: None,
 2112            focused_block: None,
 2113            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2114            addons: HashMap::default(),
 2115            registered_buffers: HashMap::default(),
 2116            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2117            selection_mark_mode: false,
 2118            toggle_fold_multiple_buffers: Task::ready(()),
 2119            serialize_selections: Task::ready(()),
 2120            serialize_folds: Task::ready(()),
 2121            text_style_refinement: None,
 2122            load_diff_task: load_uncommitted_diff,
 2123            temporary_diff_override: false,
 2124            mouse_cursor_hidden: false,
 2125            minimap: None,
 2126            hide_mouse_mode: EditorSettings::get_global(cx)
 2127                .hide_mouse
 2128                .unwrap_or_default(),
 2129            change_list: ChangeList::new(),
 2130            mode,
 2131            selection_drag_state: SelectionDragState::None,
 2132            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2133        };
 2134        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2135            editor
 2136                ._subscriptions
 2137                .push(cx.observe(breakpoints, |_, _, cx| {
 2138                    cx.notify();
 2139                }));
 2140        }
 2141        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2142        editor._subscriptions.extend(project_subscriptions);
 2143
 2144        editor._subscriptions.push(cx.subscribe_in(
 2145            &cx.entity(),
 2146            window,
 2147            |editor, _, e: &EditorEvent, window, cx| match e {
 2148                EditorEvent::ScrollPositionChanged { local, .. } => {
 2149                    if *local {
 2150                        let new_anchor = editor.scroll_manager.anchor();
 2151                        let snapshot = editor.snapshot(window, cx);
 2152                        editor.update_restoration_data(cx, move |data| {
 2153                            data.scroll_position = (
 2154                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2155                                new_anchor.offset,
 2156                            );
 2157                        });
 2158                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2159                        editor.inline_blame_popover.take();
 2160                    }
 2161                }
 2162                EditorEvent::Edited { .. } => {
 2163                    if !vim_enabled(cx) {
 2164                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2165                        let pop_state = editor
 2166                            .change_list
 2167                            .last()
 2168                            .map(|previous| {
 2169                                previous.len() == selections.len()
 2170                                    && previous.iter().enumerate().all(|(ix, p)| {
 2171                                        p.to_display_point(&map).row()
 2172                                            == selections[ix].head().row()
 2173                                    })
 2174                            })
 2175                            .unwrap_or(false);
 2176                        let new_positions = selections
 2177                            .into_iter()
 2178                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2179                            .collect();
 2180                        editor
 2181                            .change_list
 2182                            .push_to_change_list(pop_state, new_positions);
 2183                    }
 2184                }
 2185                _ => (),
 2186            },
 2187        ));
 2188
 2189        if let Some(dap_store) = editor
 2190            .project
 2191            .as_ref()
 2192            .map(|project| project.read(cx).dap_store())
 2193        {
 2194            let weak_editor = cx.weak_entity();
 2195
 2196            editor
 2197                ._subscriptions
 2198                .push(
 2199                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2200                        let session_entity = cx.entity();
 2201                        weak_editor
 2202                            .update(cx, |editor, cx| {
 2203                                editor._subscriptions.push(
 2204                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2205                                );
 2206                            })
 2207                            .ok();
 2208                    }),
 2209                );
 2210
 2211            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2212                editor
 2213                    ._subscriptions
 2214                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2215            }
 2216        }
 2217
 2218        // skip adding the initial selection to selection history
 2219        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2220        editor.end_selection(window, cx);
 2221        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2222
 2223        editor.scroll_manager.show_scrollbars(window, cx);
 2224        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2225
 2226        if full_mode {
 2227            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2228            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2229
 2230            if editor.git_blame_inline_enabled {
 2231                editor.start_git_blame_inline(false, window, cx);
 2232            }
 2233
 2234            editor.go_to_active_debug_line(window, cx);
 2235
 2236            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2237                if let Some(project) = editor.project.as_ref() {
 2238                    let handle = project.update(cx, |project, cx| {
 2239                        project.register_buffer_with_language_servers(&buffer, cx)
 2240                    });
 2241                    editor
 2242                        .registered_buffers
 2243                        .insert(buffer.read(cx).remote_id(), handle);
 2244                }
 2245            }
 2246
 2247            editor.minimap =
 2248                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2249            editor.colors = Some(LspColorData::new(cx));
 2250            editor.update_lsp_data(None, None, window, cx);
 2251        }
 2252
 2253        editor.report_editor_event("Editor Opened", None, cx);
 2254        editor
 2255    }
 2256
 2257    pub fn deploy_mouse_context_menu(
 2258        &mut self,
 2259        position: gpui::Point<Pixels>,
 2260        context_menu: Entity<ContextMenu>,
 2261        window: &mut Window,
 2262        cx: &mut Context<Self>,
 2263    ) {
 2264        self.mouse_context_menu = Some(MouseContextMenu::new(
 2265            self,
 2266            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2267            context_menu,
 2268            window,
 2269            cx,
 2270        ));
 2271    }
 2272
 2273    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2274        self.mouse_context_menu
 2275            .as_ref()
 2276            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2277    }
 2278
 2279    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2280        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2281    }
 2282
 2283    fn key_context_internal(
 2284        &self,
 2285        has_active_edit_prediction: bool,
 2286        window: &Window,
 2287        cx: &App,
 2288    ) -> KeyContext {
 2289        let mut key_context = KeyContext::new_with_defaults();
 2290        key_context.add("Editor");
 2291        let mode = match self.mode {
 2292            EditorMode::SingleLine { .. } => "single_line",
 2293            EditorMode::AutoHeight { .. } => "auto_height",
 2294            EditorMode::Minimap { .. } => "minimap",
 2295            EditorMode::Full { .. } => "full",
 2296        };
 2297
 2298        if EditorSettings::jupyter_enabled(cx) {
 2299            key_context.add("jupyter");
 2300        }
 2301
 2302        key_context.set("mode", mode);
 2303        if self.pending_rename.is_some() {
 2304            key_context.add("renaming");
 2305        }
 2306
 2307        match self.context_menu.borrow().as_ref() {
 2308            Some(CodeContextMenu::Completions(_)) => {
 2309                key_context.add("menu");
 2310                key_context.add("showing_completions");
 2311            }
 2312            Some(CodeContextMenu::CodeActions(_)) => {
 2313                key_context.add("menu");
 2314                key_context.add("showing_code_actions")
 2315            }
 2316            None => {}
 2317        }
 2318
 2319        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2320        if !self.focus_handle(cx).contains_focused(window, cx)
 2321            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2322        {
 2323            for addon in self.addons.values() {
 2324                addon.extend_key_context(&mut key_context, cx)
 2325            }
 2326        }
 2327
 2328        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2329            if let Some(extension) = singleton_buffer
 2330                .read(cx)
 2331                .file()
 2332                .and_then(|file| file.path().extension()?.to_str())
 2333            {
 2334                key_context.set("extension", extension.to_string());
 2335            }
 2336        } else {
 2337            key_context.add("multibuffer");
 2338        }
 2339
 2340        if has_active_edit_prediction {
 2341            if self.edit_prediction_in_conflict() {
 2342                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2343            } else {
 2344                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2345                key_context.add("copilot_suggestion");
 2346            }
 2347        }
 2348
 2349        if self.selection_mark_mode {
 2350            key_context.add("selection_mode");
 2351        }
 2352
 2353        key_context
 2354    }
 2355
 2356    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2357        if self.mouse_cursor_hidden {
 2358            self.mouse_cursor_hidden = false;
 2359            cx.notify();
 2360        }
 2361    }
 2362
 2363    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2364        let hide_mouse_cursor = match origin {
 2365            HideMouseCursorOrigin::TypingAction => {
 2366                matches!(
 2367                    self.hide_mouse_mode,
 2368                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2369                )
 2370            }
 2371            HideMouseCursorOrigin::MovementAction => {
 2372                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2373            }
 2374        };
 2375        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2376            self.mouse_cursor_hidden = hide_mouse_cursor;
 2377            cx.notify();
 2378        }
 2379    }
 2380
 2381    pub fn edit_prediction_in_conflict(&self) -> bool {
 2382        if !self.show_edit_predictions_in_menu() {
 2383            return false;
 2384        }
 2385
 2386        let showing_completions = self
 2387            .context_menu
 2388            .borrow()
 2389            .as_ref()
 2390            .map_or(false, |context| {
 2391                matches!(context, CodeContextMenu::Completions(_))
 2392            });
 2393
 2394        showing_completions
 2395            || self.edit_prediction_requires_modifier()
 2396            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2397            // bindings to insert tab characters.
 2398            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2399    }
 2400
 2401    pub fn accept_edit_prediction_keybind(
 2402        &self,
 2403        accept_partial: bool,
 2404        window: &Window,
 2405        cx: &App,
 2406    ) -> AcceptEditPredictionBinding {
 2407        let key_context = self.key_context_internal(true, window, cx);
 2408        let in_conflict = self.edit_prediction_in_conflict();
 2409
 2410        let bindings = if accept_partial {
 2411            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2412        } else {
 2413            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2414        };
 2415
 2416        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2417        // just the first one.
 2418        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2419            !in_conflict
 2420                || binding
 2421                    .keystrokes()
 2422                    .first()
 2423                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2424        }))
 2425    }
 2426
 2427    pub fn new_file(
 2428        workspace: &mut Workspace,
 2429        _: &workspace::NewFile,
 2430        window: &mut Window,
 2431        cx: &mut Context<Workspace>,
 2432    ) {
 2433        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2434            "Failed to create buffer",
 2435            window,
 2436            cx,
 2437            |e, _, _| match e.error_code() {
 2438                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2439                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2440                e.error_tag("required").unwrap_or("the latest version")
 2441            )),
 2442                _ => None,
 2443            },
 2444        );
 2445    }
 2446
 2447    pub fn new_in_workspace(
 2448        workspace: &mut Workspace,
 2449        window: &mut Window,
 2450        cx: &mut Context<Workspace>,
 2451    ) -> Task<Result<Entity<Editor>>> {
 2452        let project = workspace.project().clone();
 2453        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2454
 2455        cx.spawn_in(window, async move |workspace, cx| {
 2456            let buffer = create.await?;
 2457            workspace.update_in(cx, |workspace, window, cx| {
 2458                let editor =
 2459                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2460                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2461                editor
 2462            })
 2463        })
 2464    }
 2465
 2466    fn new_file_vertical(
 2467        workspace: &mut Workspace,
 2468        _: &workspace::NewFileSplitVertical,
 2469        window: &mut Window,
 2470        cx: &mut Context<Workspace>,
 2471    ) {
 2472        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2473    }
 2474
 2475    fn new_file_horizontal(
 2476        workspace: &mut Workspace,
 2477        _: &workspace::NewFileSplitHorizontal,
 2478        window: &mut Window,
 2479        cx: &mut Context<Workspace>,
 2480    ) {
 2481        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2482    }
 2483
 2484    fn new_file_in_direction(
 2485        workspace: &mut Workspace,
 2486        direction: SplitDirection,
 2487        window: &mut Window,
 2488        cx: &mut Context<Workspace>,
 2489    ) {
 2490        let project = workspace.project().clone();
 2491        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2492
 2493        cx.spawn_in(window, async move |workspace, cx| {
 2494            let buffer = create.await?;
 2495            workspace.update_in(cx, move |workspace, window, cx| {
 2496                workspace.split_item(
 2497                    direction,
 2498                    Box::new(
 2499                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2500                    ),
 2501                    window,
 2502                    cx,
 2503                )
 2504            })?;
 2505            anyhow::Ok(())
 2506        })
 2507        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2508            match e.error_code() {
 2509                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2510                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2511                e.error_tag("required").unwrap_or("the latest version")
 2512            )),
 2513                _ => None,
 2514            }
 2515        });
 2516    }
 2517
 2518    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2519        self.leader_id
 2520    }
 2521
 2522    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2523        &self.buffer
 2524    }
 2525
 2526    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2527        self.workspace.as_ref()?.0.upgrade()
 2528    }
 2529
 2530    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2531        self.buffer().read(cx).title(cx)
 2532    }
 2533
 2534    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2535        let git_blame_gutter_max_author_length = self
 2536            .render_git_blame_gutter(cx)
 2537            .then(|| {
 2538                if let Some(blame) = self.blame.as_ref() {
 2539                    let max_author_length =
 2540                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2541                    Some(max_author_length)
 2542                } else {
 2543                    None
 2544                }
 2545            })
 2546            .flatten();
 2547
 2548        EditorSnapshot {
 2549            mode: self.mode.clone(),
 2550            show_gutter: self.show_gutter,
 2551            show_line_numbers: self.show_line_numbers,
 2552            show_git_diff_gutter: self.show_git_diff_gutter,
 2553            show_code_actions: self.show_code_actions,
 2554            show_runnables: self.show_runnables,
 2555            show_breakpoints: self.show_breakpoints,
 2556            git_blame_gutter_max_author_length,
 2557            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2558            scroll_anchor: self.scroll_manager.anchor(),
 2559            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2560            placeholder_text: self.placeholder_text.clone(),
 2561            is_focused: self.focus_handle.is_focused(window),
 2562            current_line_highlight: self
 2563                .current_line_highlight
 2564                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2565            gutter_hovered: self.gutter_hovered,
 2566        }
 2567    }
 2568
 2569    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2570        self.buffer.read(cx).language_at(point, cx)
 2571    }
 2572
 2573    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2574        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2575    }
 2576
 2577    pub fn active_excerpt(
 2578        &self,
 2579        cx: &App,
 2580    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2581        self.buffer
 2582            .read(cx)
 2583            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2584    }
 2585
 2586    pub fn mode(&self) -> &EditorMode {
 2587        &self.mode
 2588    }
 2589
 2590    pub fn set_mode(&mut self, mode: EditorMode) {
 2591        self.mode = mode;
 2592    }
 2593
 2594    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2595        self.collaboration_hub.as_deref()
 2596    }
 2597
 2598    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2599        self.collaboration_hub = Some(hub);
 2600    }
 2601
 2602    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2603        self.in_project_search = in_project_search;
 2604    }
 2605
 2606    pub fn set_custom_context_menu(
 2607        &mut self,
 2608        f: impl 'static
 2609        + Fn(
 2610            &mut Self,
 2611            DisplayPoint,
 2612            &mut Window,
 2613            &mut Context<Self>,
 2614        ) -> Option<Entity<ui::ContextMenu>>,
 2615    ) {
 2616        self.custom_context_menu = Some(Box::new(f))
 2617    }
 2618
 2619    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2620        self.completion_provider = provider;
 2621    }
 2622
 2623    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2624        self.semantics_provider.clone()
 2625    }
 2626
 2627    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2628        self.semantics_provider = provider;
 2629    }
 2630
 2631    pub fn set_edit_prediction_provider<T>(
 2632        &mut self,
 2633        provider: Option<Entity<T>>,
 2634        window: &mut Window,
 2635        cx: &mut Context<Self>,
 2636    ) where
 2637        T: EditPredictionProvider,
 2638    {
 2639        self.edit_prediction_provider =
 2640            provider.map(|provider| RegisteredInlineCompletionProvider {
 2641                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2642                    if this.focus_handle.is_focused(window) {
 2643                        this.update_visible_inline_completion(window, cx);
 2644                    }
 2645                }),
 2646                provider: Arc::new(provider),
 2647            });
 2648        self.update_edit_prediction_settings(cx);
 2649        self.refresh_inline_completion(false, false, window, cx);
 2650    }
 2651
 2652    pub fn placeholder_text(&self) -> Option<&str> {
 2653        self.placeholder_text.as_deref()
 2654    }
 2655
 2656    pub fn set_placeholder_text(
 2657        &mut self,
 2658        placeholder_text: impl Into<Arc<str>>,
 2659        cx: &mut Context<Self>,
 2660    ) {
 2661        let placeholder_text = Some(placeholder_text.into());
 2662        if self.placeholder_text != placeholder_text {
 2663            self.placeholder_text = placeholder_text;
 2664            cx.notify();
 2665        }
 2666    }
 2667
 2668    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2669        self.cursor_shape = cursor_shape;
 2670
 2671        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2672        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2673
 2674        cx.notify();
 2675    }
 2676
 2677    pub fn set_current_line_highlight(
 2678        &mut self,
 2679        current_line_highlight: Option<CurrentLineHighlight>,
 2680    ) {
 2681        self.current_line_highlight = current_line_highlight;
 2682    }
 2683
 2684    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2685        self.collapse_matches = collapse_matches;
 2686    }
 2687
 2688    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2689        let buffers = self.buffer.read(cx).all_buffers();
 2690        let Some(project) = self.project.as_ref() else {
 2691            return;
 2692        };
 2693        project.update(cx, |project, cx| {
 2694            for buffer in buffers {
 2695                self.registered_buffers
 2696                    .entry(buffer.read(cx).remote_id())
 2697                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2698            }
 2699        })
 2700    }
 2701
 2702    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2703        if self.collapse_matches {
 2704            return range.start..range.start;
 2705        }
 2706        range.clone()
 2707    }
 2708
 2709    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2710        if self.display_map.read(cx).clip_at_line_ends != clip {
 2711            self.display_map
 2712                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2713        }
 2714    }
 2715
 2716    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2717        self.input_enabled = input_enabled;
 2718    }
 2719
 2720    pub fn set_inline_completions_hidden_for_vim_mode(
 2721        &mut self,
 2722        hidden: bool,
 2723        window: &mut Window,
 2724        cx: &mut Context<Self>,
 2725    ) {
 2726        if hidden != self.inline_completions_hidden_for_vim_mode {
 2727            self.inline_completions_hidden_for_vim_mode = hidden;
 2728            if hidden {
 2729                self.update_visible_inline_completion(window, cx);
 2730            } else {
 2731                self.refresh_inline_completion(true, false, window, cx);
 2732            }
 2733        }
 2734    }
 2735
 2736    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2737        self.menu_inline_completions_policy = value;
 2738    }
 2739
 2740    pub fn set_autoindent(&mut self, autoindent: bool) {
 2741        if autoindent {
 2742            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2743        } else {
 2744            self.autoindent_mode = None;
 2745        }
 2746    }
 2747
 2748    pub fn read_only(&self, cx: &App) -> bool {
 2749        self.read_only || self.buffer.read(cx).read_only()
 2750    }
 2751
 2752    pub fn set_read_only(&mut self, read_only: bool) {
 2753        self.read_only = read_only;
 2754    }
 2755
 2756    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2757        self.use_autoclose = autoclose;
 2758    }
 2759
 2760    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2761        self.use_auto_surround = auto_surround;
 2762    }
 2763
 2764    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2765        self.auto_replace_emoji_shortcode = auto_replace;
 2766    }
 2767
 2768    pub fn toggle_edit_predictions(
 2769        &mut self,
 2770        _: &ToggleEditPrediction,
 2771        window: &mut Window,
 2772        cx: &mut Context<Self>,
 2773    ) {
 2774        if self.show_inline_completions_override.is_some() {
 2775            self.set_show_edit_predictions(None, window, cx);
 2776        } else {
 2777            let show_edit_predictions = !self.edit_predictions_enabled();
 2778            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2779        }
 2780    }
 2781
 2782    pub fn set_show_edit_predictions(
 2783        &mut self,
 2784        show_edit_predictions: Option<bool>,
 2785        window: &mut Window,
 2786        cx: &mut Context<Self>,
 2787    ) {
 2788        self.show_inline_completions_override = show_edit_predictions;
 2789        self.update_edit_prediction_settings(cx);
 2790
 2791        if let Some(false) = show_edit_predictions {
 2792            self.discard_inline_completion(false, cx);
 2793        } else {
 2794            self.refresh_inline_completion(false, true, window, cx);
 2795        }
 2796    }
 2797
 2798    fn inline_completions_disabled_in_scope(
 2799        &self,
 2800        buffer: &Entity<Buffer>,
 2801        buffer_position: language::Anchor,
 2802        cx: &App,
 2803    ) -> bool {
 2804        let snapshot = buffer.read(cx).snapshot();
 2805        let settings = snapshot.settings_at(buffer_position, cx);
 2806
 2807        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2808            return false;
 2809        };
 2810
 2811        scope.override_name().map_or(false, |scope_name| {
 2812            settings
 2813                .edit_predictions_disabled_in
 2814                .iter()
 2815                .any(|s| s == scope_name)
 2816        })
 2817    }
 2818
 2819    pub fn set_use_modal_editing(&mut self, to: bool) {
 2820        self.use_modal_editing = to;
 2821    }
 2822
 2823    pub fn use_modal_editing(&self) -> bool {
 2824        self.use_modal_editing
 2825    }
 2826
 2827    fn selections_did_change(
 2828        &mut self,
 2829        local: bool,
 2830        old_cursor_position: &Anchor,
 2831        effects: SelectionEffects,
 2832        window: &mut Window,
 2833        cx: &mut Context<Self>,
 2834    ) {
 2835        window.invalidate_character_coordinates();
 2836
 2837        // Copy selections to primary selection buffer
 2838        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2839        if local {
 2840            let selections = self.selections.all::<usize>(cx);
 2841            let buffer_handle = self.buffer.read(cx).read(cx);
 2842
 2843            let mut text = String::new();
 2844            for (index, selection) in selections.iter().enumerate() {
 2845                let text_for_selection = buffer_handle
 2846                    .text_for_range(selection.start..selection.end)
 2847                    .collect::<String>();
 2848
 2849                text.push_str(&text_for_selection);
 2850                if index != selections.len() - 1 {
 2851                    text.push('\n');
 2852                }
 2853            }
 2854
 2855            if !text.is_empty() {
 2856                cx.write_to_primary(ClipboardItem::new_string(text));
 2857            }
 2858        }
 2859
 2860        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2861            self.buffer.update(cx, |buffer, cx| {
 2862                buffer.set_active_selections(
 2863                    &self.selections.disjoint_anchors(),
 2864                    self.selections.line_mode,
 2865                    self.cursor_shape,
 2866                    cx,
 2867                )
 2868            });
 2869        }
 2870        let display_map = self
 2871            .display_map
 2872            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2873        let buffer = &display_map.buffer_snapshot;
 2874        if self.selections.count() == 1 {
 2875            self.add_selections_state = None;
 2876        }
 2877        self.select_next_state = None;
 2878        self.select_prev_state = None;
 2879        self.select_syntax_node_history.try_clear();
 2880        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2881        self.snippet_stack
 2882            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2883        self.take_rename(false, window, cx);
 2884
 2885        let newest_selection = self.selections.newest_anchor();
 2886        let new_cursor_position = newest_selection.head();
 2887        let selection_start = newest_selection.start;
 2888
 2889        if effects.nav_history {
 2890            self.push_to_nav_history(
 2891                *old_cursor_position,
 2892                Some(new_cursor_position.to_point(buffer)),
 2893                false,
 2894                cx,
 2895            );
 2896        }
 2897
 2898        if local {
 2899            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2900                if !self.registered_buffers.contains_key(&buffer_id) {
 2901                    if let Some(project) = self.project.as_ref() {
 2902                        project.update(cx, |project, cx| {
 2903                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2904                                return;
 2905                            };
 2906                            self.registered_buffers.insert(
 2907                                buffer_id,
 2908                                project.register_buffer_with_language_servers(&buffer, cx),
 2909                            );
 2910                        })
 2911                    }
 2912                }
 2913            }
 2914
 2915            let mut context_menu = self.context_menu.borrow_mut();
 2916            let completion_menu = match context_menu.as_ref() {
 2917                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2918                Some(CodeContextMenu::CodeActions(_)) => {
 2919                    *context_menu = None;
 2920                    None
 2921                }
 2922                None => None,
 2923            };
 2924            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2925            drop(context_menu);
 2926
 2927            if effects.completions {
 2928                if let Some(completion_position) = completion_position {
 2929                    let start_offset = selection_start.to_offset(buffer);
 2930                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2931                    let continue_showing = if position_matches {
 2932                        if self.snippet_stack.is_empty() {
 2933                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2934                        } else {
 2935                            // Snippet choices can be shown even when the cursor is in whitespace.
 2936                            // Dismissing the menu with actions like backspace is handled by
 2937                            // invalidation regions.
 2938                            true
 2939                        }
 2940                    } else {
 2941                        false
 2942                    };
 2943
 2944                    if continue_showing {
 2945                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2946                    } else {
 2947                        self.hide_context_menu(window, cx);
 2948                    }
 2949                }
 2950            }
 2951
 2952            hide_hover(self, cx);
 2953
 2954            if old_cursor_position.to_display_point(&display_map).row()
 2955                != new_cursor_position.to_display_point(&display_map).row()
 2956            {
 2957                self.available_code_actions.take();
 2958            }
 2959            self.refresh_code_actions(window, cx);
 2960            self.refresh_document_highlights(cx);
 2961            self.refresh_selected_text_highlights(false, window, cx);
 2962            refresh_matching_bracket_highlights(self, window, cx);
 2963            self.update_visible_inline_completion(window, cx);
 2964            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2965            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2966            self.inline_blame_popover.take();
 2967            if self.git_blame_inline_enabled {
 2968                self.start_inline_blame_timer(window, cx);
 2969            }
 2970        }
 2971
 2972        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2973        cx.emit(EditorEvent::SelectionsChanged { local });
 2974
 2975        let selections = &self.selections.disjoint;
 2976        if selections.len() == 1 {
 2977            cx.emit(SearchEvent::ActiveMatchChanged)
 2978        }
 2979        if local {
 2980            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2981                let inmemory_selections = selections
 2982                    .iter()
 2983                    .map(|s| {
 2984                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2985                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2986                    })
 2987                    .collect();
 2988                self.update_restoration_data(cx, |data| {
 2989                    data.selections = inmemory_selections;
 2990                });
 2991
 2992                if WorkspaceSettings::get(None, cx).restore_on_startup
 2993                    != RestoreOnStartupBehavior::None
 2994                {
 2995                    if let Some(workspace_id) =
 2996                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2997                    {
 2998                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2999                        let selections = selections.clone();
 3000                        let background_executor = cx.background_executor().clone();
 3001                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3002                        self.serialize_selections = cx.background_spawn(async move {
 3003                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3004                            let db_selections = selections
 3005                                .iter()
 3006                                .map(|selection| {
 3007                                    (
 3008                                        selection.start.to_offset(&snapshot),
 3009                                        selection.end.to_offset(&snapshot),
 3010                                    )
 3011                                })
 3012                                .collect();
 3013
 3014                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3015                                .await
 3016                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3017                                .log_err();
 3018                        });
 3019                    }
 3020                }
 3021            }
 3022        }
 3023
 3024        cx.notify();
 3025    }
 3026
 3027    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3028        use text::ToOffset as _;
 3029        use text::ToPoint as _;
 3030
 3031        if self.mode.is_minimap()
 3032            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3033        {
 3034            return;
 3035        }
 3036
 3037        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3038            return;
 3039        };
 3040
 3041        let snapshot = singleton.read(cx).snapshot();
 3042        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3043            let display_snapshot = display_map.snapshot(cx);
 3044
 3045            display_snapshot
 3046                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3047                .map(|fold| {
 3048                    fold.range.start.text_anchor.to_point(&snapshot)
 3049                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3050                })
 3051                .collect()
 3052        });
 3053        self.update_restoration_data(cx, |data| {
 3054            data.folds = inmemory_folds;
 3055        });
 3056
 3057        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3058            return;
 3059        };
 3060        let background_executor = cx.background_executor().clone();
 3061        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3062        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3063            display_map
 3064                .snapshot(cx)
 3065                .folds_in_range(0..snapshot.len())
 3066                .map(|fold| {
 3067                    (
 3068                        fold.range.start.text_anchor.to_offset(&snapshot),
 3069                        fold.range.end.text_anchor.to_offset(&snapshot),
 3070                    )
 3071                })
 3072                .collect()
 3073        });
 3074        self.serialize_folds = cx.background_spawn(async move {
 3075            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3076            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3077                .await
 3078                .with_context(|| {
 3079                    format!(
 3080                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3081                    )
 3082                })
 3083                .log_err();
 3084        });
 3085    }
 3086
 3087    pub fn sync_selections(
 3088        &mut self,
 3089        other: Entity<Editor>,
 3090        cx: &mut Context<Self>,
 3091    ) -> gpui::Subscription {
 3092        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3093        self.selections.change_with(cx, |selections| {
 3094            selections.select_anchors(other_selections);
 3095        });
 3096
 3097        let other_subscription =
 3098            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3099                EditorEvent::SelectionsChanged { local: true } => {
 3100                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3101                    if other_selections.is_empty() {
 3102                        return;
 3103                    }
 3104                    this.selections.change_with(cx, |selections| {
 3105                        selections.select_anchors(other_selections);
 3106                    });
 3107                }
 3108                _ => {}
 3109            });
 3110
 3111        let this_subscription =
 3112            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3113                EditorEvent::SelectionsChanged { local: true } => {
 3114                    let these_selections = this.selections.disjoint.to_vec();
 3115                    if these_selections.is_empty() {
 3116                        return;
 3117                    }
 3118                    other.update(cx, |other_editor, cx| {
 3119                        other_editor.selections.change_with(cx, |selections| {
 3120                            selections.select_anchors(these_selections);
 3121                        })
 3122                    });
 3123                }
 3124                _ => {}
 3125            });
 3126
 3127        Subscription::join(other_subscription, this_subscription)
 3128    }
 3129
 3130    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3131    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3132    /// effects of selection change occur at the end of the transaction.
 3133    pub fn change_selections<R>(
 3134        &mut self,
 3135        effects: impl Into<SelectionEffects>,
 3136        window: &mut Window,
 3137        cx: &mut Context<Self>,
 3138        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3139    ) -> R {
 3140        let effects = effects.into();
 3141        if let Some(state) = &mut self.deferred_selection_effects_state {
 3142            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3143            state.effects.completions = effects.completions;
 3144            state.effects.nav_history |= effects.nav_history;
 3145            let (changed, result) = self.selections.change_with(cx, change);
 3146            state.changed |= changed;
 3147            return result;
 3148        }
 3149        let mut state = DeferredSelectionEffectsState {
 3150            changed: false,
 3151            effects,
 3152            old_cursor_position: self.selections.newest_anchor().head(),
 3153            history_entry: SelectionHistoryEntry {
 3154                selections: self.selections.disjoint_anchors(),
 3155                select_next_state: self.select_next_state.clone(),
 3156                select_prev_state: self.select_prev_state.clone(),
 3157                add_selections_state: self.add_selections_state.clone(),
 3158            },
 3159        };
 3160        let (changed, result) = self.selections.change_with(cx, change);
 3161        state.changed = state.changed || changed;
 3162        if self.defer_selection_effects {
 3163            self.deferred_selection_effects_state = Some(state);
 3164        } else {
 3165            self.apply_selection_effects(state, window, cx);
 3166        }
 3167        result
 3168    }
 3169
 3170    /// Defers the effects of selection change, so that the effects of multiple calls to
 3171    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3172    /// to selection history and the state of popovers based on selection position aren't
 3173    /// erroneously updated.
 3174    pub fn with_selection_effects_deferred<R>(
 3175        &mut self,
 3176        window: &mut Window,
 3177        cx: &mut Context<Self>,
 3178        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3179    ) -> R {
 3180        let already_deferred = self.defer_selection_effects;
 3181        self.defer_selection_effects = true;
 3182        let result = update(self, window, cx);
 3183        if !already_deferred {
 3184            self.defer_selection_effects = false;
 3185            if let Some(state) = self.deferred_selection_effects_state.take() {
 3186                self.apply_selection_effects(state, window, cx);
 3187            }
 3188        }
 3189        result
 3190    }
 3191
 3192    fn apply_selection_effects(
 3193        &mut self,
 3194        state: DeferredSelectionEffectsState,
 3195        window: &mut Window,
 3196        cx: &mut Context<Self>,
 3197    ) {
 3198        if state.changed {
 3199            self.selection_history.push(state.history_entry);
 3200
 3201            if let Some(autoscroll) = state.effects.scroll {
 3202                self.request_autoscroll(autoscroll, cx);
 3203            }
 3204
 3205            let old_cursor_position = &state.old_cursor_position;
 3206
 3207            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3208
 3209            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3210                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3211            }
 3212        }
 3213    }
 3214
 3215    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3216    where
 3217        I: IntoIterator<Item = (Range<S>, T)>,
 3218        S: ToOffset,
 3219        T: Into<Arc<str>>,
 3220    {
 3221        if self.read_only(cx) {
 3222            return;
 3223        }
 3224
 3225        self.buffer
 3226            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3227    }
 3228
 3229    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3230    where
 3231        I: IntoIterator<Item = (Range<S>, T)>,
 3232        S: ToOffset,
 3233        T: Into<Arc<str>>,
 3234    {
 3235        if self.read_only(cx) {
 3236            return;
 3237        }
 3238
 3239        self.buffer.update(cx, |buffer, cx| {
 3240            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3241        });
 3242    }
 3243
 3244    pub fn edit_with_block_indent<I, S, T>(
 3245        &mut self,
 3246        edits: I,
 3247        original_indent_columns: Vec<Option<u32>>,
 3248        cx: &mut Context<Self>,
 3249    ) where
 3250        I: IntoIterator<Item = (Range<S>, T)>,
 3251        S: ToOffset,
 3252        T: Into<Arc<str>>,
 3253    {
 3254        if self.read_only(cx) {
 3255            return;
 3256        }
 3257
 3258        self.buffer.update(cx, |buffer, cx| {
 3259            buffer.edit(
 3260                edits,
 3261                Some(AutoindentMode::Block {
 3262                    original_indent_columns,
 3263                }),
 3264                cx,
 3265            )
 3266        });
 3267    }
 3268
 3269    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3270        self.hide_context_menu(window, cx);
 3271
 3272        match phase {
 3273            SelectPhase::Begin {
 3274                position,
 3275                add,
 3276                click_count,
 3277            } => self.begin_selection(position, add, click_count, window, cx),
 3278            SelectPhase::BeginColumnar {
 3279                position,
 3280                goal_column,
 3281                reset,
 3282                mode,
 3283            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3284            SelectPhase::Extend {
 3285                position,
 3286                click_count,
 3287            } => self.extend_selection(position, click_count, window, cx),
 3288            SelectPhase::Update {
 3289                position,
 3290                goal_column,
 3291                scroll_delta,
 3292            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3293            SelectPhase::End => self.end_selection(window, cx),
 3294        }
 3295    }
 3296
 3297    fn extend_selection(
 3298        &mut self,
 3299        position: DisplayPoint,
 3300        click_count: usize,
 3301        window: &mut Window,
 3302        cx: &mut Context<Self>,
 3303    ) {
 3304        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3305        let tail = self.selections.newest::<usize>(cx).tail();
 3306        self.begin_selection(position, false, click_count, window, cx);
 3307
 3308        let position = position.to_offset(&display_map, Bias::Left);
 3309        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3310
 3311        let mut pending_selection = self
 3312            .selections
 3313            .pending_anchor()
 3314            .expect("extend_selection not called with pending selection");
 3315        if position >= tail {
 3316            pending_selection.start = tail_anchor;
 3317        } else {
 3318            pending_selection.end = tail_anchor;
 3319            pending_selection.reversed = true;
 3320        }
 3321
 3322        let mut pending_mode = self.selections.pending_mode().unwrap();
 3323        match &mut pending_mode {
 3324            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3325            _ => {}
 3326        }
 3327
 3328        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3329            SelectionEffects::scroll(Autoscroll::fit())
 3330        } else {
 3331            SelectionEffects::no_scroll()
 3332        };
 3333
 3334        self.change_selections(effects, window, cx, |s| {
 3335            s.set_pending(pending_selection, pending_mode)
 3336        });
 3337    }
 3338
 3339    fn begin_selection(
 3340        &mut self,
 3341        position: DisplayPoint,
 3342        add: bool,
 3343        click_count: usize,
 3344        window: &mut Window,
 3345        cx: &mut Context<Self>,
 3346    ) {
 3347        if !self.focus_handle.is_focused(window) {
 3348            self.last_focused_descendant = None;
 3349            window.focus(&self.focus_handle);
 3350        }
 3351
 3352        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3353        let buffer = &display_map.buffer_snapshot;
 3354        let position = display_map.clip_point(position, Bias::Left);
 3355
 3356        let start;
 3357        let end;
 3358        let mode;
 3359        let mut auto_scroll;
 3360        match click_count {
 3361            1 => {
 3362                start = buffer.anchor_before(position.to_point(&display_map));
 3363                end = start;
 3364                mode = SelectMode::Character;
 3365                auto_scroll = true;
 3366            }
 3367            2 => {
 3368                let range = movement::surrounding_word(&display_map, position);
 3369                start = buffer.anchor_before(range.start.to_point(&display_map));
 3370                end = buffer.anchor_before(range.end.to_point(&display_map));
 3371                mode = SelectMode::Word(start..end);
 3372                auto_scroll = true;
 3373            }
 3374            3 => {
 3375                let position = display_map
 3376                    .clip_point(position, Bias::Left)
 3377                    .to_point(&display_map);
 3378                let line_start = display_map.prev_line_boundary(position).0;
 3379                let next_line_start = buffer.clip_point(
 3380                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3381                    Bias::Left,
 3382                );
 3383                start = buffer.anchor_before(line_start);
 3384                end = buffer.anchor_before(next_line_start);
 3385                mode = SelectMode::Line(start..end);
 3386                auto_scroll = true;
 3387            }
 3388            _ => {
 3389                start = buffer.anchor_before(0);
 3390                end = buffer.anchor_before(buffer.len());
 3391                mode = SelectMode::All;
 3392                auto_scroll = false;
 3393            }
 3394        }
 3395        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3396
 3397        let point_to_delete: Option<usize> = {
 3398            let selected_points: Vec<Selection<Point>> =
 3399                self.selections.disjoint_in_range(start..end, cx);
 3400
 3401            if !add || click_count > 1 {
 3402                None
 3403            } else if !selected_points.is_empty() {
 3404                Some(selected_points[0].id)
 3405            } else {
 3406                let clicked_point_already_selected =
 3407                    self.selections.disjoint.iter().find(|selection| {
 3408                        selection.start.to_point(buffer) == start.to_point(buffer)
 3409                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3410                    });
 3411
 3412                clicked_point_already_selected.map(|selection| selection.id)
 3413            }
 3414        };
 3415
 3416        let selections_count = self.selections.count();
 3417
 3418        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3419            if let Some(point_to_delete) = point_to_delete {
 3420                s.delete(point_to_delete);
 3421
 3422                if selections_count == 1 {
 3423                    s.set_pending_anchor_range(start..end, mode);
 3424                }
 3425            } else {
 3426                if !add {
 3427                    s.clear_disjoint();
 3428                }
 3429
 3430                s.set_pending_anchor_range(start..end, mode);
 3431            }
 3432        });
 3433    }
 3434
 3435    fn begin_columnar_selection(
 3436        &mut self,
 3437        position: DisplayPoint,
 3438        goal_column: u32,
 3439        reset: bool,
 3440        mode: ColumnarMode,
 3441        window: &mut Window,
 3442        cx: &mut Context<Self>,
 3443    ) {
 3444        if !self.focus_handle.is_focused(window) {
 3445            self.last_focused_descendant = None;
 3446            window.focus(&self.focus_handle);
 3447        }
 3448
 3449        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3450
 3451        if reset {
 3452            let pointer_position = display_map
 3453                .buffer_snapshot
 3454                .anchor_before(position.to_point(&display_map));
 3455
 3456            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3457                s.clear_disjoint();
 3458                s.set_pending_anchor_range(
 3459                    pointer_position..pointer_position,
 3460                    SelectMode::Character,
 3461                );
 3462            });
 3463        };
 3464
 3465        let tail = self.selections.newest::<Point>(cx).tail();
 3466        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3467        self.columnar_selection_state = match mode {
 3468            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3469                selection_tail: selection_anchor,
 3470                display_point: if reset {
 3471                    if position.column() != goal_column {
 3472                        Some(DisplayPoint::new(position.row(), goal_column))
 3473                    } else {
 3474                        None
 3475                    }
 3476                } else {
 3477                    None
 3478                },
 3479            }),
 3480            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3481                selection_tail: selection_anchor,
 3482            }),
 3483        };
 3484
 3485        if !reset {
 3486            self.select_columns(position, goal_column, &display_map, window, cx);
 3487        }
 3488    }
 3489
 3490    fn update_selection(
 3491        &mut self,
 3492        position: DisplayPoint,
 3493        goal_column: u32,
 3494        scroll_delta: gpui::Point<f32>,
 3495        window: &mut Window,
 3496        cx: &mut Context<Self>,
 3497    ) {
 3498        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3499
 3500        if self.columnar_selection_state.is_some() {
 3501            self.select_columns(position, goal_column, &display_map, window, cx);
 3502        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3503            let buffer = self.buffer.read(cx).snapshot(cx);
 3504            let head;
 3505            let tail;
 3506            let mode = self.selections.pending_mode().unwrap();
 3507            match &mode {
 3508                SelectMode::Character => {
 3509                    head = position.to_point(&display_map);
 3510                    tail = pending.tail().to_point(&buffer);
 3511                }
 3512                SelectMode::Word(original_range) => {
 3513                    let original_display_range = original_range.start.to_display_point(&display_map)
 3514                        ..original_range.end.to_display_point(&display_map);
 3515                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3516                        ..original_display_range.end.to_point(&display_map);
 3517                    if movement::is_inside_word(&display_map, position)
 3518                        || original_display_range.contains(&position)
 3519                    {
 3520                        let word_range = movement::surrounding_word(&display_map, position);
 3521                        if word_range.start < original_display_range.start {
 3522                            head = word_range.start.to_point(&display_map);
 3523                        } else {
 3524                            head = word_range.end.to_point(&display_map);
 3525                        }
 3526                    } else {
 3527                        head = position.to_point(&display_map);
 3528                    }
 3529
 3530                    if head <= original_buffer_range.start {
 3531                        tail = original_buffer_range.end;
 3532                    } else {
 3533                        tail = original_buffer_range.start;
 3534                    }
 3535                }
 3536                SelectMode::Line(original_range) => {
 3537                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3538
 3539                    let position = display_map
 3540                        .clip_point(position, Bias::Left)
 3541                        .to_point(&display_map);
 3542                    let line_start = display_map.prev_line_boundary(position).0;
 3543                    let next_line_start = buffer.clip_point(
 3544                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3545                        Bias::Left,
 3546                    );
 3547
 3548                    if line_start < original_range.start {
 3549                        head = line_start
 3550                    } else {
 3551                        head = next_line_start
 3552                    }
 3553
 3554                    if head <= original_range.start {
 3555                        tail = original_range.end;
 3556                    } else {
 3557                        tail = original_range.start;
 3558                    }
 3559                }
 3560                SelectMode::All => {
 3561                    return;
 3562                }
 3563            };
 3564
 3565            if head < tail {
 3566                pending.start = buffer.anchor_before(head);
 3567                pending.end = buffer.anchor_before(tail);
 3568                pending.reversed = true;
 3569            } else {
 3570                pending.start = buffer.anchor_before(tail);
 3571                pending.end = buffer.anchor_before(head);
 3572                pending.reversed = false;
 3573            }
 3574
 3575            self.change_selections(None, window, cx, |s| {
 3576                s.set_pending(pending, mode);
 3577            });
 3578        } else {
 3579            log::error!("update_selection dispatched with no pending selection");
 3580            return;
 3581        }
 3582
 3583        self.apply_scroll_delta(scroll_delta, window, cx);
 3584        cx.notify();
 3585    }
 3586
 3587    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3588        self.columnar_selection_state.take();
 3589        if self.selections.pending_anchor().is_some() {
 3590            let selections = self.selections.all::<usize>(cx);
 3591            self.change_selections(None, window, cx, |s| {
 3592                s.select(selections);
 3593                s.clear_pending();
 3594            });
 3595        }
 3596    }
 3597
 3598    fn select_columns(
 3599        &mut self,
 3600        head: DisplayPoint,
 3601        goal_column: u32,
 3602        display_map: &DisplaySnapshot,
 3603        window: &mut Window,
 3604        cx: &mut Context<Self>,
 3605    ) {
 3606        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3607            return;
 3608        };
 3609
 3610        let tail = match columnar_state {
 3611            ColumnarSelectionState::FromMouse {
 3612                selection_tail,
 3613                display_point,
 3614            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3615            ColumnarSelectionState::FromSelection { selection_tail } => {
 3616                selection_tail.to_display_point(&display_map)
 3617            }
 3618        };
 3619
 3620        let start_row = cmp::min(tail.row(), head.row());
 3621        let end_row = cmp::max(tail.row(), head.row());
 3622        let start_column = cmp::min(tail.column(), goal_column);
 3623        let end_column = cmp::max(tail.column(), goal_column);
 3624        let reversed = start_column < tail.column();
 3625
 3626        let selection_ranges = (start_row.0..=end_row.0)
 3627            .map(DisplayRow)
 3628            .filter_map(|row| {
 3629                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3630                    || start_column <= display_map.line_len(row))
 3631                    && !display_map.is_block_line(row)
 3632                {
 3633                    let start = display_map
 3634                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3635                        .to_point(display_map);
 3636                    let end = display_map
 3637                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3638                        .to_point(display_map);
 3639                    if reversed {
 3640                        Some(end..start)
 3641                    } else {
 3642                        Some(start..end)
 3643                    }
 3644                } else {
 3645                    None
 3646                }
 3647            })
 3648            .collect::<Vec<_>>();
 3649
 3650        let ranges = match columnar_state {
 3651            ColumnarSelectionState::FromMouse { .. } => {
 3652                let mut non_empty_ranges = selection_ranges
 3653                    .iter()
 3654                    .filter(|selection_range| selection_range.start != selection_range.end)
 3655                    .peekable();
 3656                if non_empty_ranges.peek().is_some() {
 3657                    non_empty_ranges.cloned().collect()
 3658                } else {
 3659                    selection_ranges
 3660                }
 3661            }
 3662            _ => selection_ranges,
 3663        };
 3664
 3665        self.change_selections(None, window, cx, |s| {
 3666            s.select_ranges(ranges);
 3667        });
 3668        cx.notify();
 3669    }
 3670
 3671    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3672        self.selections
 3673            .all_adjusted(cx)
 3674            .iter()
 3675            .any(|selection| !selection.is_empty())
 3676    }
 3677
 3678    pub fn has_pending_nonempty_selection(&self) -> bool {
 3679        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3680            Some(Selection { start, end, .. }) => start != end,
 3681            None => false,
 3682        };
 3683
 3684        pending_nonempty_selection
 3685            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3686    }
 3687
 3688    pub fn has_pending_selection(&self) -> bool {
 3689        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3690    }
 3691
 3692    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3693        self.selection_mark_mode = false;
 3694        self.selection_drag_state = SelectionDragState::None;
 3695
 3696        if self.clear_expanded_diff_hunks(cx) {
 3697            cx.notify();
 3698            return;
 3699        }
 3700        if self.dismiss_menus_and_popups(true, window, cx) {
 3701            return;
 3702        }
 3703
 3704        if self.mode.is_full()
 3705            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3706        {
 3707            return;
 3708        }
 3709
 3710        cx.propagate();
 3711    }
 3712
 3713    pub fn dismiss_menus_and_popups(
 3714        &mut self,
 3715        is_user_requested: bool,
 3716        window: &mut Window,
 3717        cx: &mut Context<Self>,
 3718    ) -> bool {
 3719        if self.take_rename(false, window, cx).is_some() {
 3720            return true;
 3721        }
 3722
 3723        if hide_hover(self, cx) {
 3724            return true;
 3725        }
 3726
 3727        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3728            return true;
 3729        }
 3730
 3731        if self.hide_context_menu(window, cx).is_some() {
 3732            return true;
 3733        }
 3734
 3735        if self.mouse_context_menu.take().is_some() {
 3736            return true;
 3737        }
 3738
 3739        if is_user_requested && self.discard_inline_completion(true, cx) {
 3740            return true;
 3741        }
 3742
 3743        if self.snippet_stack.pop().is_some() {
 3744            return true;
 3745        }
 3746
 3747        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3748            self.dismiss_diagnostics(cx);
 3749            return true;
 3750        }
 3751
 3752        false
 3753    }
 3754
 3755    fn linked_editing_ranges_for(
 3756        &self,
 3757        selection: Range<text::Anchor>,
 3758        cx: &App,
 3759    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3760        if self.linked_edit_ranges.is_empty() {
 3761            return None;
 3762        }
 3763        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3764            selection.end.buffer_id.and_then(|end_buffer_id| {
 3765                if selection.start.buffer_id != Some(end_buffer_id) {
 3766                    return None;
 3767                }
 3768                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3769                let snapshot = buffer.read(cx).snapshot();
 3770                self.linked_edit_ranges
 3771                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3772                    .map(|ranges| (ranges, snapshot, buffer))
 3773            })?;
 3774        use text::ToOffset as TO;
 3775        // find offset from the start of current range to current cursor position
 3776        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3777
 3778        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3779        let start_difference = start_offset - start_byte_offset;
 3780        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3781        let end_difference = end_offset - start_byte_offset;
 3782        // Current range has associated linked ranges.
 3783        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3784        for range in linked_ranges.iter() {
 3785            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3786            let end_offset = start_offset + end_difference;
 3787            let start_offset = start_offset + start_difference;
 3788            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3789                continue;
 3790            }
 3791            if self.selections.disjoint_anchor_ranges().any(|s| {
 3792                if s.start.buffer_id != selection.start.buffer_id
 3793                    || s.end.buffer_id != selection.end.buffer_id
 3794                {
 3795                    return false;
 3796                }
 3797                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3798                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3799            }) {
 3800                continue;
 3801            }
 3802            let start = buffer_snapshot.anchor_after(start_offset);
 3803            let end = buffer_snapshot.anchor_after(end_offset);
 3804            linked_edits
 3805                .entry(buffer.clone())
 3806                .or_default()
 3807                .push(start..end);
 3808        }
 3809        Some(linked_edits)
 3810    }
 3811
 3812    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3813        let text: Arc<str> = text.into();
 3814
 3815        if self.read_only(cx) {
 3816            return;
 3817        }
 3818
 3819        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3820
 3821        let selections = self.selections.all_adjusted(cx);
 3822        let mut bracket_inserted = false;
 3823        let mut edits = Vec::new();
 3824        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3825        let mut new_selections = Vec::with_capacity(selections.len());
 3826        let mut new_autoclose_regions = Vec::new();
 3827        let snapshot = self.buffer.read(cx).read(cx);
 3828        let mut clear_linked_edit_ranges = false;
 3829
 3830        for (selection, autoclose_region) in
 3831            self.selections_with_autoclose_regions(selections, &snapshot)
 3832        {
 3833            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3834                // Determine if the inserted text matches the opening or closing
 3835                // bracket of any of this language's bracket pairs.
 3836                let mut bracket_pair = None;
 3837                let mut is_bracket_pair_start = false;
 3838                let mut is_bracket_pair_end = false;
 3839                if !text.is_empty() {
 3840                    let mut bracket_pair_matching_end = None;
 3841                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3842                    //  and they are removing the character that triggered IME popup.
 3843                    for (pair, enabled) in scope.brackets() {
 3844                        if !pair.close && !pair.surround {
 3845                            continue;
 3846                        }
 3847
 3848                        if enabled && pair.start.ends_with(text.as_ref()) {
 3849                            let prefix_len = pair.start.len() - text.len();
 3850                            let preceding_text_matches_prefix = prefix_len == 0
 3851                                || (selection.start.column >= (prefix_len as u32)
 3852                                    && snapshot.contains_str_at(
 3853                                        Point::new(
 3854                                            selection.start.row,
 3855                                            selection.start.column - (prefix_len as u32),
 3856                                        ),
 3857                                        &pair.start[..prefix_len],
 3858                                    ));
 3859                            if preceding_text_matches_prefix {
 3860                                bracket_pair = Some(pair.clone());
 3861                                is_bracket_pair_start = true;
 3862                                break;
 3863                            }
 3864                        }
 3865                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3866                        {
 3867                            // take first bracket pair matching end, but don't break in case a later bracket
 3868                            // pair matches start
 3869                            bracket_pair_matching_end = Some(pair.clone());
 3870                        }
 3871                    }
 3872                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3873                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3874                        is_bracket_pair_end = true;
 3875                    }
 3876                }
 3877
 3878                if let Some(bracket_pair) = bracket_pair {
 3879                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3880                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3881                    let auto_surround =
 3882                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3883                    if selection.is_empty() {
 3884                        if is_bracket_pair_start {
 3885                            // If the inserted text is a suffix of an opening bracket and the
 3886                            // selection is preceded by the rest of the opening bracket, then
 3887                            // insert the closing bracket.
 3888                            let following_text_allows_autoclose = snapshot
 3889                                .chars_at(selection.start)
 3890                                .next()
 3891                                .map_or(true, |c| scope.should_autoclose_before(c));
 3892
 3893                            let preceding_text_allows_autoclose = selection.start.column == 0
 3894                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3895                                    true,
 3896                                    |c| {
 3897                                        bracket_pair.start != bracket_pair.end
 3898                                            || !snapshot
 3899                                                .char_classifier_at(selection.start)
 3900                                                .is_word(c)
 3901                                    },
 3902                                );
 3903
 3904                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3905                                && bracket_pair.start.len() == 1
 3906                            {
 3907                                let target = bracket_pair.start.chars().next().unwrap();
 3908                                let current_line_count = snapshot
 3909                                    .reversed_chars_at(selection.start)
 3910                                    .take_while(|&c| c != '\n')
 3911                                    .filter(|&c| c == target)
 3912                                    .count();
 3913                                current_line_count % 2 == 1
 3914                            } else {
 3915                                false
 3916                            };
 3917
 3918                            if autoclose
 3919                                && bracket_pair.close
 3920                                && following_text_allows_autoclose
 3921                                && preceding_text_allows_autoclose
 3922                                && !is_closing_quote
 3923                            {
 3924                                let anchor = snapshot.anchor_before(selection.end);
 3925                                new_selections.push((selection.map(|_| anchor), text.len()));
 3926                                new_autoclose_regions.push((
 3927                                    anchor,
 3928                                    text.len(),
 3929                                    selection.id,
 3930                                    bracket_pair.clone(),
 3931                                ));
 3932                                edits.push((
 3933                                    selection.range(),
 3934                                    format!("{}{}", text, bracket_pair.end).into(),
 3935                                ));
 3936                                bracket_inserted = true;
 3937                                continue;
 3938                            }
 3939                        }
 3940
 3941                        if let Some(region) = autoclose_region {
 3942                            // If the selection is followed by an auto-inserted closing bracket,
 3943                            // then don't insert that closing bracket again; just move the selection
 3944                            // past the closing bracket.
 3945                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3946                                && text.as_ref() == region.pair.end.as_str();
 3947                            if should_skip {
 3948                                let anchor = snapshot.anchor_after(selection.end);
 3949                                new_selections
 3950                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3951                                continue;
 3952                            }
 3953                        }
 3954
 3955                        let always_treat_brackets_as_autoclosed = snapshot
 3956                            .language_settings_at(selection.start, cx)
 3957                            .always_treat_brackets_as_autoclosed;
 3958                        if always_treat_brackets_as_autoclosed
 3959                            && is_bracket_pair_end
 3960                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3961                        {
 3962                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3963                            // and the inserted text is a closing bracket and the selection is followed
 3964                            // by the closing bracket then move the selection past the closing bracket.
 3965                            let anchor = snapshot.anchor_after(selection.end);
 3966                            new_selections.push((selection.map(|_| anchor), text.len()));
 3967                            continue;
 3968                        }
 3969                    }
 3970                    // If an opening bracket is 1 character long and is typed while
 3971                    // text is selected, then surround that text with the bracket pair.
 3972                    else if auto_surround
 3973                        && bracket_pair.surround
 3974                        && is_bracket_pair_start
 3975                        && bracket_pair.start.chars().count() == 1
 3976                    {
 3977                        edits.push((selection.start..selection.start, text.clone()));
 3978                        edits.push((
 3979                            selection.end..selection.end,
 3980                            bracket_pair.end.as_str().into(),
 3981                        ));
 3982                        bracket_inserted = true;
 3983                        new_selections.push((
 3984                            Selection {
 3985                                id: selection.id,
 3986                                start: snapshot.anchor_after(selection.start),
 3987                                end: snapshot.anchor_before(selection.end),
 3988                                reversed: selection.reversed,
 3989                                goal: selection.goal,
 3990                            },
 3991                            0,
 3992                        ));
 3993                        continue;
 3994                    }
 3995                }
 3996            }
 3997
 3998            if self.auto_replace_emoji_shortcode
 3999                && selection.is_empty()
 4000                && text.as_ref().ends_with(':')
 4001            {
 4002                if let Some(possible_emoji_short_code) =
 4003                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4004                {
 4005                    if !possible_emoji_short_code.is_empty() {
 4006                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4007                            let emoji_shortcode_start = Point::new(
 4008                                selection.start.row,
 4009                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4010                            );
 4011
 4012                            // Remove shortcode from buffer
 4013                            edits.push((
 4014                                emoji_shortcode_start..selection.start,
 4015                                "".to_string().into(),
 4016                            ));
 4017                            new_selections.push((
 4018                                Selection {
 4019                                    id: selection.id,
 4020                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4021                                    end: snapshot.anchor_before(selection.start),
 4022                                    reversed: selection.reversed,
 4023                                    goal: selection.goal,
 4024                                },
 4025                                0,
 4026                            ));
 4027
 4028                            // Insert emoji
 4029                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4030                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4031                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4032
 4033                            continue;
 4034                        }
 4035                    }
 4036                }
 4037            }
 4038
 4039            // If not handling any auto-close operation, then just replace the selected
 4040            // text with the given input and move the selection to the end of the
 4041            // newly inserted text.
 4042            let anchor = snapshot.anchor_after(selection.end);
 4043            if !self.linked_edit_ranges.is_empty() {
 4044                let start_anchor = snapshot.anchor_before(selection.start);
 4045
 4046                let is_word_char = text.chars().next().map_or(true, |char| {
 4047                    let classifier = snapshot
 4048                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4049                        .ignore_punctuation(true);
 4050                    classifier.is_word(char)
 4051                });
 4052
 4053                if is_word_char {
 4054                    if let Some(ranges) = self
 4055                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4056                    {
 4057                        for (buffer, edits) in ranges {
 4058                            linked_edits
 4059                                .entry(buffer.clone())
 4060                                .or_default()
 4061                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4062                        }
 4063                    }
 4064                } else {
 4065                    clear_linked_edit_ranges = true;
 4066                }
 4067            }
 4068
 4069            new_selections.push((selection.map(|_| anchor), 0));
 4070            edits.push((selection.start..selection.end, text.clone()));
 4071        }
 4072
 4073        drop(snapshot);
 4074
 4075        self.transact(window, cx, |this, window, cx| {
 4076            if clear_linked_edit_ranges {
 4077                this.linked_edit_ranges.clear();
 4078            }
 4079            let initial_buffer_versions =
 4080                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4081
 4082            this.buffer.update(cx, |buffer, cx| {
 4083                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4084            });
 4085            for (buffer, edits) in linked_edits {
 4086                buffer.update(cx, |buffer, cx| {
 4087                    let snapshot = buffer.snapshot();
 4088                    let edits = edits
 4089                        .into_iter()
 4090                        .map(|(range, text)| {
 4091                            use text::ToPoint as TP;
 4092                            let end_point = TP::to_point(&range.end, &snapshot);
 4093                            let start_point = TP::to_point(&range.start, &snapshot);
 4094                            (start_point..end_point, text)
 4095                        })
 4096                        .sorted_by_key(|(range, _)| range.start);
 4097                    buffer.edit(edits, None, cx);
 4098                })
 4099            }
 4100            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4101            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4102            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4103            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4104                .zip(new_selection_deltas)
 4105                .map(|(selection, delta)| Selection {
 4106                    id: selection.id,
 4107                    start: selection.start + delta,
 4108                    end: selection.end + delta,
 4109                    reversed: selection.reversed,
 4110                    goal: SelectionGoal::None,
 4111                })
 4112                .collect::<Vec<_>>();
 4113
 4114            let mut i = 0;
 4115            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4116                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4117                let start = map.buffer_snapshot.anchor_before(position);
 4118                let end = map.buffer_snapshot.anchor_after(position);
 4119                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4120                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4121                        Ordering::Less => i += 1,
 4122                        Ordering::Greater => break,
 4123                        Ordering::Equal => {
 4124                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4125                                Ordering::Less => i += 1,
 4126                                Ordering::Equal => break,
 4127                                Ordering::Greater => break,
 4128                            }
 4129                        }
 4130                    }
 4131                }
 4132                this.autoclose_regions.insert(
 4133                    i,
 4134                    AutocloseRegion {
 4135                        selection_id,
 4136                        range: start..end,
 4137                        pair,
 4138                    },
 4139                );
 4140            }
 4141
 4142            let had_active_inline_completion = this.has_active_inline_completion();
 4143            this.change_selections(
 4144                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4145                window,
 4146                cx,
 4147                |s| s.select(new_selections),
 4148            );
 4149
 4150            if !bracket_inserted {
 4151                if let Some(on_type_format_task) =
 4152                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4153                {
 4154                    on_type_format_task.detach_and_log_err(cx);
 4155                }
 4156            }
 4157
 4158            let editor_settings = EditorSettings::get_global(cx);
 4159            if bracket_inserted
 4160                && (editor_settings.auto_signature_help
 4161                    || editor_settings.show_signature_help_after_edits)
 4162            {
 4163                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4164            }
 4165
 4166            let trigger_in_words =
 4167                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4168            if this.hard_wrap.is_some() {
 4169                let latest: Range<Point> = this.selections.newest(cx).range();
 4170                if latest.is_empty()
 4171                    && this
 4172                        .buffer()
 4173                        .read(cx)
 4174                        .snapshot(cx)
 4175                        .line_len(MultiBufferRow(latest.start.row))
 4176                        == latest.start.column
 4177                {
 4178                    this.rewrap_impl(
 4179                        RewrapOptions {
 4180                            override_language_settings: true,
 4181                            preserve_existing_whitespace: true,
 4182                        },
 4183                        cx,
 4184                    )
 4185                }
 4186            }
 4187            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4188            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4189            this.refresh_inline_completion(true, false, window, cx);
 4190            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4191        });
 4192    }
 4193
 4194    fn find_possible_emoji_shortcode_at_position(
 4195        snapshot: &MultiBufferSnapshot,
 4196        position: Point,
 4197    ) -> Option<String> {
 4198        let mut chars = Vec::new();
 4199        let mut found_colon = false;
 4200        for char in snapshot.reversed_chars_at(position).take(100) {
 4201            // Found a possible emoji shortcode in the middle of the buffer
 4202            if found_colon {
 4203                if char.is_whitespace() {
 4204                    chars.reverse();
 4205                    return Some(chars.iter().collect());
 4206                }
 4207                // If the previous character is not a whitespace, we are in the middle of a word
 4208                // and we only want to complete the shortcode if the word is made up of other emojis
 4209                let mut containing_word = String::new();
 4210                for ch in snapshot
 4211                    .reversed_chars_at(position)
 4212                    .skip(chars.len() + 1)
 4213                    .take(100)
 4214                {
 4215                    if ch.is_whitespace() {
 4216                        break;
 4217                    }
 4218                    containing_word.push(ch);
 4219                }
 4220                let containing_word = containing_word.chars().rev().collect::<String>();
 4221                if util::word_consists_of_emojis(containing_word.as_str()) {
 4222                    chars.reverse();
 4223                    return Some(chars.iter().collect());
 4224                }
 4225            }
 4226
 4227            if char.is_whitespace() || !char.is_ascii() {
 4228                return None;
 4229            }
 4230            if char == ':' {
 4231                found_colon = true;
 4232            } else {
 4233                chars.push(char);
 4234            }
 4235        }
 4236        // Found a possible emoji shortcode at the beginning of the buffer
 4237        chars.reverse();
 4238        Some(chars.iter().collect())
 4239    }
 4240
 4241    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4242        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4243        self.transact(window, cx, |this, window, cx| {
 4244            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4245                let selections = this.selections.all::<usize>(cx);
 4246                let multi_buffer = this.buffer.read(cx);
 4247                let buffer = multi_buffer.snapshot(cx);
 4248                selections
 4249                    .iter()
 4250                    .map(|selection| {
 4251                        let start_point = selection.start.to_point(&buffer);
 4252                        let mut existing_indent =
 4253                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4254                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4255                        let start = selection.start;
 4256                        let end = selection.end;
 4257                        let selection_is_empty = start == end;
 4258                        let language_scope = buffer.language_scope_at(start);
 4259                        let (
 4260                            comment_delimiter,
 4261                            doc_delimiter,
 4262                            insert_extra_newline,
 4263                            indent_on_newline,
 4264                            indent_on_extra_newline,
 4265                        ) = if let Some(language) = &language_scope {
 4266                            let mut insert_extra_newline =
 4267                                insert_extra_newline_brackets(&buffer, start..end, language)
 4268                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4269
 4270                            // Comment extension on newline is allowed only for cursor selections
 4271                            let comment_delimiter = maybe!({
 4272                                if !selection_is_empty {
 4273                                    return None;
 4274                                }
 4275
 4276                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4277                                    return None;
 4278                                }
 4279
 4280                                let delimiters = language.line_comment_prefixes();
 4281                                let max_len_of_delimiter =
 4282                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4283                                let (snapshot, range) =
 4284                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4285
 4286                                let num_of_whitespaces = snapshot
 4287                                    .chars_for_range(range.clone())
 4288                                    .take_while(|c| c.is_whitespace())
 4289                                    .count();
 4290                                let comment_candidate = snapshot
 4291                                    .chars_for_range(range)
 4292                                    .skip(num_of_whitespaces)
 4293                                    .take(max_len_of_delimiter)
 4294                                    .collect::<String>();
 4295                                let (delimiter, trimmed_len) = delimiters
 4296                                    .iter()
 4297                                    .filter_map(|delimiter| {
 4298                                        let prefix = delimiter.trim_end();
 4299                                        if comment_candidate.starts_with(prefix) {
 4300                                            Some((delimiter, prefix.len()))
 4301                                        } else {
 4302                                            None
 4303                                        }
 4304                                    })
 4305                                    .max_by_key(|(_, len)| *len)?;
 4306
 4307                                let cursor_is_placed_after_comment_marker =
 4308                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4309                                if cursor_is_placed_after_comment_marker {
 4310                                    Some(delimiter.clone())
 4311                                } else {
 4312                                    None
 4313                                }
 4314                            });
 4315
 4316                            let mut indent_on_newline = IndentSize::spaces(0);
 4317                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4318
 4319                            let doc_delimiter = maybe!({
 4320                                if !selection_is_empty {
 4321                                    return None;
 4322                                }
 4323
 4324                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4325                                    return None;
 4326                                }
 4327
 4328                                let DocumentationConfig {
 4329                                    start: start_tag,
 4330                                    end: end_tag,
 4331                                    prefix: delimiter,
 4332                                    tab_size: len,
 4333                                } = language.documentation()?;
 4334
 4335                                let is_within_block_comment = buffer
 4336                                    .language_scope_at(start_point)
 4337                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4338                                if !is_within_block_comment {
 4339                                    return None;
 4340                                }
 4341
 4342                                let (snapshot, range) =
 4343                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4344
 4345                                let num_of_whitespaces = snapshot
 4346                                    .chars_for_range(range.clone())
 4347                                    .take_while(|c| c.is_whitespace())
 4348                                    .count();
 4349
 4350                                // 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.
 4351                                let column = start_point.column;
 4352                                let cursor_is_after_start_tag = {
 4353                                    let start_tag_len = start_tag.len();
 4354                                    let start_tag_line = snapshot
 4355                                        .chars_for_range(range.clone())
 4356                                        .skip(num_of_whitespaces)
 4357                                        .take(start_tag_len)
 4358                                        .collect::<String>();
 4359                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4360                                        num_of_whitespaces + start_tag_len <= column as usize
 4361                                    } else {
 4362                                        false
 4363                                    }
 4364                                };
 4365
 4366                                let cursor_is_after_delimiter = {
 4367                                    let delimiter_trim = delimiter.trim_end();
 4368                                    let delimiter_line = snapshot
 4369                                        .chars_for_range(range.clone())
 4370                                        .skip(num_of_whitespaces)
 4371                                        .take(delimiter_trim.len())
 4372                                        .collect::<String>();
 4373                                    if delimiter_line.starts_with(delimiter_trim) {
 4374                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4375                                    } else {
 4376                                        false
 4377                                    }
 4378                                };
 4379
 4380                                let cursor_is_before_end_tag_if_exists = {
 4381                                    let mut char_position = 0u32;
 4382                                    let mut end_tag_offset = None;
 4383
 4384                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4385                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4386                                            let chars_before_match =
 4387                                                chunk[..byte_pos].chars().count() as u32;
 4388                                            end_tag_offset =
 4389                                                Some(char_position + chars_before_match);
 4390                                            break 'outer;
 4391                                        }
 4392                                        char_position += chunk.chars().count() as u32;
 4393                                    }
 4394
 4395                                    if let Some(end_tag_offset) = end_tag_offset {
 4396                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4397                                        if cursor_is_after_start_tag {
 4398                                            if cursor_is_before_end_tag {
 4399                                                insert_extra_newline = true;
 4400                                            }
 4401                                            let cursor_is_at_start_of_end_tag =
 4402                                                column == end_tag_offset;
 4403                                            if cursor_is_at_start_of_end_tag {
 4404                                                indent_on_extra_newline.len = (*len).into();
 4405                                            }
 4406                                        }
 4407                                        cursor_is_before_end_tag
 4408                                    } else {
 4409                                        true
 4410                                    }
 4411                                };
 4412
 4413                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4414                                    && cursor_is_before_end_tag_if_exists
 4415                                {
 4416                                    if cursor_is_after_start_tag {
 4417                                        indent_on_newline.len = (*len).into();
 4418                                    }
 4419                                    Some(delimiter.clone())
 4420                                } else {
 4421                                    None
 4422                                }
 4423                            });
 4424
 4425                            (
 4426                                comment_delimiter,
 4427                                doc_delimiter,
 4428                                insert_extra_newline,
 4429                                indent_on_newline,
 4430                                indent_on_extra_newline,
 4431                            )
 4432                        } else {
 4433                            (
 4434                                None,
 4435                                None,
 4436                                false,
 4437                                IndentSize::default(),
 4438                                IndentSize::default(),
 4439                            )
 4440                        };
 4441
 4442                        let prevent_auto_indent = doc_delimiter.is_some();
 4443                        let delimiter = comment_delimiter.or(doc_delimiter);
 4444
 4445                        let capacity_for_delimiter =
 4446                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4447                        let mut new_text = String::with_capacity(
 4448                            1 + capacity_for_delimiter
 4449                                + existing_indent.len as usize
 4450                                + indent_on_newline.len as usize
 4451                                + indent_on_extra_newline.len as usize,
 4452                        );
 4453                        new_text.push('\n');
 4454                        new_text.extend(existing_indent.chars());
 4455                        new_text.extend(indent_on_newline.chars());
 4456
 4457                        if let Some(delimiter) = &delimiter {
 4458                            new_text.push_str(delimiter);
 4459                        }
 4460
 4461                        if insert_extra_newline {
 4462                            new_text.push('\n');
 4463                            new_text.extend(existing_indent.chars());
 4464                            new_text.extend(indent_on_extra_newline.chars());
 4465                        }
 4466
 4467                        let anchor = buffer.anchor_after(end);
 4468                        let new_selection = selection.map(|_| anchor);
 4469                        (
 4470                            ((start..end, new_text), prevent_auto_indent),
 4471                            (insert_extra_newline, new_selection),
 4472                        )
 4473                    })
 4474                    .unzip()
 4475            };
 4476
 4477            let mut auto_indent_edits = Vec::new();
 4478            let mut edits = Vec::new();
 4479            for (edit, prevent_auto_indent) in edits_with_flags {
 4480                if prevent_auto_indent {
 4481                    edits.push(edit);
 4482                } else {
 4483                    auto_indent_edits.push(edit);
 4484                }
 4485            }
 4486            if !edits.is_empty() {
 4487                this.edit(edits, cx);
 4488            }
 4489            if !auto_indent_edits.is_empty() {
 4490                this.edit_with_autoindent(auto_indent_edits, cx);
 4491            }
 4492
 4493            let buffer = this.buffer.read(cx).snapshot(cx);
 4494            let new_selections = selection_info
 4495                .into_iter()
 4496                .map(|(extra_newline_inserted, new_selection)| {
 4497                    let mut cursor = new_selection.end.to_point(&buffer);
 4498                    if extra_newline_inserted {
 4499                        cursor.row -= 1;
 4500                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4501                    }
 4502                    new_selection.map(|_| cursor)
 4503                })
 4504                .collect();
 4505
 4506            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4507                s.select(new_selections)
 4508            });
 4509            this.refresh_inline_completion(true, false, window, cx);
 4510        });
 4511    }
 4512
 4513    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4514        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4515
 4516        let buffer = self.buffer.read(cx);
 4517        let snapshot = buffer.snapshot(cx);
 4518
 4519        let mut edits = Vec::new();
 4520        let mut rows = Vec::new();
 4521
 4522        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4523            let cursor = selection.head();
 4524            let row = cursor.row;
 4525
 4526            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4527
 4528            let newline = "\n".to_string();
 4529            edits.push((start_of_line..start_of_line, newline));
 4530
 4531            rows.push(row + rows_inserted as u32);
 4532        }
 4533
 4534        self.transact(window, cx, |editor, window, cx| {
 4535            editor.edit(edits, cx);
 4536
 4537            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4538                let mut index = 0;
 4539                s.move_cursors_with(|map, _, _| {
 4540                    let row = rows[index];
 4541                    index += 1;
 4542
 4543                    let point = Point::new(row, 0);
 4544                    let boundary = map.next_line_boundary(point).1;
 4545                    let clipped = map.clip_point(boundary, Bias::Left);
 4546
 4547                    (clipped, SelectionGoal::None)
 4548                });
 4549            });
 4550
 4551            let mut indent_edits = Vec::new();
 4552            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4553            for row in rows {
 4554                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4555                for (row, indent) in indents {
 4556                    if indent.len == 0 {
 4557                        continue;
 4558                    }
 4559
 4560                    let text = match indent.kind {
 4561                        IndentKind::Space => " ".repeat(indent.len as usize),
 4562                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4563                    };
 4564                    let point = Point::new(row.0, 0);
 4565                    indent_edits.push((point..point, text));
 4566                }
 4567            }
 4568            editor.edit(indent_edits, cx);
 4569        });
 4570    }
 4571
 4572    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4573        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4574
 4575        let buffer = self.buffer.read(cx);
 4576        let snapshot = buffer.snapshot(cx);
 4577
 4578        let mut edits = Vec::new();
 4579        let mut rows = Vec::new();
 4580        let mut rows_inserted = 0;
 4581
 4582        for selection in self.selections.all_adjusted(cx) {
 4583            let cursor = selection.head();
 4584            let row = cursor.row;
 4585
 4586            let point = Point::new(row + 1, 0);
 4587            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4588
 4589            let newline = "\n".to_string();
 4590            edits.push((start_of_line..start_of_line, newline));
 4591
 4592            rows_inserted += 1;
 4593            rows.push(row + rows_inserted);
 4594        }
 4595
 4596        self.transact(window, cx, |editor, window, cx| {
 4597            editor.edit(edits, cx);
 4598
 4599            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4600                let mut index = 0;
 4601                s.move_cursors_with(|map, _, _| {
 4602                    let row = rows[index];
 4603                    index += 1;
 4604
 4605                    let point = Point::new(row, 0);
 4606                    let boundary = map.next_line_boundary(point).1;
 4607                    let clipped = map.clip_point(boundary, Bias::Left);
 4608
 4609                    (clipped, SelectionGoal::None)
 4610                });
 4611            });
 4612
 4613            let mut indent_edits = Vec::new();
 4614            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4615            for row in rows {
 4616                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4617                for (row, indent) in indents {
 4618                    if indent.len == 0 {
 4619                        continue;
 4620                    }
 4621
 4622                    let text = match indent.kind {
 4623                        IndentKind::Space => " ".repeat(indent.len as usize),
 4624                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4625                    };
 4626                    let point = Point::new(row.0, 0);
 4627                    indent_edits.push((point..point, text));
 4628                }
 4629            }
 4630            editor.edit(indent_edits, cx);
 4631        });
 4632    }
 4633
 4634    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4635        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4636            original_indent_columns: Vec::new(),
 4637        });
 4638        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4639    }
 4640
 4641    fn insert_with_autoindent_mode(
 4642        &mut self,
 4643        text: &str,
 4644        autoindent_mode: Option<AutoindentMode>,
 4645        window: &mut Window,
 4646        cx: &mut Context<Self>,
 4647    ) {
 4648        if self.read_only(cx) {
 4649            return;
 4650        }
 4651
 4652        let text: Arc<str> = text.into();
 4653        self.transact(window, cx, |this, window, cx| {
 4654            let old_selections = this.selections.all_adjusted(cx);
 4655            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4656                let anchors = {
 4657                    let snapshot = buffer.read(cx);
 4658                    old_selections
 4659                        .iter()
 4660                        .map(|s| {
 4661                            let anchor = snapshot.anchor_after(s.head());
 4662                            s.map(|_| anchor)
 4663                        })
 4664                        .collect::<Vec<_>>()
 4665                };
 4666                buffer.edit(
 4667                    old_selections
 4668                        .iter()
 4669                        .map(|s| (s.start..s.end, text.clone())),
 4670                    autoindent_mode,
 4671                    cx,
 4672                );
 4673                anchors
 4674            });
 4675
 4676            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4677                s.select_anchors(selection_anchors);
 4678            });
 4679
 4680            cx.notify();
 4681        });
 4682    }
 4683
 4684    fn trigger_completion_on_input(
 4685        &mut self,
 4686        text: &str,
 4687        trigger_in_words: bool,
 4688        window: &mut Window,
 4689        cx: &mut Context<Self>,
 4690    ) {
 4691        let completions_source = self
 4692            .context_menu
 4693            .borrow()
 4694            .as_ref()
 4695            .and_then(|menu| match menu {
 4696                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4697                CodeContextMenu::CodeActions(_) => None,
 4698            });
 4699
 4700        match completions_source {
 4701            Some(CompletionsMenuSource::Words) => {
 4702                self.show_word_completions(&ShowWordCompletions, window, cx)
 4703            }
 4704            Some(CompletionsMenuSource::Normal)
 4705            | Some(CompletionsMenuSource::SnippetChoices)
 4706            | None
 4707                if self.is_completion_trigger(
 4708                    text,
 4709                    trigger_in_words,
 4710                    completions_source.is_some(),
 4711                    cx,
 4712                ) =>
 4713            {
 4714                self.show_completions(
 4715                    &ShowCompletions {
 4716                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4717                    },
 4718                    window,
 4719                    cx,
 4720                )
 4721            }
 4722            _ => {
 4723                self.hide_context_menu(window, cx);
 4724            }
 4725        }
 4726    }
 4727
 4728    fn is_completion_trigger(
 4729        &self,
 4730        text: &str,
 4731        trigger_in_words: bool,
 4732        menu_is_open: bool,
 4733        cx: &mut Context<Self>,
 4734    ) -> bool {
 4735        let position = self.selections.newest_anchor().head();
 4736        let multibuffer = self.buffer.read(cx);
 4737        let Some(buffer) = position
 4738            .buffer_id
 4739            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4740        else {
 4741            return false;
 4742        };
 4743
 4744        if let Some(completion_provider) = &self.completion_provider {
 4745            completion_provider.is_completion_trigger(
 4746                &buffer,
 4747                position.text_anchor,
 4748                text,
 4749                trigger_in_words,
 4750                menu_is_open,
 4751                cx,
 4752            )
 4753        } else {
 4754            false
 4755        }
 4756    }
 4757
 4758    /// If any empty selections is touching the start of its innermost containing autoclose
 4759    /// region, expand it to select the brackets.
 4760    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4761        let selections = self.selections.all::<usize>(cx);
 4762        let buffer = self.buffer.read(cx).read(cx);
 4763        let new_selections = self
 4764            .selections_with_autoclose_regions(selections, &buffer)
 4765            .map(|(mut selection, region)| {
 4766                if !selection.is_empty() {
 4767                    return selection;
 4768                }
 4769
 4770                if let Some(region) = region {
 4771                    let mut range = region.range.to_offset(&buffer);
 4772                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4773                        range.start -= region.pair.start.len();
 4774                        if buffer.contains_str_at(range.start, &region.pair.start)
 4775                            && buffer.contains_str_at(range.end, &region.pair.end)
 4776                        {
 4777                            range.end += region.pair.end.len();
 4778                            selection.start = range.start;
 4779                            selection.end = range.end;
 4780
 4781                            return selection;
 4782                        }
 4783                    }
 4784                }
 4785
 4786                let always_treat_brackets_as_autoclosed = buffer
 4787                    .language_settings_at(selection.start, cx)
 4788                    .always_treat_brackets_as_autoclosed;
 4789
 4790                if !always_treat_brackets_as_autoclosed {
 4791                    return selection;
 4792                }
 4793
 4794                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4795                    for (pair, enabled) in scope.brackets() {
 4796                        if !enabled || !pair.close {
 4797                            continue;
 4798                        }
 4799
 4800                        if buffer.contains_str_at(selection.start, &pair.end) {
 4801                            let pair_start_len = pair.start.len();
 4802                            if buffer.contains_str_at(
 4803                                selection.start.saturating_sub(pair_start_len),
 4804                                &pair.start,
 4805                            ) {
 4806                                selection.start -= pair_start_len;
 4807                                selection.end += pair.end.len();
 4808
 4809                                return selection;
 4810                            }
 4811                        }
 4812                    }
 4813                }
 4814
 4815                selection
 4816            })
 4817            .collect();
 4818
 4819        drop(buffer);
 4820        self.change_selections(None, window, cx, |selections| {
 4821            selections.select(new_selections)
 4822        });
 4823    }
 4824
 4825    /// Iterate the given selections, and for each one, find the smallest surrounding
 4826    /// autoclose region. This uses the ordering of the selections and the autoclose
 4827    /// regions to avoid repeated comparisons.
 4828    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4829        &'a self,
 4830        selections: impl IntoIterator<Item = Selection<D>>,
 4831        buffer: &'a MultiBufferSnapshot,
 4832    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4833        let mut i = 0;
 4834        let mut regions = self.autoclose_regions.as_slice();
 4835        selections.into_iter().map(move |selection| {
 4836            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4837
 4838            let mut enclosing = None;
 4839            while let Some(pair_state) = regions.get(i) {
 4840                if pair_state.range.end.to_offset(buffer) < range.start {
 4841                    regions = &regions[i + 1..];
 4842                    i = 0;
 4843                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4844                    break;
 4845                } else {
 4846                    if pair_state.selection_id == selection.id {
 4847                        enclosing = Some(pair_state);
 4848                    }
 4849                    i += 1;
 4850                }
 4851            }
 4852
 4853            (selection, enclosing)
 4854        })
 4855    }
 4856
 4857    /// Remove any autoclose regions that no longer contain their selection.
 4858    fn invalidate_autoclose_regions(
 4859        &mut self,
 4860        mut selections: &[Selection<Anchor>],
 4861        buffer: &MultiBufferSnapshot,
 4862    ) {
 4863        self.autoclose_regions.retain(|state| {
 4864            let mut i = 0;
 4865            while let Some(selection) = selections.get(i) {
 4866                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4867                    selections = &selections[1..];
 4868                    continue;
 4869                }
 4870                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4871                    break;
 4872                }
 4873                if selection.id == state.selection_id {
 4874                    return true;
 4875                } else {
 4876                    i += 1;
 4877                }
 4878            }
 4879            false
 4880        });
 4881    }
 4882
 4883    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4884        let offset = position.to_offset(buffer);
 4885        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4886        if offset > word_range.start && kind == Some(CharKind::Word) {
 4887            Some(
 4888                buffer
 4889                    .text_for_range(word_range.start..offset)
 4890                    .collect::<String>(),
 4891            )
 4892        } else {
 4893            None
 4894        }
 4895    }
 4896
 4897    pub fn toggle_inline_values(
 4898        &mut self,
 4899        _: &ToggleInlineValues,
 4900        _: &mut Window,
 4901        cx: &mut Context<Self>,
 4902    ) {
 4903        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4904
 4905        self.refresh_inline_values(cx);
 4906    }
 4907
 4908    pub fn toggle_inlay_hints(
 4909        &mut self,
 4910        _: &ToggleInlayHints,
 4911        _: &mut Window,
 4912        cx: &mut Context<Self>,
 4913    ) {
 4914        self.refresh_inlay_hints(
 4915            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4916            cx,
 4917        );
 4918    }
 4919
 4920    pub fn inlay_hints_enabled(&self) -> bool {
 4921        self.inlay_hint_cache.enabled
 4922    }
 4923
 4924    pub fn inline_values_enabled(&self) -> bool {
 4925        self.inline_value_cache.enabled
 4926    }
 4927
 4928    #[cfg(any(test, feature = "test-support"))]
 4929    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4930        self.display_map
 4931            .read(cx)
 4932            .current_inlays()
 4933            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4934            .cloned()
 4935            .collect()
 4936    }
 4937
 4938    #[cfg(any(test, feature = "test-support"))]
 4939    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 4940        self.display_map
 4941            .read(cx)
 4942            .current_inlays()
 4943            .cloned()
 4944            .collect()
 4945    }
 4946
 4947    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4948        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4949            return;
 4950        }
 4951
 4952        let reason_description = reason.description();
 4953        let ignore_debounce = matches!(
 4954            reason,
 4955            InlayHintRefreshReason::SettingsChange(_)
 4956                | InlayHintRefreshReason::Toggle(_)
 4957                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4958                | InlayHintRefreshReason::ModifiersChanged(_)
 4959        );
 4960        let (invalidate_cache, required_languages) = match reason {
 4961            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4962                match self.inlay_hint_cache.modifiers_override(enabled) {
 4963                    Some(enabled) => {
 4964                        if enabled {
 4965                            (InvalidationStrategy::RefreshRequested, None)
 4966                        } else {
 4967                            self.splice_inlays(
 4968                                &self
 4969                                    .visible_inlay_hints(cx)
 4970                                    .iter()
 4971                                    .map(|inlay| inlay.id)
 4972                                    .collect::<Vec<InlayId>>(),
 4973                                Vec::new(),
 4974                                cx,
 4975                            );
 4976                            return;
 4977                        }
 4978                    }
 4979                    None => return,
 4980                }
 4981            }
 4982            InlayHintRefreshReason::Toggle(enabled) => {
 4983                if self.inlay_hint_cache.toggle(enabled) {
 4984                    if enabled {
 4985                        (InvalidationStrategy::RefreshRequested, None)
 4986                    } else {
 4987                        self.splice_inlays(
 4988                            &self
 4989                                .visible_inlay_hints(cx)
 4990                                .iter()
 4991                                .map(|inlay| inlay.id)
 4992                                .collect::<Vec<InlayId>>(),
 4993                            Vec::new(),
 4994                            cx,
 4995                        );
 4996                        return;
 4997                    }
 4998                } else {
 4999                    return;
 5000                }
 5001            }
 5002            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5003                match self.inlay_hint_cache.update_settings(
 5004                    &self.buffer,
 5005                    new_settings,
 5006                    self.visible_inlay_hints(cx),
 5007                    cx,
 5008                ) {
 5009                    ControlFlow::Break(Some(InlaySplice {
 5010                        to_remove,
 5011                        to_insert,
 5012                    })) => {
 5013                        self.splice_inlays(&to_remove, to_insert, cx);
 5014                        return;
 5015                    }
 5016                    ControlFlow::Break(None) => return,
 5017                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5018                }
 5019            }
 5020            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5021                if let Some(InlaySplice {
 5022                    to_remove,
 5023                    to_insert,
 5024                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5025                {
 5026                    self.splice_inlays(&to_remove, to_insert, cx);
 5027                }
 5028                self.display_map.update(cx, |display_map, _| {
 5029                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5030                });
 5031                return;
 5032            }
 5033            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5034            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5035                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5036            }
 5037            InlayHintRefreshReason::RefreshRequested => {
 5038                (InvalidationStrategy::RefreshRequested, None)
 5039            }
 5040        };
 5041
 5042        if let Some(InlaySplice {
 5043            to_remove,
 5044            to_insert,
 5045        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5046            reason_description,
 5047            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 5048            invalidate_cache,
 5049            ignore_debounce,
 5050            cx,
 5051        ) {
 5052            self.splice_inlays(&to_remove, to_insert, cx);
 5053        }
 5054    }
 5055
 5056    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5057        self.display_map
 5058            .read(cx)
 5059            .current_inlays()
 5060            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5061            .cloned()
 5062            .collect()
 5063    }
 5064
 5065    pub fn excerpts_for_inlay_hints_query(
 5066        &self,
 5067        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5068        cx: &mut Context<Editor>,
 5069    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5070        let Some(project) = self.project.as_ref() else {
 5071            return HashMap::default();
 5072        };
 5073        let project = project.read(cx);
 5074        let multi_buffer = self.buffer().read(cx);
 5075        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5076        let multi_buffer_visible_start = self
 5077            .scroll_manager
 5078            .anchor()
 5079            .anchor
 5080            .to_point(&multi_buffer_snapshot);
 5081        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5082            multi_buffer_visible_start
 5083                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5084            Bias::Left,
 5085        );
 5086        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5087        multi_buffer_snapshot
 5088            .range_to_buffer_ranges(multi_buffer_visible_range)
 5089            .into_iter()
 5090            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5091            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5092                let buffer_file = project::File::from_dyn(buffer.file())?;
 5093                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5094                let worktree_entry = buffer_worktree
 5095                    .read(cx)
 5096                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5097                if worktree_entry.is_ignored {
 5098                    return None;
 5099                }
 5100
 5101                let language = buffer.language()?;
 5102                if let Some(restrict_to_languages) = restrict_to_languages {
 5103                    if !restrict_to_languages.contains(language) {
 5104                        return None;
 5105                    }
 5106                }
 5107                Some((
 5108                    excerpt_id,
 5109                    (
 5110                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5111                        buffer.version().clone(),
 5112                        excerpt_visible_range,
 5113                    ),
 5114                ))
 5115            })
 5116            .collect()
 5117    }
 5118
 5119    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5120        TextLayoutDetails {
 5121            text_system: window.text_system().clone(),
 5122            editor_style: self.style.clone().unwrap(),
 5123            rem_size: window.rem_size(),
 5124            scroll_anchor: self.scroll_manager.anchor(),
 5125            visible_rows: self.visible_line_count(),
 5126            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5127        }
 5128    }
 5129
 5130    pub fn splice_inlays(
 5131        &self,
 5132        to_remove: &[InlayId],
 5133        to_insert: Vec<Inlay>,
 5134        cx: &mut Context<Self>,
 5135    ) {
 5136        self.display_map.update(cx, |display_map, cx| {
 5137            display_map.splice_inlays(to_remove, to_insert, cx)
 5138        });
 5139        cx.notify();
 5140    }
 5141
 5142    fn trigger_on_type_formatting(
 5143        &self,
 5144        input: String,
 5145        window: &mut Window,
 5146        cx: &mut Context<Self>,
 5147    ) -> Option<Task<Result<()>>> {
 5148        if input.len() != 1 {
 5149            return None;
 5150        }
 5151
 5152        let project = self.project.as_ref()?;
 5153        let position = self.selections.newest_anchor().head();
 5154        let (buffer, buffer_position) = self
 5155            .buffer
 5156            .read(cx)
 5157            .text_anchor_for_position(position, cx)?;
 5158
 5159        let settings = language_settings::language_settings(
 5160            buffer
 5161                .read(cx)
 5162                .language_at(buffer_position)
 5163                .map(|l| l.name()),
 5164            buffer.read(cx).file(),
 5165            cx,
 5166        );
 5167        if !settings.use_on_type_format {
 5168            return None;
 5169        }
 5170
 5171        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5172        // hence we do LSP request & edit on host side only — add formats to host's history.
 5173        let push_to_lsp_host_history = true;
 5174        // If this is not the host, append its history with new edits.
 5175        let push_to_client_history = project.read(cx).is_via_collab();
 5176
 5177        let on_type_formatting = project.update(cx, |project, cx| {
 5178            project.on_type_format(
 5179                buffer.clone(),
 5180                buffer_position,
 5181                input,
 5182                push_to_lsp_host_history,
 5183                cx,
 5184            )
 5185        });
 5186        Some(cx.spawn_in(window, async move |editor, cx| {
 5187            if let Some(transaction) = on_type_formatting.await? {
 5188                if push_to_client_history {
 5189                    buffer
 5190                        .update(cx, |buffer, _| {
 5191                            buffer.push_transaction(transaction, Instant::now());
 5192                            buffer.finalize_last_transaction();
 5193                        })
 5194                        .ok();
 5195                }
 5196                editor.update(cx, |editor, cx| {
 5197                    editor.refresh_document_highlights(cx);
 5198                })?;
 5199            }
 5200            Ok(())
 5201        }))
 5202    }
 5203
 5204    pub fn show_word_completions(
 5205        &mut self,
 5206        _: &ShowWordCompletions,
 5207        window: &mut Window,
 5208        cx: &mut Context<Self>,
 5209    ) {
 5210        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5211    }
 5212
 5213    pub fn show_completions(
 5214        &mut self,
 5215        options: &ShowCompletions,
 5216        window: &mut Window,
 5217        cx: &mut Context<Self>,
 5218    ) {
 5219        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5220    }
 5221
 5222    fn open_or_update_completions_menu(
 5223        &mut self,
 5224        requested_source: Option<CompletionsMenuSource>,
 5225        trigger: Option<&str>,
 5226        window: &mut Window,
 5227        cx: &mut Context<Self>,
 5228    ) {
 5229        if self.pending_rename.is_some() {
 5230            return;
 5231        }
 5232
 5233        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5234
 5235        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5236        // inserted and selected. To handle that case, the start of the selection is used so that
 5237        // the menu starts with all choices.
 5238        let position = self
 5239            .selections
 5240            .newest_anchor()
 5241            .start
 5242            .bias_right(&multibuffer_snapshot);
 5243        if position.diff_base_anchor.is_some() {
 5244            return;
 5245        }
 5246        let (buffer, buffer_position) =
 5247            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5248                output
 5249            } else {
 5250                return;
 5251            };
 5252        let buffer_snapshot = buffer.read(cx).snapshot();
 5253
 5254        let query: Option<Arc<String>> =
 5255            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5256
 5257        drop(multibuffer_snapshot);
 5258
 5259        let provider = match requested_source {
 5260            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5261            Some(CompletionsMenuSource::Words) => None,
 5262            Some(CompletionsMenuSource::SnippetChoices) => {
 5263                log::error!("bug: SnippetChoices requested_source is not handled");
 5264                None
 5265            }
 5266        };
 5267
 5268        let sort_completions = provider
 5269            .as_ref()
 5270            .map_or(false, |provider| provider.sort_completions());
 5271
 5272        let filter_completions = provider
 5273            .as_ref()
 5274            .map_or(true, |provider| provider.filter_completions());
 5275
 5276        let trigger_kind = match trigger {
 5277            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5278                CompletionTriggerKind::TRIGGER_CHARACTER
 5279            }
 5280            _ => CompletionTriggerKind::INVOKED,
 5281        };
 5282        let completion_context = CompletionContext {
 5283            trigger_character: trigger.and_then(|trigger| {
 5284                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5285                    Some(String::from(trigger))
 5286                } else {
 5287                    None
 5288                }
 5289            }),
 5290            trigger_kind,
 5291        };
 5292
 5293        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5294        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5295        // involve trigger chars, so this is skipped in that case.
 5296        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5297        {
 5298            let menu_is_open = matches!(
 5299                self.context_menu.borrow().as_ref(),
 5300                Some(CodeContextMenu::Completions(_))
 5301            );
 5302            if menu_is_open {
 5303                self.hide_context_menu(window, cx);
 5304            }
 5305        }
 5306
 5307        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5308            if filter_completions {
 5309                menu.filter(query.clone(), provider.clone(), window, cx);
 5310            }
 5311            // When `is_incomplete` is false, no need to re-query completions when the current query
 5312            // is a suffix of the initial query.
 5313            if !menu.is_incomplete {
 5314                // If the new query is a suffix of the old query (typing more characters) and
 5315                // the previous result was complete, the existing completions can be filtered.
 5316                //
 5317                // Note that this is always true for snippet completions.
 5318                let query_matches = match (&menu.initial_query, &query) {
 5319                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5320                    (None, _) => true,
 5321                    _ => false,
 5322                };
 5323                if query_matches {
 5324                    let position_matches = if menu.initial_position == position {
 5325                        true
 5326                    } else {
 5327                        let snapshot = self.buffer.read(cx).read(cx);
 5328                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5329                    };
 5330                    if position_matches {
 5331                        return;
 5332                    }
 5333                }
 5334            }
 5335        };
 5336
 5337        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5338            buffer_snapshot.surrounding_word(buffer_position)
 5339        {
 5340            let word_to_exclude = buffer_snapshot
 5341                .text_for_range(word_range.clone())
 5342                .collect::<String>();
 5343            (
 5344                buffer_snapshot.anchor_before(word_range.start)
 5345                    ..buffer_snapshot.anchor_after(buffer_position),
 5346                Some(word_to_exclude),
 5347            )
 5348        } else {
 5349            (buffer_position..buffer_position, None)
 5350        };
 5351
 5352        let language = buffer_snapshot
 5353            .language_at(buffer_position)
 5354            .map(|language| language.name());
 5355
 5356        let completion_settings =
 5357            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5358
 5359        let show_completion_documentation = buffer_snapshot
 5360            .settings_at(buffer_position, cx)
 5361            .show_completion_documentation;
 5362
 5363        // The document can be large, so stay in reasonable bounds when searching for words,
 5364        // otherwise completion pop-up might be slow to appear.
 5365        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5366        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5367        let min_word_search = buffer_snapshot.clip_point(
 5368            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5369            Bias::Left,
 5370        );
 5371        let max_word_search = buffer_snapshot.clip_point(
 5372            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5373            Bias::Right,
 5374        );
 5375        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5376            ..buffer_snapshot.point_to_offset(max_word_search);
 5377
 5378        let skip_digits = query
 5379            .as_ref()
 5380            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5381
 5382        let (mut words, provider_responses) = match &provider {
 5383            Some(provider) => {
 5384                let provider_responses = provider.completions(
 5385                    position.excerpt_id,
 5386                    &buffer,
 5387                    buffer_position,
 5388                    completion_context,
 5389                    window,
 5390                    cx,
 5391                );
 5392
 5393                let words = match completion_settings.words {
 5394                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5395                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5396                        .background_spawn(async move {
 5397                            buffer_snapshot.words_in_range(WordsQuery {
 5398                                fuzzy_contents: None,
 5399                                range: word_search_range,
 5400                                skip_digits,
 5401                            })
 5402                        }),
 5403                };
 5404
 5405                (words, provider_responses)
 5406            }
 5407            None => (
 5408                cx.background_spawn(async move {
 5409                    buffer_snapshot.words_in_range(WordsQuery {
 5410                        fuzzy_contents: None,
 5411                        range: word_search_range,
 5412                        skip_digits,
 5413                    })
 5414                }),
 5415                Task::ready(Ok(Vec::new())),
 5416            ),
 5417        };
 5418
 5419        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5420
 5421        let id = post_inc(&mut self.next_completion_id);
 5422        let task = cx.spawn_in(window, async move |editor, cx| {
 5423            let Ok(()) = editor.update(cx, |this, _| {
 5424                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5425            }) else {
 5426                return;
 5427            };
 5428
 5429            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5430            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5431            let mut completions = Vec::new();
 5432            let mut is_incomplete = false;
 5433            if let Some(provider_responses) = provider_responses.await.log_err() {
 5434                if !provider_responses.is_empty() {
 5435                    for response in provider_responses {
 5436                        completions.extend(response.completions);
 5437                        is_incomplete = is_incomplete || response.is_incomplete;
 5438                    }
 5439                    if completion_settings.words == WordsCompletionMode::Fallback {
 5440                        words = Task::ready(BTreeMap::default());
 5441                    }
 5442                }
 5443            }
 5444
 5445            let mut words = words.await;
 5446            if let Some(word_to_exclude) = &word_to_exclude {
 5447                words.remove(word_to_exclude);
 5448            }
 5449            for lsp_completion in &completions {
 5450                words.remove(&lsp_completion.new_text);
 5451            }
 5452            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5453                replace_range: word_replace_range.clone(),
 5454                new_text: word.clone(),
 5455                label: CodeLabel::plain(word, None),
 5456                icon_path: None,
 5457                documentation: None,
 5458                source: CompletionSource::BufferWord {
 5459                    word_range,
 5460                    resolved: false,
 5461                },
 5462                insert_text_mode: Some(InsertTextMode::AS_IS),
 5463                confirm: None,
 5464            }));
 5465
 5466            let menu = if completions.is_empty() {
 5467                None
 5468            } else {
 5469                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5470                    let languages = editor
 5471                        .workspace
 5472                        .as_ref()
 5473                        .and_then(|(workspace, _)| workspace.upgrade())
 5474                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5475                    let menu = CompletionsMenu::new(
 5476                        id,
 5477                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5478                        sort_completions,
 5479                        show_completion_documentation,
 5480                        position,
 5481                        query.clone(),
 5482                        is_incomplete,
 5483                        buffer.clone(),
 5484                        completions.into(),
 5485                        snippet_sort_order,
 5486                        languages,
 5487                        language,
 5488                        cx,
 5489                    );
 5490
 5491                    let query = if filter_completions { query } else { None };
 5492                    let matches_task = if let Some(query) = query {
 5493                        menu.do_async_filtering(query, cx)
 5494                    } else {
 5495                        Task::ready(menu.unfiltered_matches())
 5496                    };
 5497                    (menu, matches_task)
 5498                }) else {
 5499                    return;
 5500                };
 5501
 5502                let matches = matches_task.await;
 5503
 5504                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5505                    // Newer menu already set, so exit.
 5506                    match editor.context_menu.borrow().as_ref() {
 5507                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5508                            if prev_menu.id > id {
 5509                                return;
 5510                            }
 5511                        }
 5512                        _ => {}
 5513                    };
 5514
 5515                    // Only valid to take prev_menu because it the new menu is immediately set
 5516                    // below, or the menu is hidden.
 5517                    match editor.context_menu.borrow_mut().take() {
 5518                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5519                            let position_matches =
 5520                                if prev_menu.initial_position == menu.initial_position {
 5521                                    true
 5522                                } else {
 5523                                    let snapshot = editor.buffer.read(cx).read(cx);
 5524                                    prev_menu.initial_position.to_offset(&snapshot)
 5525                                        == menu.initial_position.to_offset(&snapshot)
 5526                                };
 5527                            if position_matches {
 5528                                // Preserve markdown cache before `set_filter_results` because it will
 5529                                // try to populate the documentation cache.
 5530                                menu.preserve_markdown_cache(prev_menu);
 5531                            }
 5532                        }
 5533                        _ => {}
 5534                    };
 5535
 5536                    menu.set_filter_results(matches, provider, window, cx);
 5537                }) else {
 5538                    return;
 5539                };
 5540
 5541                menu.visible().then_some(menu)
 5542            };
 5543
 5544            editor
 5545                .update_in(cx, |editor, window, cx| {
 5546                    if editor.focus_handle.is_focused(window) {
 5547                        if let Some(menu) = menu {
 5548                            *editor.context_menu.borrow_mut() =
 5549                                Some(CodeContextMenu::Completions(menu));
 5550
 5551                            crate::hover_popover::hide_hover(editor, cx);
 5552                            if editor.show_edit_predictions_in_menu() {
 5553                                editor.update_visible_inline_completion(window, cx);
 5554                            } else {
 5555                                editor.discard_inline_completion(false, cx);
 5556                            }
 5557
 5558                            cx.notify();
 5559                            return;
 5560                        }
 5561                    }
 5562
 5563                    if editor.completion_tasks.len() <= 1 {
 5564                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5565                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5566                        // If it was already hidden and we don't show inline completions in the menu, we should
 5567                        // also show the inline-completion when available.
 5568                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5569                            editor.update_visible_inline_completion(window, cx);
 5570                        }
 5571                    }
 5572                })
 5573                .ok();
 5574        });
 5575
 5576        self.completion_tasks.push((id, task));
 5577    }
 5578
 5579    #[cfg(feature = "test-support")]
 5580    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5581        let menu = self.context_menu.borrow();
 5582        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5583            let completions = menu.completions.borrow();
 5584            Some(completions.to_vec())
 5585        } else {
 5586            None
 5587        }
 5588    }
 5589
 5590    pub fn with_completions_menu_matching_id<R>(
 5591        &self,
 5592        id: CompletionId,
 5593        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5594    ) -> R {
 5595        let mut context_menu = self.context_menu.borrow_mut();
 5596        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5597            return f(None);
 5598        };
 5599        if completions_menu.id != id {
 5600            return f(None);
 5601        }
 5602        f(Some(completions_menu))
 5603    }
 5604
 5605    pub fn confirm_completion(
 5606        &mut self,
 5607        action: &ConfirmCompletion,
 5608        window: &mut Window,
 5609        cx: &mut Context<Self>,
 5610    ) -> Option<Task<Result<()>>> {
 5611        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5612        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5613    }
 5614
 5615    pub fn confirm_completion_insert(
 5616        &mut self,
 5617        _: &ConfirmCompletionInsert,
 5618        window: &mut Window,
 5619        cx: &mut Context<Self>,
 5620    ) -> Option<Task<Result<()>>> {
 5621        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5622        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5623    }
 5624
 5625    pub fn confirm_completion_replace(
 5626        &mut self,
 5627        _: &ConfirmCompletionReplace,
 5628        window: &mut Window,
 5629        cx: &mut Context<Self>,
 5630    ) -> Option<Task<Result<()>>> {
 5631        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5632        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5633    }
 5634
 5635    pub fn compose_completion(
 5636        &mut self,
 5637        action: &ComposeCompletion,
 5638        window: &mut Window,
 5639        cx: &mut Context<Self>,
 5640    ) -> Option<Task<Result<()>>> {
 5641        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5642        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5643    }
 5644
 5645    fn do_completion(
 5646        &mut self,
 5647        item_ix: Option<usize>,
 5648        intent: CompletionIntent,
 5649        window: &mut Window,
 5650        cx: &mut Context<Editor>,
 5651    ) -> Option<Task<Result<()>>> {
 5652        use language::ToOffset as _;
 5653
 5654        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5655        else {
 5656            return None;
 5657        };
 5658
 5659        let candidate_id = {
 5660            let entries = completions_menu.entries.borrow();
 5661            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5662            if self.show_edit_predictions_in_menu() {
 5663                self.discard_inline_completion(true, cx);
 5664            }
 5665            mat.candidate_id
 5666        };
 5667
 5668        let completion = completions_menu
 5669            .completions
 5670            .borrow()
 5671            .get(candidate_id)?
 5672            .clone();
 5673        cx.stop_propagation();
 5674
 5675        let buffer_handle = completions_menu.buffer.clone();
 5676
 5677        let CompletionEdit {
 5678            new_text,
 5679            snippet,
 5680            replace_range,
 5681        } = process_completion_for_edit(
 5682            &completion,
 5683            intent,
 5684            &buffer_handle,
 5685            &completions_menu.initial_position.text_anchor,
 5686            cx,
 5687        );
 5688
 5689        let buffer = buffer_handle.read(cx);
 5690        let snapshot = self.buffer.read(cx).snapshot(cx);
 5691        let newest_anchor = self.selections.newest_anchor();
 5692        let replace_range_multibuffer = {
 5693            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5694            let multibuffer_anchor = snapshot
 5695                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5696                .unwrap()
 5697                ..snapshot
 5698                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5699                    .unwrap();
 5700            multibuffer_anchor.start.to_offset(&snapshot)
 5701                ..multibuffer_anchor.end.to_offset(&snapshot)
 5702        };
 5703        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5704            return None;
 5705        }
 5706
 5707        let old_text = buffer
 5708            .text_for_range(replace_range.clone())
 5709            .collect::<String>();
 5710        let lookbehind = newest_anchor
 5711            .start
 5712            .text_anchor
 5713            .to_offset(buffer)
 5714            .saturating_sub(replace_range.start);
 5715        let lookahead = replace_range
 5716            .end
 5717            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5718        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5719        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5720
 5721        let selections = self.selections.all::<usize>(cx);
 5722        let mut ranges = Vec::new();
 5723        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5724
 5725        for selection in &selections {
 5726            let range = if selection.id == newest_anchor.id {
 5727                replace_range_multibuffer.clone()
 5728            } else {
 5729                let mut range = selection.range();
 5730
 5731                // if prefix is present, don't duplicate it
 5732                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5733                    range.start = range.start.saturating_sub(lookbehind);
 5734
 5735                    // if suffix is also present, mimic the newest cursor and replace it
 5736                    if selection.id != newest_anchor.id
 5737                        && snapshot.contains_str_at(range.end, suffix)
 5738                    {
 5739                        range.end += lookahead;
 5740                    }
 5741                }
 5742                range
 5743            };
 5744
 5745            ranges.push(range.clone());
 5746
 5747            if !self.linked_edit_ranges.is_empty() {
 5748                let start_anchor = snapshot.anchor_before(range.start);
 5749                let end_anchor = snapshot.anchor_after(range.end);
 5750                if let Some(ranges) = self
 5751                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5752                {
 5753                    for (buffer, edits) in ranges {
 5754                        linked_edits
 5755                            .entry(buffer.clone())
 5756                            .or_default()
 5757                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5758                    }
 5759                }
 5760            }
 5761        }
 5762
 5763        let common_prefix_len = old_text
 5764            .chars()
 5765            .zip(new_text.chars())
 5766            .take_while(|(a, b)| a == b)
 5767            .map(|(a, _)| a.len_utf8())
 5768            .sum::<usize>();
 5769
 5770        cx.emit(EditorEvent::InputHandled {
 5771            utf16_range_to_replace: None,
 5772            text: new_text[common_prefix_len..].into(),
 5773        });
 5774
 5775        self.transact(window, cx, |this, window, cx| {
 5776            if let Some(mut snippet) = snippet {
 5777                snippet.text = new_text.to_string();
 5778                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5779            } else {
 5780                this.buffer.update(cx, |buffer, cx| {
 5781                    let auto_indent = match completion.insert_text_mode {
 5782                        Some(InsertTextMode::AS_IS) => None,
 5783                        _ => this.autoindent_mode.clone(),
 5784                    };
 5785                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5786                    buffer.edit(edits, auto_indent, cx);
 5787                });
 5788            }
 5789            for (buffer, edits) in linked_edits {
 5790                buffer.update(cx, |buffer, cx| {
 5791                    let snapshot = buffer.snapshot();
 5792                    let edits = edits
 5793                        .into_iter()
 5794                        .map(|(range, text)| {
 5795                            use text::ToPoint as TP;
 5796                            let end_point = TP::to_point(&range.end, &snapshot);
 5797                            let start_point = TP::to_point(&range.start, &snapshot);
 5798                            (start_point..end_point, text)
 5799                        })
 5800                        .sorted_by_key(|(range, _)| range.start);
 5801                    buffer.edit(edits, None, cx);
 5802                })
 5803            }
 5804
 5805            this.refresh_inline_completion(true, false, window, cx);
 5806        });
 5807
 5808        let show_new_completions_on_confirm = completion
 5809            .confirm
 5810            .as_ref()
 5811            .map_or(false, |confirm| confirm(intent, window, cx));
 5812        if show_new_completions_on_confirm {
 5813            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5814        }
 5815
 5816        let provider = self.completion_provider.as_ref()?;
 5817        drop(completion);
 5818        let apply_edits = provider.apply_additional_edits_for_completion(
 5819            buffer_handle,
 5820            completions_menu.completions.clone(),
 5821            candidate_id,
 5822            true,
 5823            cx,
 5824        );
 5825
 5826        let editor_settings = EditorSettings::get_global(cx);
 5827        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5828            // After the code completion is finished, users often want to know what signatures are needed.
 5829            // so we should automatically call signature_help
 5830            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5831        }
 5832
 5833        Some(cx.foreground_executor().spawn(async move {
 5834            apply_edits.await?;
 5835            Ok(())
 5836        }))
 5837    }
 5838
 5839    pub fn toggle_code_actions(
 5840        &mut self,
 5841        action: &ToggleCodeActions,
 5842        window: &mut Window,
 5843        cx: &mut Context<Self>,
 5844    ) {
 5845        let quick_launch = action.quick_launch;
 5846        let mut context_menu = self.context_menu.borrow_mut();
 5847        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5848            if code_actions.deployed_from == action.deployed_from {
 5849                // Toggle if we're selecting the same one
 5850                *context_menu = None;
 5851                cx.notify();
 5852                return;
 5853            } else {
 5854                // Otherwise, clear it and start a new one
 5855                *context_menu = None;
 5856                cx.notify();
 5857            }
 5858        }
 5859        drop(context_menu);
 5860        let snapshot = self.snapshot(window, cx);
 5861        let deployed_from = action.deployed_from.clone();
 5862        let action = action.clone();
 5863        self.completion_tasks.clear();
 5864        self.discard_inline_completion(false, cx);
 5865
 5866        let multibuffer_point = match &action.deployed_from {
 5867            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5868                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5869            }
 5870            _ => self.selections.newest::<Point>(cx).head(),
 5871        };
 5872        let Some((buffer, buffer_row)) = snapshot
 5873            .buffer_snapshot
 5874            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5875            .and_then(|(buffer_snapshot, range)| {
 5876                self.buffer()
 5877                    .read(cx)
 5878                    .buffer(buffer_snapshot.remote_id())
 5879                    .map(|buffer| (buffer, range.start.row))
 5880            })
 5881        else {
 5882            return;
 5883        };
 5884        let buffer_id = buffer.read(cx).remote_id();
 5885        let tasks = self
 5886            .tasks
 5887            .get(&(buffer_id, buffer_row))
 5888            .map(|t| Arc::new(t.to_owned()));
 5889
 5890        if !self.focus_handle.is_focused(window) {
 5891            return;
 5892        }
 5893        let project = self.project.clone();
 5894
 5895        let code_actions_task = match deployed_from {
 5896            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5897            _ => self.code_actions(buffer_row, window, cx),
 5898        };
 5899
 5900        let runnable_task = match deployed_from {
 5901            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5902            _ => {
 5903                let mut task_context_task = Task::ready(None);
 5904                if let Some(tasks) = &tasks {
 5905                    if let Some(project) = project {
 5906                        task_context_task =
 5907                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5908                    }
 5909                }
 5910
 5911                cx.spawn_in(window, {
 5912                    let buffer = buffer.clone();
 5913                    async move |editor, cx| {
 5914                        let task_context = task_context_task.await;
 5915
 5916                        let resolved_tasks =
 5917                            tasks
 5918                                .zip(task_context.clone())
 5919                                .map(|(tasks, task_context)| ResolvedTasks {
 5920                                    templates: tasks.resolve(&task_context).collect(),
 5921                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5922                                        multibuffer_point.row,
 5923                                        tasks.column,
 5924                                    )),
 5925                                });
 5926                        let debug_scenarios = editor
 5927                            .update(cx, |editor, cx| {
 5928                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5929                            })?
 5930                            .await;
 5931                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5932                    }
 5933                })
 5934            }
 5935        };
 5936
 5937        cx.spawn_in(window, async move |editor, cx| {
 5938            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5939            let code_actions = code_actions_task.await;
 5940            let spawn_straight_away = quick_launch
 5941                && resolved_tasks
 5942                    .as_ref()
 5943                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5944                && code_actions
 5945                    .as_ref()
 5946                    .map_or(true, |actions| actions.is_empty())
 5947                && debug_scenarios.is_empty();
 5948
 5949            editor.update_in(cx, |editor, window, cx| {
 5950                crate::hover_popover::hide_hover(editor, cx);
 5951                *editor.context_menu.borrow_mut() =
 5952                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5953                        buffer,
 5954                        actions: CodeActionContents::new(
 5955                            resolved_tasks,
 5956                            code_actions,
 5957                            debug_scenarios,
 5958                            task_context.unwrap_or_default(),
 5959                        ),
 5960                        selected_item: Default::default(),
 5961                        scroll_handle: UniformListScrollHandle::default(),
 5962                        deployed_from,
 5963                    }));
 5964                cx.notify();
 5965                if spawn_straight_away {
 5966                    if let Some(task) = editor.confirm_code_action(
 5967                        &ConfirmCodeAction { item_ix: Some(0) },
 5968                        window,
 5969                        cx,
 5970                    ) {
 5971                        return task;
 5972                    }
 5973                }
 5974
 5975                Task::ready(Ok(()))
 5976            })
 5977        })
 5978        .detach_and_log_err(cx);
 5979    }
 5980
 5981    fn debug_scenarios(
 5982        &mut self,
 5983        resolved_tasks: &Option<ResolvedTasks>,
 5984        buffer: &Entity<Buffer>,
 5985        cx: &mut App,
 5986    ) -> Task<Vec<task::DebugScenario>> {
 5987        maybe!({
 5988            let project = self.project.as_ref()?;
 5989            let dap_store = project.read(cx).dap_store();
 5990            let mut scenarios = vec![];
 5991            let resolved_tasks = resolved_tasks.as_ref()?;
 5992            let buffer = buffer.read(cx);
 5993            let language = buffer.language()?;
 5994            let file = buffer.file();
 5995            let debug_adapter = language_settings(language.name().into(), file, cx)
 5996                .debuggers
 5997                .first()
 5998                .map(SharedString::from)
 5999                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6000
 6001            dap_store.update(cx, |dap_store, cx| {
 6002                for (_, task) in &resolved_tasks.templates {
 6003                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6004                        task.original_task().clone(),
 6005                        debug_adapter.clone().into(),
 6006                        task.display_label().to_owned().into(),
 6007                        cx,
 6008                    );
 6009                    scenarios.push(maybe_scenario);
 6010                }
 6011            });
 6012            Some(cx.background_spawn(async move {
 6013                let scenarios = futures::future::join_all(scenarios)
 6014                    .await
 6015                    .into_iter()
 6016                    .flatten()
 6017                    .collect::<Vec<_>>();
 6018                scenarios
 6019            }))
 6020        })
 6021        .unwrap_or_else(|| Task::ready(vec![]))
 6022    }
 6023
 6024    fn code_actions(
 6025        &mut self,
 6026        buffer_row: u32,
 6027        window: &mut Window,
 6028        cx: &mut Context<Self>,
 6029    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6030        let mut task = self.code_actions_task.take();
 6031        cx.spawn_in(window, async move |editor, cx| {
 6032            while let Some(prev_task) = task {
 6033                prev_task.await.log_err();
 6034                task = editor
 6035                    .update(cx, |this, _| this.code_actions_task.take())
 6036                    .ok()?;
 6037            }
 6038
 6039            editor
 6040                .update(cx, |editor, cx| {
 6041                    editor
 6042                        .available_code_actions
 6043                        .clone()
 6044                        .and_then(|(location, code_actions)| {
 6045                            let snapshot = location.buffer.read(cx).snapshot();
 6046                            let point_range = location.range.to_point(&snapshot);
 6047                            let point_range = point_range.start.row..=point_range.end.row;
 6048                            if point_range.contains(&buffer_row) {
 6049                                Some(code_actions)
 6050                            } else {
 6051                                None
 6052                            }
 6053                        })
 6054                })
 6055                .ok()
 6056                .flatten()
 6057        })
 6058    }
 6059
 6060    pub fn confirm_code_action(
 6061        &mut self,
 6062        action: &ConfirmCodeAction,
 6063        window: &mut Window,
 6064        cx: &mut Context<Self>,
 6065    ) -> Option<Task<Result<()>>> {
 6066        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6067
 6068        let actions_menu =
 6069            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6070                menu
 6071            } else {
 6072                return None;
 6073            };
 6074
 6075        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6076        let action = actions_menu.actions.get(action_ix)?;
 6077        let title = action.label();
 6078        let buffer = actions_menu.buffer;
 6079        let workspace = self.workspace()?;
 6080
 6081        match action {
 6082            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6083                workspace.update(cx, |workspace, cx| {
 6084                    workspace.schedule_resolved_task(
 6085                        task_source_kind,
 6086                        resolved_task,
 6087                        false,
 6088                        window,
 6089                        cx,
 6090                    );
 6091
 6092                    Some(Task::ready(Ok(())))
 6093                })
 6094            }
 6095            CodeActionsItem::CodeAction {
 6096                excerpt_id,
 6097                action,
 6098                provider,
 6099            } => {
 6100                let apply_code_action =
 6101                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6102                let workspace = workspace.downgrade();
 6103                Some(cx.spawn_in(window, async move |editor, cx| {
 6104                    let project_transaction = apply_code_action.await?;
 6105                    Self::open_project_transaction(
 6106                        &editor,
 6107                        workspace,
 6108                        project_transaction,
 6109                        title,
 6110                        cx,
 6111                    )
 6112                    .await
 6113                }))
 6114            }
 6115            CodeActionsItem::DebugScenario(scenario) => {
 6116                let context = actions_menu.actions.context.clone();
 6117
 6118                workspace.update(cx, |workspace, cx| {
 6119                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6120                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6121                });
 6122                Some(Task::ready(Ok(())))
 6123            }
 6124        }
 6125    }
 6126
 6127    pub async fn open_project_transaction(
 6128        this: &WeakEntity<Editor>,
 6129        workspace: WeakEntity<Workspace>,
 6130        transaction: ProjectTransaction,
 6131        title: String,
 6132        cx: &mut AsyncWindowContext,
 6133    ) -> Result<()> {
 6134        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6135        cx.update(|_, cx| {
 6136            entries.sort_unstable_by_key(|(buffer, _)| {
 6137                buffer.read(cx).file().map(|f| f.path().clone())
 6138            });
 6139        })?;
 6140
 6141        // If the project transaction's edits are all contained within this editor, then
 6142        // avoid opening a new editor to display them.
 6143
 6144        if let Some((buffer, transaction)) = entries.first() {
 6145            if entries.len() == 1 {
 6146                let excerpt = this.update(cx, |editor, cx| {
 6147                    editor
 6148                        .buffer()
 6149                        .read(cx)
 6150                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6151                })?;
 6152                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6153                    if excerpted_buffer == *buffer {
 6154                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6155                            let excerpt_range = excerpt_range.to_offset(buffer);
 6156                            buffer
 6157                                .edited_ranges_for_transaction::<usize>(transaction)
 6158                                .all(|range| {
 6159                                    excerpt_range.start <= range.start
 6160                                        && excerpt_range.end >= range.end
 6161                                })
 6162                        })?;
 6163
 6164                        if all_edits_within_excerpt {
 6165                            return Ok(());
 6166                        }
 6167                    }
 6168                }
 6169            }
 6170        } else {
 6171            return Ok(());
 6172        }
 6173
 6174        let mut ranges_to_highlight = Vec::new();
 6175        let excerpt_buffer = cx.new(|cx| {
 6176            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6177            for (buffer_handle, transaction) in &entries {
 6178                let edited_ranges = buffer_handle
 6179                    .read(cx)
 6180                    .edited_ranges_for_transaction::<Point>(transaction)
 6181                    .collect::<Vec<_>>();
 6182                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6183                    PathKey::for_buffer(buffer_handle, cx),
 6184                    buffer_handle.clone(),
 6185                    edited_ranges,
 6186                    DEFAULT_MULTIBUFFER_CONTEXT,
 6187                    cx,
 6188                );
 6189
 6190                ranges_to_highlight.extend(ranges);
 6191            }
 6192            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6193            multibuffer
 6194        })?;
 6195
 6196        workspace.update_in(cx, |workspace, window, cx| {
 6197            let project = workspace.project().clone();
 6198            let editor =
 6199                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6200            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6201            editor.update(cx, |editor, cx| {
 6202                editor.highlight_background::<Self>(
 6203                    &ranges_to_highlight,
 6204                    |theme| theme.colors().editor_highlighted_line_background,
 6205                    cx,
 6206                );
 6207            });
 6208        })?;
 6209
 6210        Ok(())
 6211    }
 6212
 6213    pub fn clear_code_action_providers(&mut self) {
 6214        self.code_action_providers.clear();
 6215        self.available_code_actions.take();
 6216    }
 6217
 6218    pub fn add_code_action_provider(
 6219        &mut self,
 6220        provider: Rc<dyn CodeActionProvider>,
 6221        window: &mut Window,
 6222        cx: &mut Context<Self>,
 6223    ) {
 6224        if self
 6225            .code_action_providers
 6226            .iter()
 6227            .any(|existing_provider| existing_provider.id() == provider.id())
 6228        {
 6229            return;
 6230        }
 6231
 6232        self.code_action_providers.push(provider);
 6233        self.refresh_code_actions(window, cx);
 6234    }
 6235
 6236    pub fn remove_code_action_provider(
 6237        &mut self,
 6238        id: Arc<str>,
 6239        window: &mut Window,
 6240        cx: &mut Context<Self>,
 6241    ) {
 6242        self.code_action_providers
 6243            .retain(|provider| provider.id() != id);
 6244        self.refresh_code_actions(window, cx);
 6245    }
 6246
 6247    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6248        !self.code_action_providers.is_empty()
 6249            && EditorSettings::get_global(cx).toolbar.code_actions
 6250    }
 6251
 6252    pub fn has_available_code_actions(&self) -> bool {
 6253        self.available_code_actions
 6254            .as_ref()
 6255            .is_some_and(|(_, actions)| !actions.is_empty())
 6256    }
 6257
 6258    fn render_inline_code_actions(
 6259        &self,
 6260        icon_size: ui::IconSize,
 6261        display_row: DisplayRow,
 6262        is_active: bool,
 6263        cx: &mut Context<Self>,
 6264    ) -> AnyElement {
 6265        let show_tooltip = !self.context_menu_visible();
 6266        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6267            .icon_size(icon_size)
 6268            .shape(ui::IconButtonShape::Square)
 6269            .style(ButtonStyle::Transparent)
 6270            .icon_color(ui::Color::Hidden)
 6271            .toggle_state(is_active)
 6272            .when(show_tooltip, |this| {
 6273                this.tooltip({
 6274                    let focus_handle = self.focus_handle.clone();
 6275                    move |window, cx| {
 6276                        Tooltip::for_action_in(
 6277                            "Toggle Code Actions",
 6278                            &ToggleCodeActions {
 6279                                deployed_from: None,
 6280                                quick_launch: false,
 6281                            },
 6282                            &focus_handle,
 6283                            window,
 6284                            cx,
 6285                        )
 6286                    }
 6287                })
 6288            })
 6289            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6290                window.focus(&editor.focus_handle(cx));
 6291                editor.toggle_code_actions(
 6292                    &crate::actions::ToggleCodeActions {
 6293                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6294                            display_row,
 6295                        )),
 6296                        quick_launch: false,
 6297                    },
 6298                    window,
 6299                    cx,
 6300                );
 6301            }))
 6302            .into_any_element()
 6303    }
 6304
 6305    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6306        &self.context_menu
 6307    }
 6308
 6309    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6310        let newest_selection = self.selections.newest_anchor().clone();
 6311        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6312        let buffer = self.buffer.read(cx);
 6313        if newest_selection.head().diff_base_anchor.is_some() {
 6314            return None;
 6315        }
 6316        let (start_buffer, start) =
 6317            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6318        let (end_buffer, end) =
 6319            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6320        if start_buffer != end_buffer {
 6321            return None;
 6322        }
 6323
 6324        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6325            cx.background_executor()
 6326                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6327                .await;
 6328
 6329            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6330                let providers = this.code_action_providers.clone();
 6331                let tasks = this
 6332                    .code_action_providers
 6333                    .iter()
 6334                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6335                    .collect::<Vec<_>>();
 6336                (providers, tasks)
 6337            })?;
 6338
 6339            let mut actions = Vec::new();
 6340            for (provider, provider_actions) in
 6341                providers.into_iter().zip(future::join_all(tasks).await)
 6342            {
 6343                if let Some(provider_actions) = provider_actions.log_err() {
 6344                    actions.extend(provider_actions.into_iter().map(|action| {
 6345                        AvailableCodeAction {
 6346                            excerpt_id: newest_selection.start.excerpt_id,
 6347                            action,
 6348                            provider: provider.clone(),
 6349                        }
 6350                    }));
 6351                }
 6352            }
 6353
 6354            this.update(cx, |this, cx| {
 6355                this.available_code_actions = if actions.is_empty() {
 6356                    None
 6357                } else {
 6358                    Some((
 6359                        Location {
 6360                            buffer: start_buffer,
 6361                            range: start..end,
 6362                        },
 6363                        actions.into(),
 6364                    ))
 6365                };
 6366                cx.notify();
 6367            })
 6368        }));
 6369        None
 6370    }
 6371
 6372    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6373        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6374            self.show_git_blame_inline = false;
 6375
 6376            self.show_git_blame_inline_delay_task =
 6377                Some(cx.spawn_in(window, async move |this, cx| {
 6378                    cx.background_executor().timer(delay).await;
 6379
 6380                    this.update(cx, |this, cx| {
 6381                        this.show_git_blame_inline = true;
 6382                        cx.notify();
 6383                    })
 6384                    .log_err();
 6385                }));
 6386        }
 6387    }
 6388
 6389    fn show_blame_popover(
 6390        &mut self,
 6391        blame_entry: &BlameEntry,
 6392        position: gpui::Point<Pixels>,
 6393        cx: &mut Context<Self>,
 6394    ) {
 6395        if let Some(state) = &mut self.inline_blame_popover {
 6396            state.hide_task.take();
 6397        } else {
 6398            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6399            let blame_entry = blame_entry.clone();
 6400            let show_task = cx.spawn(async move |editor, cx| {
 6401                cx.background_executor()
 6402                    .timer(std::time::Duration::from_millis(delay))
 6403                    .await;
 6404                editor
 6405                    .update(cx, |editor, cx| {
 6406                        editor.inline_blame_popover_show_task.take();
 6407                        let Some(blame) = editor.blame.as_ref() else {
 6408                            return;
 6409                        };
 6410                        let blame = blame.read(cx);
 6411                        let details = blame.details_for_entry(&blame_entry);
 6412                        let markdown = cx.new(|cx| {
 6413                            Markdown::new(
 6414                                details
 6415                                    .as_ref()
 6416                                    .map(|message| message.message.clone())
 6417                                    .unwrap_or_default(),
 6418                                None,
 6419                                None,
 6420                                cx,
 6421                            )
 6422                        });
 6423                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6424                            position,
 6425                            hide_task: None,
 6426                            popover_bounds: None,
 6427                            popover_state: InlineBlamePopoverState {
 6428                                scroll_handle: ScrollHandle::new(),
 6429                                commit_message: details,
 6430                                markdown,
 6431                            },
 6432                        });
 6433                        cx.notify();
 6434                    })
 6435                    .ok();
 6436            });
 6437            self.inline_blame_popover_show_task = Some(show_task);
 6438        }
 6439    }
 6440
 6441    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6442        self.inline_blame_popover_show_task.take();
 6443        if let Some(state) = &mut self.inline_blame_popover {
 6444            let hide_task = cx.spawn(async move |editor, cx| {
 6445                cx.background_executor()
 6446                    .timer(std::time::Duration::from_millis(100))
 6447                    .await;
 6448                editor
 6449                    .update(cx, |editor, cx| {
 6450                        editor.inline_blame_popover.take();
 6451                        cx.notify();
 6452                    })
 6453                    .ok();
 6454            });
 6455            state.hide_task = Some(hide_task);
 6456        }
 6457    }
 6458
 6459    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6460        if self.pending_rename.is_some() {
 6461            return None;
 6462        }
 6463
 6464        let provider = self.semantics_provider.clone()?;
 6465        let buffer = self.buffer.read(cx);
 6466        let newest_selection = self.selections.newest_anchor().clone();
 6467        let cursor_position = newest_selection.head();
 6468        let (cursor_buffer, cursor_buffer_position) =
 6469            buffer.text_anchor_for_position(cursor_position, cx)?;
 6470        let (tail_buffer, tail_buffer_position) =
 6471            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6472        if cursor_buffer != tail_buffer {
 6473            return None;
 6474        }
 6475
 6476        let snapshot = cursor_buffer.read(cx).snapshot();
 6477        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6478        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6479        if start_word_range != end_word_range {
 6480            self.document_highlights_task.take();
 6481            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6482            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6483            return None;
 6484        }
 6485
 6486        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6487        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6488            cx.background_executor()
 6489                .timer(Duration::from_millis(debounce))
 6490                .await;
 6491
 6492            let highlights = if let Some(highlights) = cx
 6493                .update(|cx| {
 6494                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6495                })
 6496                .ok()
 6497                .flatten()
 6498            {
 6499                highlights.await.log_err()
 6500            } else {
 6501                None
 6502            };
 6503
 6504            if let Some(highlights) = highlights {
 6505                this.update(cx, |this, cx| {
 6506                    if this.pending_rename.is_some() {
 6507                        return;
 6508                    }
 6509
 6510                    let buffer_id = cursor_position.buffer_id;
 6511                    let buffer = this.buffer.read(cx);
 6512                    if !buffer
 6513                        .text_anchor_for_position(cursor_position, cx)
 6514                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6515                    {
 6516                        return;
 6517                    }
 6518
 6519                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6520                    let mut write_ranges = Vec::new();
 6521                    let mut read_ranges = Vec::new();
 6522                    for highlight in highlights {
 6523                        for (excerpt_id, excerpt_range) in
 6524                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6525                        {
 6526                            let start = highlight
 6527                                .range
 6528                                .start
 6529                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6530                            let end = highlight
 6531                                .range
 6532                                .end
 6533                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6534                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6535                                continue;
 6536                            }
 6537
 6538                            let range = Anchor {
 6539                                buffer_id,
 6540                                excerpt_id,
 6541                                text_anchor: start,
 6542                                diff_base_anchor: None,
 6543                            }..Anchor {
 6544                                buffer_id,
 6545                                excerpt_id,
 6546                                text_anchor: end,
 6547                                diff_base_anchor: None,
 6548                            };
 6549                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6550                                write_ranges.push(range);
 6551                            } else {
 6552                                read_ranges.push(range);
 6553                            }
 6554                        }
 6555                    }
 6556
 6557                    this.highlight_background::<DocumentHighlightRead>(
 6558                        &read_ranges,
 6559                        |theme| theme.colors().editor_document_highlight_read_background,
 6560                        cx,
 6561                    );
 6562                    this.highlight_background::<DocumentHighlightWrite>(
 6563                        &write_ranges,
 6564                        |theme| theme.colors().editor_document_highlight_write_background,
 6565                        cx,
 6566                    );
 6567                    cx.notify();
 6568                })
 6569                .log_err();
 6570            }
 6571        }));
 6572        None
 6573    }
 6574
 6575    fn prepare_highlight_query_from_selection(
 6576        &mut self,
 6577        cx: &mut Context<Editor>,
 6578    ) -> Option<(String, Range<Anchor>)> {
 6579        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6580            return None;
 6581        }
 6582        if !EditorSettings::get_global(cx).selection_highlight {
 6583            return None;
 6584        }
 6585        if self.selections.count() != 1 || self.selections.line_mode {
 6586            return None;
 6587        }
 6588        let selection = self.selections.newest::<Point>(cx);
 6589        if selection.is_empty() || selection.start.row != selection.end.row {
 6590            return None;
 6591        }
 6592        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6593        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6594        let query = multi_buffer_snapshot
 6595            .text_for_range(selection_anchor_range.clone())
 6596            .collect::<String>();
 6597        if query.trim().is_empty() {
 6598            return None;
 6599        }
 6600        Some((query, selection_anchor_range))
 6601    }
 6602
 6603    fn update_selection_occurrence_highlights(
 6604        &mut self,
 6605        query_text: String,
 6606        query_range: Range<Anchor>,
 6607        multi_buffer_range_to_query: Range<Point>,
 6608        use_debounce: bool,
 6609        window: &mut Window,
 6610        cx: &mut Context<Editor>,
 6611    ) -> Task<()> {
 6612        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6613        cx.spawn_in(window, async move |editor, cx| {
 6614            if use_debounce {
 6615                cx.background_executor()
 6616                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6617                    .await;
 6618            }
 6619            let match_task = cx.background_spawn(async move {
 6620                let buffer_ranges = multi_buffer_snapshot
 6621                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6622                    .into_iter()
 6623                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6624                let mut match_ranges = Vec::new();
 6625                let Ok(regex) = project::search::SearchQuery::text(
 6626                    query_text.clone(),
 6627                    false,
 6628                    false,
 6629                    false,
 6630                    Default::default(),
 6631                    Default::default(),
 6632                    false,
 6633                    None,
 6634                ) else {
 6635                    return Vec::default();
 6636                };
 6637                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6638                    match_ranges.extend(
 6639                        regex
 6640                            .search(&buffer_snapshot, Some(search_range.clone()))
 6641                            .await
 6642                            .into_iter()
 6643                            .filter_map(|match_range| {
 6644                                let match_start = buffer_snapshot
 6645                                    .anchor_after(search_range.start + match_range.start);
 6646                                let match_end = buffer_snapshot
 6647                                    .anchor_before(search_range.start + match_range.end);
 6648                                let match_anchor_range = Anchor::range_in_buffer(
 6649                                    excerpt_id,
 6650                                    buffer_snapshot.remote_id(),
 6651                                    match_start..match_end,
 6652                                );
 6653                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6654                            }),
 6655                    );
 6656                }
 6657                match_ranges
 6658            });
 6659            let match_ranges = match_task.await;
 6660            editor
 6661                .update_in(cx, |editor, _, cx| {
 6662                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6663                    if !match_ranges.is_empty() {
 6664                        editor.highlight_background::<SelectedTextHighlight>(
 6665                            &match_ranges,
 6666                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6667                            cx,
 6668                        )
 6669                    }
 6670                })
 6671                .log_err();
 6672        })
 6673    }
 6674
 6675    fn refresh_selected_text_highlights(
 6676        &mut self,
 6677        on_buffer_edit: bool,
 6678        window: &mut Window,
 6679        cx: &mut Context<Editor>,
 6680    ) {
 6681        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6682        else {
 6683            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6684            self.quick_selection_highlight_task.take();
 6685            self.debounced_selection_highlight_task.take();
 6686            return;
 6687        };
 6688        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6689        if on_buffer_edit
 6690            || self
 6691                .quick_selection_highlight_task
 6692                .as_ref()
 6693                .map_or(true, |(prev_anchor_range, _)| {
 6694                    prev_anchor_range != &query_range
 6695                })
 6696        {
 6697            let multi_buffer_visible_start = self
 6698                .scroll_manager
 6699                .anchor()
 6700                .anchor
 6701                .to_point(&multi_buffer_snapshot);
 6702            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6703                multi_buffer_visible_start
 6704                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6705                Bias::Left,
 6706            );
 6707            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6708            self.quick_selection_highlight_task = Some((
 6709                query_range.clone(),
 6710                self.update_selection_occurrence_highlights(
 6711                    query_text.clone(),
 6712                    query_range.clone(),
 6713                    multi_buffer_visible_range,
 6714                    false,
 6715                    window,
 6716                    cx,
 6717                ),
 6718            ));
 6719        }
 6720        if on_buffer_edit
 6721            || self
 6722                .debounced_selection_highlight_task
 6723                .as_ref()
 6724                .map_or(true, |(prev_anchor_range, _)| {
 6725                    prev_anchor_range != &query_range
 6726                })
 6727        {
 6728            let multi_buffer_start = multi_buffer_snapshot
 6729                .anchor_before(0)
 6730                .to_point(&multi_buffer_snapshot);
 6731            let multi_buffer_end = multi_buffer_snapshot
 6732                .anchor_after(multi_buffer_snapshot.len())
 6733                .to_point(&multi_buffer_snapshot);
 6734            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6735            self.debounced_selection_highlight_task = Some((
 6736                query_range.clone(),
 6737                self.update_selection_occurrence_highlights(
 6738                    query_text,
 6739                    query_range,
 6740                    multi_buffer_full_range,
 6741                    true,
 6742                    window,
 6743                    cx,
 6744                ),
 6745            ));
 6746        }
 6747    }
 6748
 6749    pub fn refresh_inline_completion(
 6750        &mut self,
 6751        debounce: bool,
 6752        user_requested: bool,
 6753        window: &mut Window,
 6754        cx: &mut Context<Self>,
 6755    ) -> Option<()> {
 6756        let provider = self.edit_prediction_provider()?;
 6757        let cursor = self.selections.newest_anchor().head();
 6758        let (buffer, cursor_buffer_position) =
 6759            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6760
 6761        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6762            self.discard_inline_completion(false, cx);
 6763            return None;
 6764        }
 6765
 6766        if !user_requested
 6767            && (!self.should_show_edit_predictions()
 6768                || !self.is_focused(window)
 6769                || buffer.read(cx).is_empty())
 6770        {
 6771            self.discard_inline_completion(false, cx);
 6772            return None;
 6773        }
 6774
 6775        self.update_visible_inline_completion(window, cx);
 6776        provider.refresh(
 6777            self.project.clone(),
 6778            buffer,
 6779            cursor_buffer_position,
 6780            debounce,
 6781            cx,
 6782        );
 6783        Some(())
 6784    }
 6785
 6786    fn show_edit_predictions_in_menu(&self) -> bool {
 6787        match self.edit_prediction_settings {
 6788            EditPredictionSettings::Disabled => false,
 6789            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6790        }
 6791    }
 6792
 6793    pub fn edit_predictions_enabled(&self) -> bool {
 6794        match self.edit_prediction_settings {
 6795            EditPredictionSettings::Disabled => false,
 6796            EditPredictionSettings::Enabled { .. } => true,
 6797        }
 6798    }
 6799
 6800    fn edit_prediction_requires_modifier(&self) -> bool {
 6801        match self.edit_prediction_settings {
 6802            EditPredictionSettings::Disabled => false,
 6803            EditPredictionSettings::Enabled {
 6804                preview_requires_modifier,
 6805                ..
 6806            } => preview_requires_modifier,
 6807        }
 6808    }
 6809
 6810    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6811        if self.edit_prediction_provider.is_none() {
 6812            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6813        } else {
 6814            let selection = self.selections.newest_anchor();
 6815            let cursor = selection.head();
 6816
 6817            if let Some((buffer, cursor_buffer_position)) =
 6818                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6819            {
 6820                self.edit_prediction_settings =
 6821                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6822            }
 6823        }
 6824    }
 6825
 6826    fn edit_prediction_settings_at_position(
 6827        &self,
 6828        buffer: &Entity<Buffer>,
 6829        buffer_position: language::Anchor,
 6830        cx: &App,
 6831    ) -> EditPredictionSettings {
 6832        if !self.mode.is_full()
 6833            || !self.show_inline_completions_override.unwrap_or(true)
 6834            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6835        {
 6836            return EditPredictionSettings::Disabled;
 6837        }
 6838
 6839        let buffer = buffer.read(cx);
 6840
 6841        let file = buffer.file();
 6842
 6843        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6844            return EditPredictionSettings::Disabled;
 6845        };
 6846
 6847        let by_provider = matches!(
 6848            self.menu_inline_completions_policy,
 6849            MenuInlineCompletionsPolicy::ByProvider
 6850        );
 6851
 6852        let show_in_menu = by_provider
 6853            && self
 6854                .edit_prediction_provider
 6855                .as_ref()
 6856                .map_or(false, |provider| {
 6857                    provider.provider.show_completions_in_menu()
 6858                });
 6859
 6860        let preview_requires_modifier =
 6861            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6862
 6863        EditPredictionSettings::Enabled {
 6864            show_in_menu,
 6865            preview_requires_modifier,
 6866        }
 6867    }
 6868
 6869    fn should_show_edit_predictions(&self) -> bool {
 6870        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6871    }
 6872
 6873    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6874        matches!(
 6875            self.edit_prediction_preview,
 6876            EditPredictionPreview::Active { .. }
 6877        )
 6878    }
 6879
 6880    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6881        let cursor = self.selections.newest_anchor().head();
 6882        if let Some((buffer, cursor_position)) =
 6883            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6884        {
 6885            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6886        } else {
 6887            false
 6888        }
 6889    }
 6890
 6891    pub fn supports_minimap(&self, cx: &App) -> bool {
 6892        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6893    }
 6894
 6895    fn edit_predictions_enabled_in_buffer(
 6896        &self,
 6897        buffer: &Entity<Buffer>,
 6898        buffer_position: language::Anchor,
 6899        cx: &App,
 6900    ) -> bool {
 6901        maybe!({
 6902            if self.read_only(cx) {
 6903                return Some(false);
 6904            }
 6905            let provider = self.edit_prediction_provider()?;
 6906            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6907                return Some(false);
 6908            }
 6909            let buffer = buffer.read(cx);
 6910            let Some(file) = buffer.file() else {
 6911                return Some(true);
 6912            };
 6913            let settings = all_language_settings(Some(file), cx);
 6914            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6915        })
 6916        .unwrap_or(false)
 6917    }
 6918
 6919    fn cycle_inline_completion(
 6920        &mut self,
 6921        direction: Direction,
 6922        window: &mut Window,
 6923        cx: &mut Context<Self>,
 6924    ) -> Option<()> {
 6925        let provider = self.edit_prediction_provider()?;
 6926        let cursor = self.selections.newest_anchor().head();
 6927        let (buffer, cursor_buffer_position) =
 6928            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6929        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6930            return None;
 6931        }
 6932
 6933        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6934        self.update_visible_inline_completion(window, cx);
 6935
 6936        Some(())
 6937    }
 6938
 6939    pub fn show_inline_completion(
 6940        &mut self,
 6941        _: &ShowEditPrediction,
 6942        window: &mut Window,
 6943        cx: &mut Context<Self>,
 6944    ) {
 6945        if !self.has_active_inline_completion() {
 6946            self.refresh_inline_completion(false, true, window, cx);
 6947            return;
 6948        }
 6949
 6950        self.update_visible_inline_completion(window, cx);
 6951    }
 6952
 6953    pub fn display_cursor_names(
 6954        &mut self,
 6955        _: &DisplayCursorNames,
 6956        window: &mut Window,
 6957        cx: &mut Context<Self>,
 6958    ) {
 6959        self.show_cursor_names(window, cx);
 6960    }
 6961
 6962    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6963        self.show_cursor_names = true;
 6964        cx.notify();
 6965        cx.spawn_in(window, async move |this, cx| {
 6966            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6967            this.update(cx, |this, cx| {
 6968                this.show_cursor_names = false;
 6969                cx.notify()
 6970            })
 6971            .ok()
 6972        })
 6973        .detach();
 6974    }
 6975
 6976    pub fn next_edit_prediction(
 6977        &mut self,
 6978        _: &NextEditPrediction,
 6979        window: &mut Window,
 6980        cx: &mut Context<Self>,
 6981    ) {
 6982        if self.has_active_inline_completion() {
 6983            self.cycle_inline_completion(Direction::Next, window, cx);
 6984        } else {
 6985            let is_copilot_disabled = self
 6986                .refresh_inline_completion(false, true, window, cx)
 6987                .is_none();
 6988            if is_copilot_disabled {
 6989                cx.propagate();
 6990            }
 6991        }
 6992    }
 6993
 6994    pub fn previous_edit_prediction(
 6995        &mut self,
 6996        _: &PreviousEditPrediction,
 6997        window: &mut Window,
 6998        cx: &mut Context<Self>,
 6999    ) {
 7000        if self.has_active_inline_completion() {
 7001            self.cycle_inline_completion(Direction::Prev, window, cx);
 7002        } else {
 7003            let is_copilot_disabled = self
 7004                .refresh_inline_completion(false, true, window, cx)
 7005                .is_none();
 7006            if is_copilot_disabled {
 7007                cx.propagate();
 7008            }
 7009        }
 7010    }
 7011
 7012    pub fn accept_edit_prediction(
 7013        &mut self,
 7014        _: &AcceptEditPrediction,
 7015        window: &mut Window,
 7016        cx: &mut Context<Self>,
 7017    ) {
 7018        if self.show_edit_predictions_in_menu() {
 7019            self.hide_context_menu(window, cx);
 7020        }
 7021
 7022        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7023            return;
 7024        };
 7025
 7026        self.report_inline_completion_event(
 7027            active_inline_completion.completion_id.clone(),
 7028            true,
 7029            cx,
 7030        );
 7031
 7032        match &active_inline_completion.completion {
 7033            InlineCompletion::Move { target, .. } => {
 7034                let target = *target;
 7035
 7036                if let Some(position_map) = &self.last_position_map {
 7037                    if position_map
 7038                        .visible_row_range
 7039                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7040                        || !self.edit_prediction_requires_modifier()
 7041                    {
 7042                        self.unfold_ranges(&[target..target], true, false, cx);
 7043                        // Note that this is also done in vim's handler of the Tab action.
 7044                        self.change_selections(
 7045                            Some(Autoscroll::newest()),
 7046                            window,
 7047                            cx,
 7048                            |selections| {
 7049                                selections.select_anchor_ranges([target..target]);
 7050                            },
 7051                        );
 7052                        self.clear_row_highlights::<EditPredictionPreview>();
 7053
 7054                        self.edit_prediction_preview
 7055                            .set_previous_scroll_position(None);
 7056                    } else {
 7057                        self.edit_prediction_preview
 7058                            .set_previous_scroll_position(Some(
 7059                                position_map.snapshot.scroll_anchor,
 7060                            ));
 7061
 7062                        self.highlight_rows::<EditPredictionPreview>(
 7063                            target..target,
 7064                            cx.theme().colors().editor_highlighted_line_background,
 7065                            RowHighlightOptions {
 7066                                autoscroll: true,
 7067                                ..Default::default()
 7068                            },
 7069                            cx,
 7070                        );
 7071                        self.request_autoscroll(Autoscroll::fit(), cx);
 7072                    }
 7073                }
 7074            }
 7075            InlineCompletion::Edit { edits, .. } => {
 7076                if let Some(provider) = self.edit_prediction_provider() {
 7077                    provider.accept(cx);
 7078                }
 7079
 7080                // Store the transaction ID and selections before applying the edit
 7081                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7082
 7083                let snapshot = self.buffer.read(cx).snapshot(cx);
 7084                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7085
 7086                self.buffer.update(cx, |buffer, cx| {
 7087                    buffer.edit(edits.iter().cloned(), None, cx)
 7088                });
 7089
 7090                self.change_selections(None, window, cx, |s| {
 7091                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7092                });
 7093
 7094                let selections = self.selections.disjoint_anchors();
 7095                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7096                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7097                    if has_new_transaction {
 7098                        self.selection_history
 7099                            .insert_transaction(transaction_id_now, selections);
 7100                    }
 7101                }
 7102
 7103                self.update_visible_inline_completion(window, cx);
 7104                if self.active_inline_completion.is_none() {
 7105                    self.refresh_inline_completion(true, true, window, cx);
 7106                }
 7107
 7108                cx.notify();
 7109            }
 7110        }
 7111
 7112        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7113    }
 7114
 7115    pub fn accept_partial_inline_completion(
 7116        &mut self,
 7117        _: &AcceptPartialEditPrediction,
 7118        window: &mut Window,
 7119        cx: &mut Context<Self>,
 7120    ) {
 7121        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7122            return;
 7123        };
 7124        if self.selections.count() != 1 {
 7125            return;
 7126        }
 7127
 7128        self.report_inline_completion_event(
 7129            active_inline_completion.completion_id.clone(),
 7130            true,
 7131            cx,
 7132        );
 7133
 7134        match &active_inline_completion.completion {
 7135            InlineCompletion::Move { target, .. } => {
 7136                let target = *target;
 7137                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7138                    selections.select_anchor_ranges([target..target]);
 7139                });
 7140            }
 7141            InlineCompletion::Edit { edits, .. } => {
 7142                // Find an insertion that starts at the cursor position.
 7143                let snapshot = self.buffer.read(cx).snapshot(cx);
 7144                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7145                let insertion = edits.iter().find_map(|(range, text)| {
 7146                    let range = range.to_offset(&snapshot);
 7147                    if range.is_empty() && range.start == cursor_offset {
 7148                        Some(text)
 7149                    } else {
 7150                        None
 7151                    }
 7152                });
 7153
 7154                if let Some(text) = insertion {
 7155                    let mut partial_completion = text
 7156                        .chars()
 7157                        .by_ref()
 7158                        .take_while(|c| c.is_alphabetic())
 7159                        .collect::<String>();
 7160                    if partial_completion.is_empty() {
 7161                        partial_completion = text
 7162                            .chars()
 7163                            .by_ref()
 7164                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7165                            .collect::<String>();
 7166                    }
 7167
 7168                    cx.emit(EditorEvent::InputHandled {
 7169                        utf16_range_to_replace: None,
 7170                        text: partial_completion.clone().into(),
 7171                    });
 7172
 7173                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7174
 7175                    self.refresh_inline_completion(true, true, window, cx);
 7176                    cx.notify();
 7177                } else {
 7178                    self.accept_edit_prediction(&Default::default(), window, cx);
 7179                }
 7180            }
 7181        }
 7182    }
 7183
 7184    fn discard_inline_completion(
 7185        &mut self,
 7186        should_report_inline_completion_event: bool,
 7187        cx: &mut Context<Self>,
 7188    ) -> bool {
 7189        if should_report_inline_completion_event {
 7190            let completion_id = self
 7191                .active_inline_completion
 7192                .as_ref()
 7193                .and_then(|active_completion| active_completion.completion_id.clone());
 7194
 7195            self.report_inline_completion_event(completion_id, false, cx);
 7196        }
 7197
 7198        if let Some(provider) = self.edit_prediction_provider() {
 7199            provider.discard(cx);
 7200        }
 7201
 7202        self.take_active_inline_completion(cx)
 7203    }
 7204
 7205    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7206        let Some(provider) = self.edit_prediction_provider() else {
 7207            return;
 7208        };
 7209
 7210        let Some((_, buffer, _)) = self
 7211            .buffer
 7212            .read(cx)
 7213            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7214        else {
 7215            return;
 7216        };
 7217
 7218        let extension = buffer
 7219            .read(cx)
 7220            .file()
 7221            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7222
 7223        let event_type = match accepted {
 7224            true => "Edit Prediction Accepted",
 7225            false => "Edit Prediction Discarded",
 7226        };
 7227        telemetry::event!(
 7228            event_type,
 7229            provider = provider.name(),
 7230            prediction_id = id,
 7231            suggestion_accepted = accepted,
 7232            file_extension = extension,
 7233        );
 7234    }
 7235
 7236    pub fn has_active_inline_completion(&self) -> bool {
 7237        self.active_inline_completion.is_some()
 7238    }
 7239
 7240    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7241        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7242            return false;
 7243        };
 7244
 7245        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7246        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7247        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7248        true
 7249    }
 7250
 7251    /// Returns true when we're displaying the edit prediction popover below the cursor
 7252    /// like we are not previewing and the LSP autocomplete menu is visible
 7253    /// or we are in `when_holding_modifier` mode.
 7254    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7255        if self.edit_prediction_preview_is_active()
 7256            || !self.show_edit_predictions_in_menu()
 7257            || !self.edit_predictions_enabled()
 7258        {
 7259            return false;
 7260        }
 7261
 7262        if self.has_visible_completions_menu() {
 7263            return true;
 7264        }
 7265
 7266        has_completion && self.edit_prediction_requires_modifier()
 7267    }
 7268
 7269    fn handle_modifiers_changed(
 7270        &mut self,
 7271        modifiers: Modifiers,
 7272        position_map: &PositionMap,
 7273        window: &mut Window,
 7274        cx: &mut Context<Self>,
 7275    ) {
 7276        if self.show_edit_predictions_in_menu() {
 7277            self.update_edit_prediction_preview(&modifiers, window, cx);
 7278        }
 7279
 7280        self.update_selection_mode(&modifiers, position_map, window, cx);
 7281
 7282        let mouse_position = window.mouse_position();
 7283        if !position_map.text_hitbox.is_hovered(window) {
 7284            return;
 7285        }
 7286
 7287        self.update_hovered_link(
 7288            position_map.point_for_position(mouse_position),
 7289            &position_map.snapshot,
 7290            modifiers,
 7291            window,
 7292            cx,
 7293        )
 7294    }
 7295
 7296    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7297        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7298        if invert {
 7299            match multi_cursor_setting {
 7300                MultiCursorModifier::Alt => modifiers.alt,
 7301                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7302            }
 7303        } else {
 7304            match multi_cursor_setting {
 7305                MultiCursorModifier::Alt => modifiers.secondary(),
 7306                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7307            }
 7308        }
 7309    }
 7310
 7311    fn columnar_selection_mode(
 7312        modifiers: &Modifiers,
 7313        cx: &mut Context<Self>,
 7314    ) -> Option<ColumnarMode> {
 7315        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7316            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7317                Some(ColumnarMode::FromMouse)
 7318            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7319                Some(ColumnarMode::FromSelection)
 7320            } else {
 7321                None
 7322            }
 7323        } else {
 7324            None
 7325        }
 7326    }
 7327
 7328    fn update_selection_mode(
 7329        &mut self,
 7330        modifiers: &Modifiers,
 7331        position_map: &PositionMap,
 7332        window: &mut Window,
 7333        cx: &mut Context<Self>,
 7334    ) {
 7335        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7336            return;
 7337        };
 7338        if self.selections.pending.is_none() {
 7339            return;
 7340        }
 7341
 7342        let mouse_position = window.mouse_position();
 7343        let point_for_position = position_map.point_for_position(mouse_position);
 7344        let position = point_for_position.previous_valid;
 7345
 7346        self.select(
 7347            SelectPhase::BeginColumnar {
 7348                position,
 7349                reset: false,
 7350                mode,
 7351                goal_column: point_for_position.exact_unclipped.column(),
 7352            },
 7353            window,
 7354            cx,
 7355        );
 7356    }
 7357
 7358    fn update_edit_prediction_preview(
 7359        &mut self,
 7360        modifiers: &Modifiers,
 7361        window: &mut Window,
 7362        cx: &mut Context<Self>,
 7363    ) {
 7364        let mut modifiers_held = false;
 7365        if let Some(accept_keystroke) = self
 7366            .accept_edit_prediction_keybind(false, window, cx)
 7367            .keystroke()
 7368        {
 7369            modifiers_held = modifiers_held
 7370                || (&accept_keystroke.modifiers == modifiers
 7371                    && accept_keystroke.modifiers.modified());
 7372        };
 7373        if let Some(accept_partial_keystroke) = self
 7374            .accept_edit_prediction_keybind(true, window, cx)
 7375            .keystroke()
 7376        {
 7377            modifiers_held = modifiers_held
 7378                || (&accept_partial_keystroke.modifiers == modifiers
 7379                    && accept_partial_keystroke.modifiers.modified());
 7380        }
 7381
 7382        if modifiers_held {
 7383            if matches!(
 7384                self.edit_prediction_preview,
 7385                EditPredictionPreview::Inactive { .. }
 7386            ) {
 7387                self.edit_prediction_preview = EditPredictionPreview::Active {
 7388                    previous_scroll_position: None,
 7389                    since: Instant::now(),
 7390                };
 7391
 7392                self.update_visible_inline_completion(window, cx);
 7393                cx.notify();
 7394            }
 7395        } else if let EditPredictionPreview::Active {
 7396            previous_scroll_position,
 7397            since,
 7398        } = self.edit_prediction_preview
 7399        {
 7400            if let (Some(previous_scroll_position), Some(position_map)) =
 7401                (previous_scroll_position, self.last_position_map.as_ref())
 7402            {
 7403                self.set_scroll_position(
 7404                    previous_scroll_position
 7405                        .scroll_position(&position_map.snapshot.display_snapshot),
 7406                    window,
 7407                    cx,
 7408                );
 7409            }
 7410
 7411            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7412                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7413            };
 7414            self.clear_row_highlights::<EditPredictionPreview>();
 7415            self.update_visible_inline_completion(window, cx);
 7416            cx.notify();
 7417        }
 7418    }
 7419
 7420    fn update_visible_inline_completion(
 7421        &mut self,
 7422        _window: &mut Window,
 7423        cx: &mut Context<Self>,
 7424    ) -> Option<()> {
 7425        let selection = self.selections.newest_anchor();
 7426        let cursor = selection.head();
 7427        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7428        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7429        let excerpt_id = cursor.excerpt_id;
 7430
 7431        let show_in_menu = self.show_edit_predictions_in_menu();
 7432        let completions_menu_has_precedence = !show_in_menu
 7433            && (self.context_menu.borrow().is_some()
 7434                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7435
 7436        if completions_menu_has_precedence
 7437            || !offset_selection.is_empty()
 7438            || self
 7439                .active_inline_completion
 7440                .as_ref()
 7441                .map_or(false, |completion| {
 7442                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7443                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7444                    !invalidation_range.contains(&offset_selection.head())
 7445                })
 7446        {
 7447            self.discard_inline_completion(false, cx);
 7448            return None;
 7449        }
 7450
 7451        self.take_active_inline_completion(cx);
 7452        let Some(provider) = self.edit_prediction_provider() else {
 7453            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7454            return None;
 7455        };
 7456
 7457        let (buffer, cursor_buffer_position) =
 7458            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7459
 7460        self.edit_prediction_settings =
 7461            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7462
 7463        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7464
 7465        if self.edit_prediction_indent_conflict {
 7466            let cursor_point = cursor.to_point(&multibuffer);
 7467
 7468            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7469
 7470            if let Some((_, indent)) = indents.iter().next() {
 7471                if indent.len == cursor_point.column {
 7472                    self.edit_prediction_indent_conflict = false;
 7473                }
 7474            }
 7475        }
 7476
 7477        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7478        let edits = inline_completion
 7479            .edits
 7480            .into_iter()
 7481            .flat_map(|(range, new_text)| {
 7482                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7483                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7484                Some((start..end, new_text))
 7485            })
 7486            .collect::<Vec<_>>();
 7487        if edits.is_empty() {
 7488            return None;
 7489        }
 7490
 7491        let first_edit_start = edits.first().unwrap().0.start;
 7492        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7493        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7494
 7495        let last_edit_end = edits.last().unwrap().0.end;
 7496        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7497        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7498
 7499        let cursor_row = cursor.to_point(&multibuffer).row;
 7500
 7501        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7502
 7503        let mut inlay_ids = Vec::new();
 7504        let invalidation_row_range;
 7505        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7506            Some(cursor_row..edit_end_row)
 7507        } else if cursor_row > edit_end_row {
 7508            Some(edit_start_row..cursor_row)
 7509        } else {
 7510            None
 7511        };
 7512        let is_move =
 7513            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7514        let completion = if is_move {
 7515            invalidation_row_range =
 7516                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7517            let target = first_edit_start;
 7518            InlineCompletion::Move { target, snapshot }
 7519        } else {
 7520            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7521                && !self.inline_completions_hidden_for_vim_mode;
 7522
 7523            if show_completions_in_buffer {
 7524                if edits
 7525                    .iter()
 7526                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7527                {
 7528                    let mut inlays = Vec::new();
 7529                    for (range, new_text) in &edits {
 7530                        let inlay = Inlay::inline_completion(
 7531                            post_inc(&mut self.next_inlay_id),
 7532                            range.start,
 7533                            new_text.as_str(),
 7534                        );
 7535                        inlay_ids.push(inlay.id);
 7536                        inlays.push(inlay);
 7537                    }
 7538
 7539                    self.splice_inlays(&[], inlays, cx);
 7540                } else {
 7541                    let background_color = cx.theme().status().deleted_background;
 7542                    self.highlight_text::<InlineCompletionHighlight>(
 7543                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7544                        HighlightStyle {
 7545                            background_color: Some(background_color),
 7546                            ..Default::default()
 7547                        },
 7548                        cx,
 7549                    );
 7550                }
 7551            }
 7552
 7553            invalidation_row_range = edit_start_row..edit_end_row;
 7554
 7555            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7556                if provider.show_tab_accept_marker() {
 7557                    EditDisplayMode::TabAccept
 7558                } else {
 7559                    EditDisplayMode::Inline
 7560                }
 7561            } else {
 7562                EditDisplayMode::DiffPopover
 7563            };
 7564
 7565            InlineCompletion::Edit {
 7566                edits,
 7567                edit_preview: inline_completion.edit_preview,
 7568                display_mode,
 7569                snapshot,
 7570            }
 7571        };
 7572
 7573        let invalidation_range = multibuffer
 7574            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7575            ..multibuffer.anchor_after(Point::new(
 7576                invalidation_row_range.end,
 7577                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7578            ));
 7579
 7580        self.stale_inline_completion_in_menu = None;
 7581        self.active_inline_completion = Some(InlineCompletionState {
 7582            inlay_ids,
 7583            completion,
 7584            completion_id: inline_completion.id,
 7585            invalidation_range,
 7586        });
 7587
 7588        cx.notify();
 7589
 7590        Some(())
 7591    }
 7592
 7593    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7594        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7595    }
 7596
 7597    fn clear_tasks(&mut self) {
 7598        self.tasks.clear()
 7599    }
 7600
 7601    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7602        if self.tasks.insert(key, value).is_some() {
 7603            // This case should hopefully be rare, but just in case...
 7604            log::error!(
 7605                "multiple different run targets found on a single line, only the last target will be rendered"
 7606            )
 7607        }
 7608    }
 7609
 7610    /// Get all display points of breakpoints that will be rendered within editor
 7611    ///
 7612    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7613    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7614    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7615    fn active_breakpoints(
 7616        &self,
 7617        range: Range<DisplayRow>,
 7618        window: &mut Window,
 7619        cx: &mut Context<Self>,
 7620    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7621        let mut breakpoint_display_points = HashMap::default();
 7622
 7623        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7624            return breakpoint_display_points;
 7625        };
 7626
 7627        let snapshot = self.snapshot(window, cx);
 7628
 7629        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7630        let Some(project) = self.project.as_ref() else {
 7631            return breakpoint_display_points;
 7632        };
 7633
 7634        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7635            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7636
 7637        for (buffer_snapshot, range, excerpt_id) in
 7638            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7639        {
 7640            let Some(buffer) = project
 7641                .read(cx)
 7642                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7643            else {
 7644                continue;
 7645            };
 7646            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7647                &buffer,
 7648                Some(
 7649                    buffer_snapshot.anchor_before(range.start)
 7650                        ..buffer_snapshot.anchor_after(range.end),
 7651                ),
 7652                buffer_snapshot,
 7653                cx,
 7654            );
 7655            for (breakpoint, state) in breakpoints {
 7656                let multi_buffer_anchor =
 7657                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7658                let position = multi_buffer_anchor
 7659                    .to_point(&multi_buffer_snapshot)
 7660                    .to_display_point(&snapshot);
 7661
 7662                breakpoint_display_points.insert(
 7663                    position.row(),
 7664                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7665                );
 7666            }
 7667        }
 7668
 7669        breakpoint_display_points
 7670    }
 7671
 7672    fn breakpoint_context_menu(
 7673        &self,
 7674        anchor: Anchor,
 7675        window: &mut Window,
 7676        cx: &mut Context<Self>,
 7677    ) -> Entity<ui::ContextMenu> {
 7678        let weak_editor = cx.weak_entity();
 7679        let focus_handle = self.focus_handle(cx);
 7680
 7681        let row = self
 7682            .buffer
 7683            .read(cx)
 7684            .snapshot(cx)
 7685            .summary_for_anchor::<Point>(&anchor)
 7686            .row;
 7687
 7688        let breakpoint = self
 7689            .breakpoint_at_row(row, window, cx)
 7690            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7691
 7692        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7693            "Edit Log Breakpoint"
 7694        } else {
 7695            "Set Log Breakpoint"
 7696        };
 7697
 7698        let condition_breakpoint_msg = if breakpoint
 7699            .as_ref()
 7700            .is_some_and(|bp| bp.1.condition.is_some())
 7701        {
 7702            "Edit Condition Breakpoint"
 7703        } else {
 7704            "Set Condition Breakpoint"
 7705        };
 7706
 7707        let hit_condition_breakpoint_msg = if breakpoint
 7708            .as_ref()
 7709            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7710        {
 7711            "Edit Hit Condition Breakpoint"
 7712        } else {
 7713            "Set Hit Condition Breakpoint"
 7714        };
 7715
 7716        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7717            "Unset Breakpoint"
 7718        } else {
 7719            "Set Breakpoint"
 7720        };
 7721
 7722        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7723
 7724        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7725            BreakpointState::Enabled => Some("Disable"),
 7726            BreakpointState::Disabled => Some("Enable"),
 7727        });
 7728
 7729        let (anchor, breakpoint) =
 7730            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7731
 7732        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7733            menu.on_blur_subscription(Subscription::new(|| {}))
 7734                .context(focus_handle)
 7735                .when(run_to_cursor, |this| {
 7736                    let weak_editor = weak_editor.clone();
 7737                    this.entry("Run to cursor", None, move |window, cx| {
 7738                        weak_editor
 7739                            .update(cx, |editor, cx| {
 7740                                editor.change_selections(None, window, cx, |s| {
 7741                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7742                                });
 7743                            })
 7744                            .ok();
 7745
 7746                        window.dispatch_action(Box::new(RunToCursor), cx);
 7747                    })
 7748                    .separator()
 7749                })
 7750                .when_some(toggle_state_msg, |this, msg| {
 7751                    this.entry(msg, None, {
 7752                        let weak_editor = weak_editor.clone();
 7753                        let breakpoint = breakpoint.clone();
 7754                        move |_window, cx| {
 7755                            weak_editor
 7756                                .update(cx, |this, cx| {
 7757                                    this.edit_breakpoint_at_anchor(
 7758                                        anchor,
 7759                                        breakpoint.as_ref().clone(),
 7760                                        BreakpointEditAction::InvertState,
 7761                                        cx,
 7762                                    );
 7763                                })
 7764                                .log_err();
 7765                        }
 7766                    })
 7767                })
 7768                .entry(set_breakpoint_msg, None, {
 7769                    let weak_editor = weak_editor.clone();
 7770                    let breakpoint = breakpoint.clone();
 7771                    move |_window, cx| {
 7772                        weak_editor
 7773                            .update(cx, |this, cx| {
 7774                                this.edit_breakpoint_at_anchor(
 7775                                    anchor,
 7776                                    breakpoint.as_ref().clone(),
 7777                                    BreakpointEditAction::Toggle,
 7778                                    cx,
 7779                                );
 7780                            })
 7781                            .log_err();
 7782                    }
 7783                })
 7784                .entry(log_breakpoint_msg, None, {
 7785                    let breakpoint = breakpoint.clone();
 7786                    let weak_editor = weak_editor.clone();
 7787                    move |window, cx| {
 7788                        weak_editor
 7789                            .update(cx, |this, cx| {
 7790                                this.add_edit_breakpoint_block(
 7791                                    anchor,
 7792                                    breakpoint.as_ref(),
 7793                                    BreakpointPromptEditAction::Log,
 7794                                    window,
 7795                                    cx,
 7796                                );
 7797                            })
 7798                            .log_err();
 7799                    }
 7800                })
 7801                .entry(condition_breakpoint_msg, None, {
 7802                    let breakpoint = breakpoint.clone();
 7803                    let weak_editor = weak_editor.clone();
 7804                    move |window, cx| {
 7805                        weak_editor
 7806                            .update(cx, |this, cx| {
 7807                                this.add_edit_breakpoint_block(
 7808                                    anchor,
 7809                                    breakpoint.as_ref(),
 7810                                    BreakpointPromptEditAction::Condition,
 7811                                    window,
 7812                                    cx,
 7813                                );
 7814                            })
 7815                            .log_err();
 7816                    }
 7817                })
 7818                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7819                    weak_editor
 7820                        .update(cx, |this, cx| {
 7821                            this.add_edit_breakpoint_block(
 7822                                anchor,
 7823                                breakpoint.as_ref(),
 7824                                BreakpointPromptEditAction::HitCondition,
 7825                                window,
 7826                                cx,
 7827                            );
 7828                        })
 7829                        .log_err();
 7830                })
 7831        })
 7832    }
 7833
 7834    fn render_breakpoint(
 7835        &self,
 7836        position: Anchor,
 7837        row: DisplayRow,
 7838        breakpoint: &Breakpoint,
 7839        state: Option<BreakpointSessionState>,
 7840        cx: &mut Context<Self>,
 7841    ) -> IconButton {
 7842        let is_rejected = state.is_some_and(|s| !s.verified);
 7843        // Is it a breakpoint that shows up when hovering over gutter?
 7844        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7845            (false, false),
 7846            |PhantomBreakpointIndicator {
 7847                 is_active,
 7848                 display_row,
 7849                 collides_with_existing_breakpoint,
 7850             }| {
 7851                (
 7852                    is_active && display_row == row,
 7853                    collides_with_existing_breakpoint,
 7854                )
 7855            },
 7856        );
 7857
 7858        let (color, icon) = {
 7859            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7860                (false, false) => ui::IconName::DebugBreakpoint,
 7861                (true, false) => ui::IconName::DebugLogBreakpoint,
 7862                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7863                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7864            };
 7865
 7866            let color = if is_phantom {
 7867                Color::Hint
 7868            } else if is_rejected {
 7869                Color::Disabled
 7870            } else {
 7871                Color::Debugger
 7872            };
 7873
 7874            (color, icon)
 7875        };
 7876
 7877        let breakpoint = Arc::from(breakpoint.clone());
 7878
 7879        let alt_as_text = gpui::Keystroke {
 7880            modifiers: Modifiers::secondary_key(),
 7881            ..Default::default()
 7882        };
 7883        let primary_action_text = if breakpoint.is_disabled() {
 7884            "Enable breakpoint"
 7885        } else if is_phantom && !collides_with_existing {
 7886            "Set breakpoint"
 7887        } else {
 7888            "Unset breakpoint"
 7889        };
 7890        let focus_handle = self.focus_handle.clone();
 7891
 7892        let meta = if is_rejected {
 7893            SharedString::from("No executable code is associated with this line.")
 7894        } else if collides_with_existing && !breakpoint.is_disabled() {
 7895            SharedString::from(format!(
 7896                "{alt_as_text}-click to disable,\nright-click for more options."
 7897            ))
 7898        } else {
 7899            SharedString::from("Right-click for more options.")
 7900        };
 7901        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7902            .icon_size(IconSize::XSmall)
 7903            .size(ui::ButtonSize::None)
 7904            .when(is_rejected, |this| {
 7905                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7906            })
 7907            .icon_color(color)
 7908            .style(ButtonStyle::Transparent)
 7909            .on_click(cx.listener({
 7910                let breakpoint = breakpoint.clone();
 7911
 7912                move |editor, event: &ClickEvent, window, cx| {
 7913                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7914                        BreakpointEditAction::InvertState
 7915                    } else {
 7916                        BreakpointEditAction::Toggle
 7917                    };
 7918
 7919                    window.focus(&editor.focus_handle(cx));
 7920                    editor.edit_breakpoint_at_anchor(
 7921                        position,
 7922                        breakpoint.as_ref().clone(),
 7923                        edit_action,
 7924                        cx,
 7925                    );
 7926                }
 7927            }))
 7928            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7929                editor.set_breakpoint_context_menu(
 7930                    row,
 7931                    Some(position),
 7932                    event.down.position,
 7933                    window,
 7934                    cx,
 7935                );
 7936            }))
 7937            .tooltip(move |window, cx| {
 7938                Tooltip::with_meta_in(
 7939                    primary_action_text,
 7940                    Some(&ToggleBreakpoint),
 7941                    meta.clone(),
 7942                    &focus_handle,
 7943                    window,
 7944                    cx,
 7945                )
 7946            })
 7947    }
 7948
 7949    fn build_tasks_context(
 7950        project: &Entity<Project>,
 7951        buffer: &Entity<Buffer>,
 7952        buffer_row: u32,
 7953        tasks: &Arc<RunnableTasks>,
 7954        cx: &mut Context<Self>,
 7955    ) -> Task<Option<task::TaskContext>> {
 7956        let position = Point::new(buffer_row, tasks.column);
 7957        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7958        let location = Location {
 7959            buffer: buffer.clone(),
 7960            range: range_start..range_start,
 7961        };
 7962        // Fill in the environmental variables from the tree-sitter captures
 7963        let mut captured_task_variables = TaskVariables::default();
 7964        for (capture_name, value) in tasks.extra_variables.clone() {
 7965            captured_task_variables.insert(
 7966                task::VariableName::Custom(capture_name.into()),
 7967                value.clone(),
 7968            );
 7969        }
 7970        project.update(cx, |project, cx| {
 7971            project.task_store().update(cx, |task_store, cx| {
 7972                task_store.task_context_for_location(captured_task_variables, location, cx)
 7973            })
 7974        })
 7975    }
 7976
 7977    pub fn spawn_nearest_task(
 7978        &mut self,
 7979        action: &SpawnNearestTask,
 7980        window: &mut Window,
 7981        cx: &mut Context<Self>,
 7982    ) {
 7983        let Some((workspace, _)) = self.workspace.clone() else {
 7984            return;
 7985        };
 7986        let Some(project) = self.project.clone() else {
 7987            return;
 7988        };
 7989
 7990        // Try to find a closest, enclosing node using tree-sitter that has a
 7991        // task
 7992        let Some((buffer, buffer_row, tasks)) = self
 7993            .find_enclosing_node_task(cx)
 7994            // Or find the task that's closest in row-distance.
 7995            .or_else(|| self.find_closest_task(cx))
 7996        else {
 7997            return;
 7998        };
 7999
 8000        let reveal_strategy = action.reveal;
 8001        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8002        cx.spawn_in(window, async move |_, cx| {
 8003            let context = task_context.await?;
 8004            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8005
 8006            let resolved = &mut resolved_task.resolved;
 8007            resolved.reveal = reveal_strategy;
 8008
 8009            workspace
 8010                .update_in(cx, |workspace, window, cx| {
 8011                    workspace.schedule_resolved_task(
 8012                        task_source_kind,
 8013                        resolved_task,
 8014                        false,
 8015                        window,
 8016                        cx,
 8017                    );
 8018                })
 8019                .ok()
 8020        })
 8021        .detach();
 8022    }
 8023
 8024    fn find_closest_task(
 8025        &mut self,
 8026        cx: &mut Context<Self>,
 8027    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8028        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8029
 8030        let ((buffer_id, row), tasks) = self
 8031            .tasks
 8032            .iter()
 8033            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8034
 8035        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8036        let tasks = Arc::new(tasks.to_owned());
 8037        Some((buffer, *row, tasks))
 8038    }
 8039
 8040    fn find_enclosing_node_task(
 8041        &mut self,
 8042        cx: &mut Context<Self>,
 8043    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8044        let snapshot = self.buffer.read(cx).snapshot(cx);
 8045        let offset = self.selections.newest::<usize>(cx).head();
 8046        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8047        let buffer_id = excerpt.buffer().remote_id();
 8048
 8049        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8050        let mut cursor = layer.node().walk();
 8051
 8052        while cursor.goto_first_child_for_byte(offset).is_some() {
 8053            if cursor.node().end_byte() == offset {
 8054                cursor.goto_next_sibling();
 8055            }
 8056        }
 8057
 8058        // Ascend to the smallest ancestor that contains the range and has a task.
 8059        loop {
 8060            let node = cursor.node();
 8061            let node_range = node.byte_range();
 8062            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8063
 8064            // Check if this node contains our offset
 8065            if node_range.start <= offset && node_range.end >= offset {
 8066                // If it contains offset, check for task
 8067                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8068                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8069                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8070                }
 8071            }
 8072
 8073            if !cursor.goto_parent() {
 8074                break;
 8075            }
 8076        }
 8077        None
 8078    }
 8079
 8080    fn render_run_indicator(
 8081        &self,
 8082        _style: &EditorStyle,
 8083        is_active: bool,
 8084        row: DisplayRow,
 8085        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8086        cx: &mut Context<Self>,
 8087    ) -> IconButton {
 8088        let color = Color::Muted;
 8089        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8090
 8091        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8092            .shape(ui::IconButtonShape::Square)
 8093            .icon_size(IconSize::XSmall)
 8094            .icon_color(color)
 8095            .toggle_state(is_active)
 8096            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8097                let quick_launch = e.down.button == MouseButton::Left;
 8098                window.focus(&editor.focus_handle(cx));
 8099                editor.toggle_code_actions(
 8100                    &ToggleCodeActions {
 8101                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8102                        quick_launch,
 8103                    },
 8104                    window,
 8105                    cx,
 8106                );
 8107            }))
 8108            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8109                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8110            }))
 8111    }
 8112
 8113    pub fn context_menu_visible(&self) -> bool {
 8114        !self.edit_prediction_preview_is_active()
 8115            && self
 8116                .context_menu
 8117                .borrow()
 8118                .as_ref()
 8119                .map_or(false, |menu| menu.visible())
 8120    }
 8121
 8122    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8123        self.context_menu
 8124            .borrow()
 8125            .as_ref()
 8126            .map(|menu| menu.origin())
 8127    }
 8128
 8129    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8130        self.context_menu_options = Some(options);
 8131    }
 8132
 8133    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8134    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8135
 8136    fn render_edit_prediction_popover(
 8137        &mut self,
 8138        text_bounds: &Bounds<Pixels>,
 8139        content_origin: gpui::Point<Pixels>,
 8140        right_margin: Pixels,
 8141        editor_snapshot: &EditorSnapshot,
 8142        visible_row_range: Range<DisplayRow>,
 8143        scroll_top: f32,
 8144        scroll_bottom: f32,
 8145        line_layouts: &[LineWithInvisibles],
 8146        line_height: Pixels,
 8147        scroll_pixel_position: gpui::Point<Pixels>,
 8148        newest_selection_head: Option<DisplayPoint>,
 8149        editor_width: Pixels,
 8150        style: &EditorStyle,
 8151        window: &mut Window,
 8152        cx: &mut App,
 8153    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8154        if self.mode().is_minimap() {
 8155            return None;
 8156        }
 8157        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8158
 8159        if self.edit_prediction_visible_in_cursor_popover(true) {
 8160            return None;
 8161        }
 8162
 8163        match &active_inline_completion.completion {
 8164            InlineCompletion::Move { target, .. } => {
 8165                let target_display_point = target.to_display_point(editor_snapshot);
 8166
 8167                if self.edit_prediction_requires_modifier() {
 8168                    if !self.edit_prediction_preview_is_active() {
 8169                        return None;
 8170                    }
 8171
 8172                    self.render_edit_prediction_modifier_jump_popover(
 8173                        text_bounds,
 8174                        content_origin,
 8175                        visible_row_range,
 8176                        line_layouts,
 8177                        line_height,
 8178                        scroll_pixel_position,
 8179                        newest_selection_head,
 8180                        target_display_point,
 8181                        window,
 8182                        cx,
 8183                    )
 8184                } else {
 8185                    self.render_edit_prediction_eager_jump_popover(
 8186                        text_bounds,
 8187                        content_origin,
 8188                        editor_snapshot,
 8189                        visible_row_range,
 8190                        scroll_top,
 8191                        scroll_bottom,
 8192                        line_height,
 8193                        scroll_pixel_position,
 8194                        target_display_point,
 8195                        editor_width,
 8196                        window,
 8197                        cx,
 8198                    )
 8199                }
 8200            }
 8201            InlineCompletion::Edit {
 8202                display_mode: EditDisplayMode::Inline,
 8203                ..
 8204            } => None,
 8205            InlineCompletion::Edit {
 8206                display_mode: EditDisplayMode::TabAccept,
 8207                edits,
 8208                ..
 8209            } => {
 8210                let range = &edits.first()?.0;
 8211                let target_display_point = range.end.to_display_point(editor_snapshot);
 8212
 8213                self.render_edit_prediction_end_of_line_popover(
 8214                    "Accept",
 8215                    editor_snapshot,
 8216                    visible_row_range,
 8217                    target_display_point,
 8218                    line_height,
 8219                    scroll_pixel_position,
 8220                    content_origin,
 8221                    editor_width,
 8222                    window,
 8223                    cx,
 8224                )
 8225            }
 8226            InlineCompletion::Edit {
 8227                edits,
 8228                edit_preview,
 8229                display_mode: EditDisplayMode::DiffPopover,
 8230                snapshot,
 8231            } => self.render_edit_prediction_diff_popover(
 8232                text_bounds,
 8233                content_origin,
 8234                right_margin,
 8235                editor_snapshot,
 8236                visible_row_range,
 8237                line_layouts,
 8238                line_height,
 8239                scroll_pixel_position,
 8240                newest_selection_head,
 8241                editor_width,
 8242                style,
 8243                edits,
 8244                edit_preview,
 8245                snapshot,
 8246                window,
 8247                cx,
 8248            ),
 8249        }
 8250    }
 8251
 8252    fn render_edit_prediction_modifier_jump_popover(
 8253        &mut self,
 8254        text_bounds: &Bounds<Pixels>,
 8255        content_origin: gpui::Point<Pixels>,
 8256        visible_row_range: Range<DisplayRow>,
 8257        line_layouts: &[LineWithInvisibles],
 8258        line_height: Pixels,
 8259        scroll_pixel_position: gpui::Point<Pixels>,
 8260        newest_selection_head: Option<DisplayPoint>,
 8261        target_display_point: DisplayPoint,
 8262        window: &mut Window,
 8263        cx: &mut App,
 8264    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8265        let scrolled_content_origin =
 8266            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8267
 8268        const SCROLL_PADDING_Y: Pixels = px(12.);
 8269
 8270        if target_display_point.row() < visible_row_range.start {
 8271            return self.render_edit_prediction_scroll_popover(
 8272                |_| SCROLL_PADDING_Y,
 8273                IconName::ArrowUp,
 8274                visible_row_range,
 8275                line_layouts,
 8276                newest_selection_head,
 8277                scrolled_content_origin,
 8278                window,
 8279                cx,
 8280            );
 8281        } else if target_display_point.row() >= visible_row_range.end {
 8282            return self.render_edit_prediction_scroll_popover(
 8283                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8284                IconName::ArrowDown,
 8285                visible_row_range,
 8286                line_layouts,
 8287                newest_selection_head,
 8288                scrolled_content_origin,
 8289                window,
 8290                cx,
 8291            );
 8292        }
 8293
 8294        const POLE_WIDTH: Pixels = px(2.);
 8295
 8296        let line_layout =
 8297            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8298        let target_column = target_display_point.column() as usize;
 8299
 8300        let target_x = line_layout.x_for_index(target_column);
 8301        let target_y =
 8302            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8303
 8304        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8305
 8306        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8307        border_color.l += 0.001;
 8308
 8309        let mut element = v_flex()
 8310            .items_end()
 8311            .when(flag_on_right, |el| el.items_start())
 8312            .child(if flag_on_right {
 8313                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8314                    .rounded_bl(px(0.))
 8315                    .rounded_tl(px(0.))
 8316                    .border_l_2()
 8317                    .border_color(border_color)
 8318            } else {
 8319                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8320                    .rounded_br(px(0.))
 8321                    .rounded_tr(px(0.))
 8322                    .border_r_2()
 8323                    .border_color(border_color)
 8324            })
 8325            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8326            .into_any();
 8327
 8328        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8329
 8330        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8331            - point(
 8332                if flag_on_right {
 8333                    POLE_WIDTH
 8334                } else {
 8335                    size.width - POLE_WIDTH
 8336                },
 8337                size.height - line_height,
 8338            );
 8339
 8340        origin.x = origin.x.max(content_origin.x);
 8341
 8342        element.prepaint_at(origin, window, cx);
 8343
 8344        Some((element, origin))
 8345    }
 8346
 8347    fn render_edit_prediction_scroll_popover(
 8348        &mut self,
 8349        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8350        scroll_icon: IconName,
 8351        visible_row_range: Range<DisplayRow>,
 8352        line_layouts: &[LineWithInvisibles],
 8353        newest_selection_head: Option<DisplayPoint>,
 8354        scrolled_content_origin: gpui::Point<Pixels>,
 8355        window: &mut Window,
 8356        cx: &mut App,
 8357    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8358        let mut element = self
 8359            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8360            .into_any();
 8361
 8362        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8363
 8364        let cursor = newest_selection_head?;
 8365        let cursor_row_layout =
 8366            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8367        let cursor_column = cursor.column() as usize;
 8368
 8369        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8370
 8371        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8372
 8373        element.prepaint_at(origin, window, cx);
 8374        Some((element, origin))
 8375    }
 8376
 8377    fn render_edit_prediction_eager_jump_popover(
 8378        &mut self,
 8379        text_bounds: &Bounds<Pixels>,
 8380        content_origin: gpui::Point<Pixels>,
 8381        editor_snapshot: &EditorSnapshot,
 8382        visible_row_range: Range<DisplayRow>,
 8383        scroll_top: f32,
 8384        scroll_bottom: f32,
 8385        line_height: Pixels,
 8386        scroll_pixel_position: gpui::Point<Pixels>,
 8387        target_display_point: DisplayPoint,
 8388        editor_width: Pixels,
 8389        window: &mut Window,
 8390        cx: &mut App,
 8391    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8392        if target_display_point.row().as_f32() < scroll_top {
 8393            let mut element = self
 8394                .render_edit_prediction_line_popover(
 8395                    "Jump to Edit",
 8396                    Some(IconName::ArrowUp),
 8397                    window,
 8398                    cx,
 8399                )?
 8400                .into_any();
 8401
 8402            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8403            let offset = point(
 8404                (text_bounds.size.width - size.width) / 2.,
 8405                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8406            );
 8407
 8408            let origin = text_bounds.origin + offset;
 8409            element.prepaint_at(origin, window, cx);
 8410            Some((element, origin))
 8411        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8412            let mut element = self
 8413                .render_edit_prediction_line_popover(
 8414                    "Jump to Edit",
 8415                    Some(IconName::ArrowDown),
 8416                    window,
 8417                    cx,
 8418                )?
 8419                .into_any();
 8420
 8421            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8422            let offset = point(
 8423                (text_bounds.size.width - size.width) / 2.,
 8424                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8425            );
 8426
 8427            let origin = text_bounds.origin + offset;
 8428            element.prepaint_at(origin, window, cx);
 8429            Some((element, origin))
 8430        } else {
 8431            self.render_edit_prediction_end_of_line_popover(
 8432                "Jump to Edit",
 8433                editor_snapshot,
 8434                visible_row_range,
 8435                target_display_point,
 8436                line_height,
 8437                scroll_pixel_position,
 8438                content_origin,
 8439                editor_width,
 8440                window,
 8441                cx,
 8442            )
 8443        }
 8444    }
 8445
 8446    fn render_edit_prediction_end_of_line_popover(
 8447        self: &mut Editor,
 8448        label: &'static str,
 8449        editor_snapshot: &EditorSnapshot,
 8450        visible_row_range: Range<DisplayRow>,
 8451        target_display_point: DisplayPoint,
 8452        line_height: Pixels,
 8453        scroll_pixel_position: gpui::Point<Pixels>,
 8454        content_origin: gpui::Point<Pixels>,
 8455        editor_width: Pixels,
 8456        window: &mut Window,
 8457        cx: &mut App,
 8458    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8459        let target_line_end = DisplayPoint::new(
 8460            target_display_point.row(),
 8461            editor_snapshot.line_len(target_display_point.row()),
 8462        );
 8463
 8464        let mut element = self
 8465            .render_edit_prediction_line_popover(label, None, window, cx)?
 8466            .into_any();
 8467
 8468        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8469
 8470        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8471
 8472        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8473        let mut origin = start_point
 8474            + line_origin
 8475            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8476        origin.x = origin.x.max(content_origin.x);
 8477
 8478        let max_x = content_origin.x + editor_width - size.width;
 8479
 8480        if origin.x > max_x {
 8481            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8482
 8483            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8484                origin.y += offset;
 8485                IconName::ArrowUp
 8486            } else {
 8487                origin.y -= offset;
 8488                IconName::ArrowDown
 8489            };
 8490
 8491            element = self
 8492                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8493                .into_any();
 8494
 8495            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8496
 8497            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8498        }
 8499
 8500        element.prepaint_at(origin, window, cx);
 8501        Some((element, origin))
 8502    }
 8503
 8504    fn render_edit_prediction_diff_popover(
 8505        self: &Editor,
 8506        text_bounds: &Bounds<Pixels>,
 8507        content_origin: gpui::Point<Pixels>,
 8508        right_margin: Pixels,
 8509        editor_snapshot: &EditorSnapshot,
 8510        visible_row_range: Range<DisplayRow>,
 8511        line_layouts: &[LineWithInvisibles],
 8512        line_height: Pixels,
 8513        scroll_pixel_position: gpui::Point<Pixels>,
 8514        newest_selection_head: Option<DisplayPoint>,
 8515        editor_width: Pixels,
 8516        style: &EditorStyle,
 8517        edits: &Vec<(Range<Anchor>, String)>,
 8518        edit_preview: &Option<language::EditPreview>,
 8519        snapshot: &language::BufferSnapshot,
 8520        window: &mut Window,
 8521        cx: &mut App,
 8522    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8523        let edit_start = edits
 8524            .first()
 8525            .unwrap()
 8526            .0
 8527            .start
 8528            .to_display_point(editor_snapshot);
 8529        let edit_end = edits
 8530            .last()
 8531            .unwrap()
 8532            .0
 8533            .end
 8534            .to_display_point(editor_snapshot);
 8535
 8536        let is_visible = visible_row_range.contains(&edit_start.row())
 8537            || visible_row_range.contains(&edit_end.row());
 8538        if !is_visible {
 8539            return None;
 8540        }
 8541
 8542        let highlighted_edits =
 8543            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8544
 8545        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8546        let line_count = highlighted_edits.text.lines().count();
 8547
 8548        const BORDER_WIDTH: Pixels = px(1.);
 8549
 8550        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8551        let has_keybind = keybind.is_some();
 8552
 8553        let mut element = h_flex()
 8554            .items_start()
 8555            .child(
 8556                h_flex()
 8557                    .bg(cx.theme().colors().editor_background)
 8558                    .border(BORDER_WIDTH)
 8559                    .shadow_sm()
 8560                    .border_color(cx.theme().colors().border)
 8561                    .rounded_l_lg()
 8562                    .when(line_count > 1, |el| el.rounded_br_lg())
 8563                    .pr_1()
 8564                    .child(styled_text),
 8565            )
 8566            .child(
 8567                h_flex()
 8568                    .h(line_height + BORDER_WIDTH * 2.)
 8569                    .px_1p5()
 8570                    .gap_1()
 8571                    // Workaround: For some reason, there's a gap if we don't do this
 8572                    .ml(-BORDER_WIDTH)
 8573                    .shadow(vec![gpui::BoxShadow {
 8574                        color: gpui::black().opacity(0.05),
 8575                        offset: point(px(1.), px(1.)),
 8576                        blur_radius: px(2.),
 8577                        spread_radius: px(0.),
 8578                    }])
 8579                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8580                    .border(BORDER_WIDTH)
 8581                    .border_color(cx.theme().colors().border)
 8582                    .rounded_r_lg()
 8583                    .id("edit_prediction_diff_popover_keybind")
 8584                    .when(!has_keybind, |el| {
 8585                        let status_colors = cx.theme().status();
 8586
 8587                        el.bg(status_colors.error_background)
 8588                            .border_color(status_colors.error.opacity(0.6))
 8589                            .child(Icon::new(IconName::Info).color(Color::Error))
 8590                            .cursor_default()
 8591                            .hoverable_tooltip(move |_window, cx| {
 8592                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8593                            })
 8594                    })
 8595                    .children(keybind),
 8596            )
 8597            .into_any();
 8598
 8599        let longest_row =
 8600            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8601        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8602            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8603        } else {
 8604            layout_line(
 8605                longest_row,
 8606                editor_snapshot,
 8607                style,
 8608                editor_width,
 8609                |_| false,
 8610                window,
 8611                cx,
 8612            )
 8613            .width
 8614        };
 8615
 8616        let viewport_bounds =
 8617            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8618                right: -right_margin,
 8619                ..Default::default()
 8620            });
 8621
 8622        let x_after_longest =
 8623            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8624                - scroll_pixel_position.x;
 8625
 8626        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8627
 8628        // Fully visible if it can be displayed within the window (allow overlapping other
 8629        // panes). However, this is only allowed if the popover starts within text_bounds.
 8630        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8631            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8632
 8633        let mut origin = if can_position_to_the_right {
 8634            point(
 8635                x_after_longest,
 8636                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8637                    - scroll_pixel_position.y,
 8638            )
 8639        } else {
 8640            let cursor_row = newest_selection_head.map(|head| head.row());
 8641            let above_edit = edit_start
 8642                .row()
 8643                .0
 8644                .checked_sub(line_count as u32)
 8645                .map(DisplayRow);
 8646            let below_edit = Some(edit_end.row() + 1);
 8647            let above_cursor =
 8648                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8649            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8650
 8651            // Place the edit popover adjacent to the edit if there is a location
 8652            // available that is onscreen and does not obscure the cursor. Otherwise,
 8653            // place it adjacent to the cursor.
 8654            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8655                .into_iter()
 8656                .flatten()
 8657                .find(|&start_row| {
 8658                    let end_row = start_row + line_count as u32;
 8659                    visible_row_range.contains(&start_row)
 8660                        && visible_row_range.contains(&end_row)
 8661                        && cursor_row.map_or(true, |cursor_row| {
 8662                            !((start_row..end_row).contains(&cursor_row))
 8663                        })
 8664                })?;
 8665
 8666            content_origin
 8667                + point(
 8668                    -scroll_pixel_position.x,
 8669                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8670                )
 8671        };
 8672
 8673        origin.x -= BORDER_WIDTH;
 8674
 8675        window.defer_draw(element, origin, 1);
 8676
 8677        // Do not return an element, since it will already be drawn due to defer_draw.
 8678        None
 8679    }
 8680
 8681    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8682        px(30.)
 8683    }
 8684
 8685    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8686        if self.read_only(cx) {
 8687            cx.theme().players().read_only()
 8688        } else {
 8689            self.style.as_ref().unwrap().local_player
 8690        }
 8691    }
 8692
 8693    fn render_edit_prediction_accept_keybind(
 8694        &self,
 8695        window: &mut Window,
 8696        cx: &App,
 8697    ) -> Option<AnyElement> {
 8698        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8699        let accept_keystroke = accept_binding.keystroke()?;
 8700
 8701        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8702
 8703        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8704            Color::Accent
 8705        } else {
 8706            Color::Muted
 8707        };
 8708
 8709        h_flex()
 8710            .px_0p5()
 8711            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8712            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8713            .text_size(TextSize::XSmall.rems(cx))
 8714            .child(h_flex().children(ui::render_modifiers(
 8715                &accept_keystroke.modifiers,
 8716                PlatformStyle::platform(),
 8717                Some(modifiers_color),
 8718                Some(IconSize::XSmall.rems().into()),
 8719                true,
 8720            )))
 8721            .when(is_platform_style_mac, |parent| {
 8722                parent.child(accept_keystroke.key.clone())
 8723            })
 8724            .when(!is_platform_style_mac, |parent| {
 8725                parent.child(
 8726                    Key::new(
 8727                        util::capitalize(&accept_keystroke.key),
 8728                        Some(Color::Default),
 8729                    )
 8730                    .size(Some(IconSize::XSmall.rems().into())),
 8731                )
 8732            })
 8733            .into_any()
 8734            .into()
 8735    }
 8736
 8737    fn render_edit_prediction_line_popover(
 8738        &self,
 8739        label: impl Into<SharedString>,
 8740        icon: Option<IconName>,
 8741        window: &mut Window,
 8742        cx: &App,
 8743    ) -> Option<Stateful<Div>> {
 8744        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8745
 8746        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8747        let has_keybind = keybind.is_some();
 8748
 8749        let result = h_flex()
 8750            .id("ep-line-popover")
 8751            .py_0p5()
 8752            .pl_1()
 8753            .pr(padding_right)
 8754            .gap_1()
 8755            .rounded_md()
 8756            .border_1()
 8757            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8758            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8759            .shadow_sm()
 8760            .when(!has_keybind, |el| {
 8761                let status_colors = cx.theme().status();
 8762
 8763                el.bg(status_colors.error_background)
 8764                    .border_color(status_colors.error.opacity(0.6))
 8765                    .pl_2()
 8766                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8767                    .cursor_default()
 8768                    .hoverable_tooltip(move |_window, cx| {
 8769                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8770                    })
 8771            })
 8772            .children(keybind)
 8773            .child(
 8774                Label::new(label)
 8775                    .size(LabelSize::Small)
 8776                    .when(!has_keybind, |el| {
 8777                        el.color(cx.theme().status().error.into()).strikethrough()
 8778                    }),
 8779            )
 8780            .when(!has_keybind, |el| {
 8781                el.child(
 8782                    h_flex().ml_1().child(
 8783                        Icon::new(IconName::Info)
 8784                            .size(IconSize::Small)
 8785                            .color(cx.theme().status().error.into()),
 8786                    ),
 8787                )
 8788            })
 8789            .when_some(icon, |element, icon| {
 8790                element.child(
 8791                    div()
 8792                        .mt(px(1.5))
 8793                        .child(Icon::new(icon).size(IconSize::Small)),
 8794                )
 8795            });
 8796
 8797        Some(result)
 8798    }
 8799
 8800    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8801        let accent_color = cx.theme().colors().text_accent;
 8802        let editor_bg_color = cx.theme().colors().editor_background;
 8803        editor_bg_color.blend(accent_color.opacity(0.1))
 8804    }
 8805
 8806    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8807        let accent_color = cx.theme().colors().text_accent;
 8808        let editor_bg_color = cx.theme().colors().editor_background;
 8809        editor_bg_color.blend(accent_color.opacity(0.6))
 8810    }
 8811
 8812    fn render_edit_prediction_cursor_popover(
 8813        &self,
 8814        min_width: Pixels,
 8815        max_width: Pixels,
 8816        cursor_point: Point,
 8817        style: &EditorStyle,
 8818        accept_keystroke: Option<&gpui::Keystroke>,
 8819        _window: &Window,
 8820        cx: &mut Context<Editor>,
 8821    ) -> Option<AnyElement> {
 8822        let provider = self.edit_prediction_provider.as_ref()?;
 8823
 8824        if provider.provider.needs_terms_acceptance(cx) {
 8825            return Some(
 8826                h_flex()
 8827                    .min_w(min_width)
 8828                    .flex_1()
 8829                    .px_2()
 8830                    .py_1()
 8831                    .gap_3()
 8832                    .elevation_2(cx)
 8833                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8834                    .id("accept-terms")
 8835                    .cursor_pointer()
 8836                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8837                    .on_click(cx.listener(|this, _event, window, cx| {
 8838                        cx.stop_propagation();
 8839                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8840                        window.dispatch_action(
 8841                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8842                            cx,
 8843                        );
 8844                    }))
 8845                    .child(
 8846                        h_flex()
 8847                            .flex_1()
 8848                            .gap_2()
 8849                            .child(Icon::new(IconName::ZedPredict))
 8850                            .child(Label::new("Accept Terms of Service"))
 8851                            .child(div().w_full())
 8852                            .child(
 8853                                Icon::new(IconName::ArrowUpRight)
 8854                                    .color(Color::Muted)
 8855                                    .size(IconSize::Small),
 8856                            )
 8857                            .into_any_element(),
 8858                    )
 8859                    .into_any(),
 8860            );
 8861        }
 8862
 8863        let is_refreshing = provider.provider.is_refreshing(cx);
 8864
 8865        fn pending_completion_container() -> Div {
 8866            h_flex()
 8867                .h_full()
 8868                .flex_1()
 8869                .gap_2()
 8870                .child(Icon::new(IconName::ZedPredict))
 8871        }
 8872
 8873        let completion = match &self.active_inline_completion {
 8874            Some(prediction) => {
 8875                if !self.has_visible_completions_menu() {
 8876                    const RADIUS: Pixels = px(6.);
 8877                    const BORDER_WIDTH: Pixels = px(1.);
 8878
 8879                    return Some(
 8880                        h_flex()
 8881                            .elevation_2(cx)
 8882                            .border(BORDER_WIDTH)
 8883                            .border_color(cx.theme().colors().border)
 8884                            .when(accept_keystroke.is_none(), |el| {
 8885                                el.border_color(cx.theme().status().error)
 8886                            })
 8887                            .rounded(RADIUS)
 8888                            .rounded_tl(px(0.))
 8889                            .overflow_hidden()
 8890                            .child(div().px_1p5().child(match &prediction.completion {
 8891                                InlineCompletion::Move { target, snapshot } => {
 8892                                    use text::ToPoint as _;
 8893                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8894                                    {
 8895                                        Icon::new(IconName::ZedPredictDown)
 8896                                    } else {
 8897                                        Icon::new(IconName::ZedPredictUp)
 8898                                    }
 8899                                }
 8900                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8901                            }))
 8902                            .child(
 8903                                h_flex()
 8904                                    .gap_1()
 8905                                    .py_1()
 8906                                    .px_2()
 8907                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8908                                    .border_l_1()
 8909                                    .border_color(cx.theme().colors().border)
 8910                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8911                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8912                                        el.child(
 8913                                            Label::new("Hold")
 8914                                                .size(LabelSize::Small)
 8915                                                .when(accept_keystroke.is_none(), |el| {
 8916                                                    el.strikethrough()
 8917                                                })
 8918                                                .line_height_style(LineHeightStyle::UiLabel),
 8919                                        )
 8920                                    })
 8921                                    .id("edit_prediction_cursor_popover_keybind")
 8922                                    .when(accept_keystroke.is_none(), |el| {
 8923                                        let status_colors = cx.theme().status();
 8924
 8925                                        el.bg(status_colors.error_background)
 8926                                            .border_color(status_colors.error.opacity(0.6))
 8927                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8928                                            .cursor_default()
 8929                                            .hoverable_tooltip(move |_window, cx| {
 8930                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8931                                                    .into()
 8932                                            })
 8933                                    })
 8934                                    .when_some(
 8935                                        accept_keystroke.as_ref(),
 8936                                        |el, accept_keystroke| {
 8937                                            el.child(h_flex().children(ui::render_modifiers(
 8938                                                &accept_keystroke.modifiers,
 8939                                                PlatformStyle::platform(),
 8940                                                Some(Color::Default),
 8941                                                Some(IconSize::XSmall.rems().into()),
 8942                                                false,
 8943                                            )))
 8944                                        },
 8945                                    ),
 8946                            )
 8947                            .into_any(),
 8948                    );
 8949                }
 8950
 8951                self.render_edit_prediction_cursor_popover_preview(
 8952                    prediction,
 8953                    cursor_point,
 8954                    style,
 8955                    cx,
 8956                )?
 8957            }
 8958
 8959            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8960                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8961                    stale_completion,
 8962                    cursor_point,
 8963                    style,
 8964                    cx,
 8965                )?,
 8966
 8967                None => {
 8968                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8969                }
 8970            },
 8971
 8972            None => pending_completion_container().child(Label::new("No Prediction")),
 8973        };
 8974
 8975        let completion = if is_refreshing {
 8976            completion
 8977                .with_animation(
 8978                    "loading-completion",
 8979                    Animation::new(Duration::from_secs(2))
 8980                        .repeat()
 8981                        .with_easing(pulsating_between(0.4, 0.8)),
 8982                    |label, delta| label.opacity(delta),
 8983                )
 8984                .into_any_element()
 8985        } else {
 8986            completion.into_any_element()
 8987        };
 8988
 8989        let has_completion = self.active_inline_completion.is_some();
 8990
 8991        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8992        Some(
 8993            h_flex()
 8994                .min_w(min_width)
 8995                .max_w(max_width)
 8996                .flex_1()
 8997                .elevation_2(cx)
 8998                .border_color(cx.theme().colors().border)
 8999                .child(
 9000                    div()
 9001                        .flex_1()
 9002                        .py_1()
 9003                        .px_2()
 9004                        .overflow_hidden()
 9005                        .child(completion),
 9006                )
 9007                .when_some(accept_keystroke, |el, accept_keystroke| {
 9008                    if !accept_keystroke.modifiers.modified() {
 9009                        return el;
 9010                    }
 9011
 9012                    el.child(
 9013                        h_flex()
 9014                            .h_full()
 9015                            .border_l_1()
 9016                            .rounded_r_lg()
 9017                            .border_color(cx.theme().colors().border)
 9018                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9019                            .gap_1()
 9020                            .py_1()
 9021                            .px_2()
 9022                            .child(
 9023                                h_flex()
 9024                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9025                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9026                                    .child(h_flex().children(ui::render_modifiers(
 9027                                        &accept_keystroke.modifiers,
 9028                                        PlatformStyle::platform(),
 9029                                        Some(if !has_completion {
 9030                                            Color::Muted
 9031                                        } else {
 9032                                            Color::Default
 9033                                        }),
 9034                                        None,
 9035                                        false,
 9036                                    ))),
 9037                            )
 9038                            .child(Label::new("Preview").into_any_element())
 9039                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9040                    )
 9041                })
 9042                .into_any(),
 9043        )
 9044    }
 9045
 9046    fn render_edit_prediction_cursor_popover_preview(
 9047        &self,
 9048        completion: &InlineCompletionState,
 9049        cursor_point: Point,
 9050        style: &EditorStyle,
 9051        cx: &mut Context<Editor>,
 9052    ) -> Option<Div> {
 9053        use text::ToPoint as _;
 9054
 9055        fn render_relative_row_jump(
 9056            prefix: impl Into<String>,
 9057            current_row: u32,
 9058            target_row: u32,
 9059        ) -> Div {
 9060            let (row_diff, arrow) = if target_row < current_row {
 9061                (current_row - target_row, IconName::ArrowUp)
 9062            } else {
 9063                (target_row - current_row, IconName::ArrowDown)
 9064            };
 9065
 9066            h_flex()
 9067                .child(
 9068                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9069                        .color(Color::Muted)
 9070                        .size(LabelSize::Small),
 9071                )
 9072                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9073        }
 9074
 9075        match &completion.completion {
 9076            InlineCompletion::Move {
 9077                target, snapshot, ..
 9078            } => Some(
 9079                h_flex()
 9080                    .px_2()
 9081                    .gap_2()
 9082                    .flex_1()
 9083                    .child(
 9084                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9085                            Icon::new(IconName::ZedPredictDown)
 9086                        } else {
 9087                            Icon::new(IconName::ZedPredictUp)
 9088                        },
 9089                    )
 9090                    .child(Label::new("Jump to Edit")),
 9091            ),
 9092
 9093            InlineCompletion::Edit {
 9094                edits,
 9095                edit_preview,
 9096                snapshot,
 9097                display_mode: _,
 9098            } => {
 9099                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9100
 9101                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9102                    &snapshot,
 9103                    &edits,
 9104                    edit_preview.as_ref()?,
 9105                    true,
 9106                    cx,
 9107                )
 9108                .first_line_preview();
 9109
 9110                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9111                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9112
 9113                let preview = h_flex()
 9114                    .gap_1()
 9115                    .min_w_16()
 9116                    .child(styled_text)
 9117                    .when(has_more_lines, |parent| parent.child(""));
 9118
 9119                let left = if first_edit_row != cursor_point.row {
 9120                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9121                        .into_any_element()
 9122                } else {
 9123                    Icon::new(IconName::ZedPredict).into_any_element()
 9124                };
 9125
 9126                Some(
 9127                    h_flex()
 9128                        .h_full()
 9129                        .flex_1()
 9130                        .gap_2()
 9131                        .pr_1()
 9132                        .overflow_x_hidden()
 9133                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9134                        .child(left)
 9135                        .child(preview),
 9136                )
 9137            }
 9138        }
 9139    }
 9140
 9141    pub fn render_context_menu(
 9142        &self,
 9143        style: &EditorStyle,
 9144        max_height_in_lines: u32,
 9145        window: &mut Window,
 9146        cx: &mut Context<Editor>,
 9147    ) -> Option<AnyElement> {
 9148        let menu = self.context_menu.borrow();
 9149        let menu = menu.as_ref()?;
 9150        if !menu.visible() {
 9151            return None;
 9152        };
 9153        Some(menu.render(style, max_height_in_lines, window, cx))
 9154    }
 9155
 9156    fn render_context_menu_aside(
 9157        &mut self,
 9158        max_size: Size<Pixels>,
 9159        window: &mut Window,
 9160        cx: &mut Context<Editor>,
 9161    ) -> Option<AnyElement> {
 9162        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9163            if menu.visible() {
 9164                menu.render_aside(max_size, window, cx)
 9165            } else {
 9166                None
 9167            }
 9168        })
 9169    }
 9170
 9171    fn hide_context_menu(
 9172        &mut self,
 9173        window: &mut Window,
 9174        cx: &mut Context<Self>,
 9175    ) -> Option<CodeContextMenu> {
 9176        cx.notify();
 9177        self.completion_tasks.clear();
 9178        let context_menu = self.context_menu.borrow_mut().take();
 9179        self.stale_inline_completion_in_menu.take();
 9180        self.update_visible_inline_completion(window, cx);
 9181        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9182            if let Some(completion_provider) = &self.completion_provider {
 9183                completion_provider.selection_changed(None, window, cx);
 9184            }
 9185        }
 9186        context_menu
 9187    }
 9188
 9189    fn show_snippet_choices(
 9190        &mut self,
 9191        choices: &Vec<String>,
 9192        selection: Range<Anchor>,
 9193        cx: &mut Context<Self>,
 9194    ) {
 9195        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9196            (Some(a), Some(b)) if a == b => a,
 9197            _ => {
 9198                log::error!("expected anchor range to have matching buffer IDs");
 9199                return;
 9200            }
 9201        };
 9202        let multi_buffer = self.buffer().read(cx);
 9203        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9204            return;
 9205        };
 9206
 9207        let id = post_inc(&mut self.next_completion_id);
 9208        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9209        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9210            CompletionsMenu::new_snippet_choices(
 9211                id,
 9212                true,
 9213                choices,
 9214                selection,
 9215                buffer,
 9216                snippet_sort_order,
 9217            ),
 9218        ));
 9219    }
 9220
 9221    pub fn insert_snippet(
 9222        &mut self,
 9223        insertion_ranges: &[Range<usize>],
 9224        snippet: Snippet,
 9225        window: &mut Window,
 9226        cx: &mut Context<Self>,
 9227    ) -> Result<()> {
 9228        struct Tabstop<T> {
 9229            is_end_tabstop: bool,
 9230            ranges: Vec<Range<T>>,
 9231            choices: Option<Vec<String>>,
 9232        }
 9233
 9234        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9235            let snippet_text: Arc<str> = snippet.text.clone().into();
 9236            let edits = insertion_ranges
 9237                .iter()
 9238                .cloned()
 9239                .map(|range| (range, snippet_text.clone()));
 9240            let autoindent_mode = AutoindentMode::Block {
 9241                original_indent_columns: Vec::new(),
 9242            };
 9243            buffer.edit(edits, Some(autoindent_mode), cx);
 9244
 9245            let snapshot = &*buffer.read(cx);
 9246            let snippet = &snippet;
 9247            snippet
 9248                .tabstops
 9249                .iter()
 9250                .map(|tabstop| {
 9251                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9252                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9253                    });
 9254                    let mut tabstop_ranges = tabstop
 9255                        .ranges
 9256                        .iter()
 9257                        .flat_map(|tabstop_range| {
 9258                            let mut delta = 0_isize;
 9259                            insertion_ranges.iter().map(move |insertion_range| {
 9260                                let insertion_start = insertion_range.start as isize + delta;
 9261                                delta +=
 9262                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9263
 9264                                let start = ((insertion_start + tabstop_range.start) as usize)
 9265                                    .min(snapshot.len());
 9266                                let end = ((insertion_start + tabstop_range.end) as usize)
 9267                                    .min(snapshot.len());
 9268                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9269                            })
 9270                        })
 9271                        .collect::<Vec<_>>();
 9272                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9273
 9274                    Tabstop {
 9275                        is_end_tabstop,
 9276                        ranges: tabstop_ranges,
 9277                        choices: tabstop.choices.clone(),
 9278                    }
 9279                })
 9280                .collect::<Vec<_>>()
 9281        });
 9282        if let Some(tabstop) = tabstops.first() {
 9283            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9284                // Reverse order so that the first range is the newest created selection.
 9285                // Completions will use it and autoscroll will prioritize it.
 9286                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9287            });
 9288
 9289            if let Some(choices) = &tabstop.choices {
 9290                if let Some(selection) = tabstop.ranges.first() {
 9291                    self.show_snippet_choices(choices, selection.clone(), cx)
 9292                }
 9293            }
 9294
 9295            // If we're already at the last tabstop and it's at the end of the snippet,
 9296            // we're done, we don't need to keep the state around.
 9297            if !tabstop.is_end_tabstop {
 9298                let choices = tabstops
 9299                    .iter()
 9300                    .map(|tabstop| tabstop.choices.clone())
 9301                    .collect();
 9302
 9303                let ranges = tabstops
 9304                    .into_iter()
 9305                    .map(|tabstop| tabstop.ranges)
 9306                    .collect::<Vec<_>>();
 9307
 9308                self.snippet_stack.push(SnippetState {
 9309                    active_index: 0,
 9310                    ranges,
 9311                    choices,
 9312                });
 9313            }
 9314
 9315            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9316            if self.autoclose_regions.is_empty() {
 9317                let snapshot = self.buffer.read(cx).snapshot(cx);
 9318                for selection in &mut self.selections.all::<Point>(cx) {
 9319                    let selection_head = selection.head();
 9320                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9321                        continue;
 9322                    };
 9323
 9324                    let mut bracket_pair = None;
 9325                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9326                    let prev_chars = snapshot
 9327                        .reversed_chars_at(selection_head)
 9328                        .collect::<String>();
 9329                    for (pair, enabled) in scope.brackets() {
 9330                        if enabled
 9331                            && pair.close
 9332                            && prev_chars.starts_with(pair.start.as_str())
 9333                            && next_chars.starts_with(pair.end.as_str())
 9334                        {
 9335                            bracket_pair = Some(pair.clone());
 9336                            break;
 9337                        }
 9338                    }
 9339                    if let Some(pair) = bracket_pair {
 9340                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9341                        let autoclose_enabled =
 9342                            self.use_autoclose && snapshot_settings.use_autoclose;
 9343                        if autoclose_enabled {
 9344                            let start = snapshot.anchor_after(selection_head);
 9345                            let end = snapshot.anchor_after(selection_head);
 9346                            self.autoclose_regions.push(AutocloseRegion {
 9347                                selection_id: selection.id,
 9348                                range: start..end,
 9349                                pair,
 9350                            });
 9351                        }
 9352                    }
 9353                }
 9354            }
 9355        }
 9356        Ok(())
 9357    }
 9358
 9359    pub fn move_to_next_snippet_tabstop(
 9360        &mut self,
 9361        window: &mut Window,
 9362        cx: &mut Context<Self>,
 9363    ) -> bool {
 9364        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9365    }
 9366
 9367    pub fn move_to_prev_snippet_tabstop(
 9368        &mut self,
 9369        window: &mut Window,
 9370        cx: &mut Context<Self>,
 9371    ) -> bool {
 9372        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9373    }
 9374
 9375    pub fn move_to_snippet_tabstop(
 9376        &mut self,
 9377        bias: Bias,
 9378        window: &mut Window,
 9379        cx: &mut Context<Self>,
 9380    ) -> bool {
 9381        if let Some(mut snippet) = self.snippet_stack.pop() {
 9382            match bias {
 9383                Bias::Left => {
 9384                    if snippet.active_index > 0 {
 9385                        snippet.active_index -= 1;
 9386                    } else {
 9387                        self.snippet_stack.push(snippet);
 9388                        return false;
 9389                    }
 9390                }
 9391                Bias::Right => {
 9392                    if snippet.active_index + 1 < snippet.ranges.len() {
 9393                        snippet.active_index += 1;
 9394                    } else {
 9395                        self.snippet_stack.push(snippet);
 9396                        return false;
 9397                    }
 9398                }
 9399            }
 9400            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9401                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9402                    // Reverse order so that the first range is the newest created selection.
 9403                    // Completions will use it and autoscroll will prioritize it.
 9404                    s.select_ranges(current_ranges.iter().rev().cloned())
 9405                });
 9406
 9407                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9408                    if let Some(selection) = current_ranges.first() {
 9409                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9410                    }
 9411                }
 9412
 9413                // If snippet state is not at the last tabstop, push it back on the stack
 9414                if snippet.active_index + 1 < snippet.ranges.len() {
 9415                    self.snippet_stack.push(snippet);
 9416                }
 9417                return true;
 9418            }
 9419        }
 9420
 9421        false
 9422    }
 9423
 9424    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9425        self.transact(window, cx, |this, window, cx| {
 9426            this.select_all(&SelectAll, window, cx);
 9427            this.insert("", window, cx);
 9428        });
 9429    }
 9430
 9431    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9432        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9433        self.transact(window, cx, |this, window, cx| {
 9434            this.select_autoclose_pair(window, cx);
 9435            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9436            if !this.linked_edit_ranges.is_empty() {
 9437                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9438                let snapshot = this.buffer.read(cx).snapshot(cx);
 9439
 9440                for selection in selections.iter() {
 9441                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9442                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9443                    if selection_start.buffer_id != selection_end.buffer_id {
 9444                        continue;
 9445                    }
 9446                    if let Some(ranges) =
 9447                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9448                    {
 9449                        for (buffer, entries) in ranges {
 9450                            linked_ranges.entry(buffer).or_default().extend(entries);
 9451                        }
 9452                    }
 9453                }
 9454            }
 9455
 9456            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9457            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9458            for selection in &mut selections {
 9459                if selection.is_empty() {
 9460                    let old_head = selection.head();
 9461                    let mut new_head =
 9462                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9463                            .to_point(&display_map);
 9464                    if let Some((buffer, line_buffer_range)) = display_map
 9465                        .buffer_snapshot
 9466                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9467                    {
 9468                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9469                        let indent_len = match indent_size.kind {
 9470                            IndentKind::Space => {
 9471                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9472                            }
 9473                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9474                        };
 9475                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9476                            let indent_len = indent_len.get();
 9477                            new_head = cmp::min(
 9478                                new_head,
 9479                                MultiBufferPoint::new(
 9480                                    old_head.row,
 9481                                    ((old_head.column - 1) / indent_len) * indent_len,
 9482                                ),
 9483                            );
 9484                        }
 9485                    }
 9486
 9487                    selection.set_head(new_head, SelectionGoal::None);
 9488                }
 9489            }
 9490
 9491            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9492                s.select(selections)
 9493            });
 9494            this.insert("", window, cx);
 9495            let empty_str: Arc<str> = Arc::from("");
 9496            for (buffer, edits) in linked_ranges {
 9497                let snapshot = buffer.read(cx).snapshot();
 9498                use text::ToPoint as TP;
 9499
 9500                let edits = edits
 9501                    .into_iter()
 9502                    .map(|range| {
 9503                        let end_point = TP::to_point(&range.end, &snapshot);
 9504                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9505
 9506                        if end_point == start_point {
 9507                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9508                                .saturating_sub(1);
 9509                            start_point =
 9510                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9511                        };
 9512
 9513                        (start_point..end_point, empty_str.clone())
 9514                    })
 9515                    .sorted_by_key(|(range, _)| range.start)
 9516                    .collect::<Vec<_>>();
 9517                buffer.update(cx, |this, cx| {
 9518                    this.edit(edits, None, cx);
 9519                })
 9520            }
 9521            this.refresh_inline_completion(true, false, window, cx);
 9522            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9523        });
 9524    }
 9525
 9526    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9527        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9528        self.transact(window, cx, |this, window, cx| {
 9529            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9530                s.move_with(|map, selection| {
 9531                    if selection.is_empty() {
 9532                        let cursor = movement::right(map, selection.head());
 9533                        selection.end = cursor;
 9534                        selection.reversed = true;
 9535                        selection.goal = SelectionGoal::None;
 9536                    }
 9537                })
 9538            });
 9539            this.insert("", window, cx);
 9540            this.refresh_inline_completion(true, false, window, cx);
 9541        });
 9542    }
 9543
 9544    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9545        if self.mode.is_single_line() {
 9546            cx.propagate();
 9547            return;
 9548        }
 9549
 9550        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9551        if self.move_to_prev_snippet_tabstop(window, cx) {
 9552            return;
 9553        }
 9554        self.outdent(&Outdent, window, cx);
 9555    }
 9556
 9557    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9558        if self.mode.is_single_line() {
 9559            cx.propagate();
 9560            return;
 9561        }
 9562
 9563        if self.move_to_next_snippet_tabstop(window, cx) {
 9564            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9565            return;
 9566        }
 9567        if self.read_only(cx) {
 9568            return;
 9569        }
 9570        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9571        let mut selections = self.selections.all_adjusted(cx);
 9572        let buffer = self.buffer.read(cx);
 9573        let snapshot = buffer.snapshot(cx);
 9574        let rows_iter = selections.iter().map(|s| s.head().row);
 9575        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9576
 9577        let has_some_cursor_in_whitespace = selections
 9578            .iter()
 9579            .filter(|selection| selection.is_empty())
 9580            .any(|selection| {
 9581                let cursor = selection.head();
 9582                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9583                cursor.column < current_indent.len
 9584            });
 9585
 9586        let mut edits = Vec::new();
 9587        let mut prev_edited_row = 0;
 9588        let mut row_delta = 0;
 9589        for selection in &mut selections {
 9590            if selection.start.row != prev_edited_row {
 9591                row_delta = 0;
 9592            }
 9593            prev_edited_row = selection.end.row;
 9594
 9595            // If the selection is non-empty, then increase the indentation of the selected lines.
 9596            if !selection.is_empty() {
 9597                row_delta =
 9598                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9599                continue;
 9600            }
 9601
 9602            let cursor = selection.head();
 9603            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9604            if let Some(suggested_indent) =
 9605                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9606            {
 9607                // Don't do anything if already at suggested indent
 9608                // and there is any other cursor which is not
 9609                if has_some_cursor_in_whitespace
 9610                    && cursor.column == current_indent.len
 9611                    && current_indent.len == suggested_indent.len
 9612                {
 9613                    continue;
 9614                }
 9615
 9616                // Adjust line and move cursor to suggested indent
 9617                // if cursor is not at suggested indent
 9618                if cursor.column < suggested_indent.len
 9619                    && cursor.column <= current_indent.len
 9620                    && current_indent.len <= suggested_indent.len
 9621                {
 9622                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9623                    selection.end = selection.start;
 9624                    if row_delta == 0 {
 9625                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9626                            cursor.row,
 9627                            current_indent,
 9628                            suggested_indent,
 9629                        ));
 9630                        row_delta = suggested_indent.len - current_indent.len;
 9631                    }
 9632                    continue;
 9633                }
 9634
 9635                // If current indent is more than suggested indent
 9636                // only move cursor to current indent and skip indent
 9637                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9638                    selection.start = Point::new(cursor.row, current_indent.len);
 9639                    selection.end = selection.start;
 9640                    continue;
 9641                }
 9642            }
 9643
 9644            // Otherwise, insert a hard or soft tab.
 9645            let settings = buffer.language_settings_at(cursor, cx);
 9646            let tab_size = if settings.hard_tabs {
 9647                IndentSize::tab()
 9648            } else {
 9649                let tab_size = settings.tab_size.get();
 9650                let indent_remainder = snapshot
 9651                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9652                    .flat_map(str::chars)
 9653                    .fold(row_delta % tab_size, |counter: u32, c| {
 9654                        if c == '\t' {
 9655                            0
 9656                        } else {
 9657                            (counter + 1) % tab_size
 9658                        }
 9659                    });
 9660
 9661                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9662                IndentSize::spaces(chars_to_next_tab_stop)
 9663            };
 9664            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9665            selection.end = selection.start;
 9666            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9667            row_delta += tab_size.len;
 9668        }
 9669
 9670        self.transact(window, cx, |this, window, cx| {
 9671            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9672            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9673                s.select(selections)
 9674            });
 9675            this.refresh_inline_completion(true, false, window, cx);
 9676        });
 9677    }
 9678
 9679    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9680        if self.read_only(cx) {
 9681            return;
 9682        }
 9683        if self.mode.is_single_line() {
 9684            cx.propagate();
 9685            return;
 9686        }
 9687
 9688        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9689        let mut selections = self.selections.all::<Point>(cx);
 9690        let mut prev_edited_row = 0;
 9691        let mut row_delta = 0;
 9692        let mut edits = Vec::new();
 9693        let buffer = self.buffer.read(cx);
 9694        let snapshot = buffer.snapshot(cx);
 9695        for selection in &mut selections {
 9696            if selection.start.row != prev_edited_row {
 9697                row_delta = 0;
 9698            }
 9699            prev_edited_row = selection.end.row;
 9700
 9701            row_delta =
 9702                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9703        }
 9704
 9705        self.transact(window, cx, |this, window, cx| {
 9706            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9707            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9708                s.select(selections)
 9709            });
 9710        });
 9711    }
 9712
 9713    fn indent_selection(
 9714        buffer: &MultiBuffer,
 9715        snapshot: &MultiBufferSnapshot,
 9716        selection: &mut Selection<Point>,
 9717        edits: &mut Vec<(Range<Point>, String)>,
 9718        delta_for_start_row: u32,
 9719        cx: &App,
 9720    ) -> u32 {
 9721        let settings = buffer.language_settings_at(selection.start, cx);
 9722        let tab_size = settings.tab_size.get();
 9723        let indent_kind = if settings.hard_tabs {
 9724            IndentKind::Tab
 9725        } else {
 9726            IndentKind::Space
 9727        };
 9728        let mut start_row = selection.start.row;
 9729        let mut end_row = selection.end.row + 1;
 9730
 9731        // If a selection ends at the beginning of a line, don't indent
 9732        // that last line.
 9733        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9734            end_row -= 1;
 9735        }
 9736
 9737        // Avoid re-indenting a row that has already been indented by a
 9738        // previous selection, but still update this selection's column
 9739        // to reflect that indentation.
 9740        if delta_for_start_row > 0 {
 9741            start_row += 1;
 9742            selection.start.column += delta_for_start_row;
 9743            if selection.end.row == selection.start.row {
 9744                selection.end.column += delta_for_start_row;
 9745            }
 9746        }
 9747
 9748        let mut delta_for_end_row = 0;
 9749        let has_multiple_rows = start_row + 1 != end_row;
 9750        for row in start_row..end_row {
 9751            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9752            let indent_delta = match (current_indent.kind, indent_kind) {
 9753                (IndentKind::Space, IndentKind::Space) => {
 9754                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9755                    IndentSize::spaces(columns_to_next_tab_stop)
 9756                }
 9757                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9758                (_, IndentKind::Tab) => IndentSize::tab(),
 9759            };
 9760
 9761            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9762                0
 9763            } else {
 9764                selection.start.column
 9765            };
 9766            let row_start = Point::new(row, start);
 9767            edits.push((
 9768                row_start..row_start,
 9769                indent_delta.chars().collect::<String>(),
 9770            ));
 9771
 9772            // Update this selection's endpoints to reflect the indentation.
 9773            if row == selection.start.row {
 9774                selection.start.column += indent_delta.len;
 9775            }
 9776            if row == selection.end.row {
 9777                selection.end.column += indent_delta.len;
 9778                delta_for_end_row = indent_delta.len;
 9779            }
 9780        }
 9781
 9782        if selection.start.row == selection.end.row {
 9783            delta_for_start_row + delta_for_end_row
 9784        } else {
 9785            delta_for_end_row
 9786        }
 9787    }
 9788
 9789    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9790        if self.read_only(cx) {
 9791            return;
 9792        }
 9793        if self.mode.is_single_line() {
 9794            cx.propagate();
 9795            return;
 9796        }
 9797
 9798        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9799        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9800        let selections = self.selections.all::<Point>(cx);
 9801        let mut deletion_ranges = Vec::new();
 9802        let mut last_outdent = None;
 9803        {
 9804            let buffer = self.buffer.read(cx);
 9805            let snapshot = buffer.snapshot(cx);
 9806            for selection in &selections {
 9807                let settings = buffer.language_settings_at(selection.start, cx);
 9808                let tab_size = settings.tab_size.get();
 9809                let mut rows = selection.spanned_rows(false, &display_map);
 9810
 9811                // Avoid re-outdenting a row that has already been outdented by a
 9812                // previous selection.
 9813                if let Some(last_row) = last_outdent {
 9814                    if last_row == rows.start {
 9815                        rows.start = rows.start.next_row();
 9816                    }
 9817                }
 9818                let has_multiple_rows = rows.len() > 1;
 9819                for row in rows.iter_rows() {
 9820                    let indent_size = snapshot.indent_size_for_line(row);
 9821                    if indent_size.len > 0 {
 9822                        let deletion_len = match indent_size.kind {
 9823                            IndentKind::Space => {
 9824                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9825                                if columns_to_prev_tab_stop == 0 {
 9826                                    tab_size
 9827                                } else {
 9828                                    columns_to_prev_tab_stop
 9829                                }
 9830                            }
 9831                            IndentKind::Tab => 1,
 9832                        };
 9833                        let start = if has_multiple_rows
 9834                            || deletion_len > selection.start.column
 9835                            || indent_size.len < selection.start.column
 9836                        {
 9837                            0
 9838                        } else {
 9839                            selection.start.column - deletion_len
 9840                        };
 9841                        deletion_ranges.push(
 9842                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9843                        );
 9844                        last_outdent = Some(row);
 9845                    }
 9846                }
 9847            }
 9848        }
 9849
 9850        self.transact(window, cx, |this, window, cx| {
 9851            this.buffer.update(cx, |buffer, cx| {
 9852                let empty_str: Arc<str> = Arc::default();
 9853                buffer.edit(
 9854                    deletion_ranges
 9855                        .into_iter()
 9856                        .map(|range| (range, empty_str.clone())),
 9857                    None,
 9858                    cx,
 9859                );
 9860            });
 9861            let selections = this.selections.all::<usize>(cx);
 9862            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9863                s.select(selections)
 9864            });
 9865        });
 9866    }
 9867
 9868    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9869        if self.read_only(cx) {
 9870            return;
 9871        }
 9872        if self.mode.is_single_line() {
 9873            cx.propagate();
 9874            return;
 9875        }
 9876
 9877        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9878        let selections = self
 9879            .selections
 9880            .all::<usize>(cx)
 9881            .into_iter()
 9882            .map(|s| s.range());
 9883
 9884        self.transact(window, cx, |this, window, cx| {
 9885            this.buffer.update(cx, |buffer, cx| {
 9886                buffer.autoindent_ranges(selections, cx);
 9887            });
 9888            let selections = this.selections.all::<usize>(cx);
 9889            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9890                s.select(selections)
 9891            });
 9892        });
 9893    }
 9894
 9895    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9896        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9897        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9898        let selections = self.selections.all::<Point>(cx);
 9899
 9900        let mut new_cursors = Vec::new();
 9901        let mut edit_ranges = Vec::new();
 9902        let mut selections = selections.iter().peekable();
 9903        while let Some(selection) = selections.next() {
 9904            let mut rows = selection.spanned_rows(false, &display_map);
 9905            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9906
 9907            // Accumulate contiguous regions of rows that we want to delete.
 9908            while let Some(next_selection) = selections.peek() {
 9909                let next_rows = next_selection.spanned_rows(false, &display_map);
 9910                if next_rows.start <= rows.end {
 9911                    rows.end = next_rows.end;
 9912                    selections.next().unwrap();
 9913                } else {
 9914                    break;
 9915                }
 9916            }
 9917
 9918            let buffer = &display_map.buffer_snapshot;
 9919            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9920            let edit_end;
 9921            let cursor_buffer_row;
 9922            if buffer.max_point().row >= rows.end.0 {
 9923                // If there's a line after the range, delete the \n from the end of the row range
 9924                // and position the cursor on the next line.
 9925                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9926                cursor_buffer_row = rows.end;
 9927            } else {
 9928                // If there isn't a line after the range, delete the \n from the line before the
 9929                // start of the row range and position the cursor there.
 9930                edit_start = edit_start.saturating_sub(1);
 9931                edit_end = buffer.len();
 9932                cursor_buffer_row = rows.start.previous_row();
 9933            }
 9934
 9935            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9936            *cursor.column_mut() =
 9937                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9938
 9939            new_cursors.push((
 9940                selection.id,
 9941                buffer.anchor_after(cursor.to_point(&display_map)),
 9942            ));
 9943            edit_ranges.push(edit_start..edit_end);
 9944        }
 9945
 9946        self.transact(window, cx, |this, window, cx| {
 9947            let buffer = this.buffer.update(cx, |buffer, cx| {
 9948                let empty_str: Arc<str> = Arc::default();
 9949                buffer.edit(
 9950                    edit_ranges
 9951                        .into_iter()
 9952                        .map(|range| (range, empty_str.clone())),
 9953                    None,
 9954                    cx,
 9955                );
 9956                buffer.snapshot(cx)
 9957            });
 9958            let new_selections = new_cursors
 9959                .into_iter()
 9960                .map(|(id, cursor)| {
 9961                    let cursor = cursor.to_point(&buffer);
 9962                    Selection {
 9963                        id,
 9964                        start: cursor,
 9965                        end: cursor,
 9966                        reversed: false,
 9967                        goal: SelectionGoal::None,
 9968                    }
 9969                })
 9970                .collect();
 9971
 9972            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9973                s.select(new_selections);
 9974            });
 9975        });
 9976    }
 9977
 9978    pub fn join_lines_impl(
 9979        &mut self,
 9980        insert_whitespace: bool,
 9981        window: &mut Window,
 9982        cx: &mut Context<Self>,
 9983    ) {
 9984        if self.read_only(cx) {
 9985            return;
 9986        }
 9987        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9988        for selection in self.selections.all::<Point>(cx) {
 9989            let start = MultiBufferRow(selection.start.row);
 9990            // Treat single line selections as if they include the next line. Otherwise this action
 9991            // would do nothing for single line selections individual cursors.
 9992            let end = if selection.start.row == selection.end.row {
 9993                MultiBufferRow(selection.start.row + 1)
 9994            } else {
 9995                MultiBufferRow(selection.end.row)
 9996            };
 9997
 9998            if let Some(last_row_range) = row_ranges.last_mut() {
 9999                if start <= last_row_range.end {
10000                    last_row_range.end = end;
10001                    continue;
10002                }
10003            }
10004            row_ranges.push(start..end);
10005        }
10006
10007        let snapshot = self.buffer.read(cx).snapshot(cx);
10008        let mut cursor_positions = Vec::new();
10009        for row_range in &row_ranges {
10010            let anchor = snapshot.anchor_before(Point::new(
10011                row_range.end.previous_row().0,
10012                snapshot.line_len(row_range.end.previous_row()),
10013            ));
10014            cursor_positions.push(anchor..anchor);
10015        }
10016
10017        self.transact(window, cx, |this, window, cx| {
10018            for row_range in row_ranges.into_iter().rev() {
10019                for row in row_range.iter_rows().rev() {
10020                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10021                    let next_line_row = row.next_row();
10022                    let indent = snapshot.indent_size_for_line(next_line_row);
10023                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10024
10025                    let replace =
10026                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10027                            " "
10028                        } else {
10029                            ""
10030                        };
10031
10032                    this.buffer.update(cx, |buffer, cx| {
10033                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10034                    });
10035                }
10036            }
10037
10038            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10039                s.select_anchor_ranges(cursor_positions)
10040            });
10041        });
10042    }
10043
10044    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10045        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10046        self.join_lines_impl(true, window, cx);
10047    }
10048
10049    pub fn sort_lines_case_sensitive(
10050        &mut self,
10051        _: &SortLinesCaseSensitive,
10052        window: &mut Window,
10053        cx: &mut Context<Self>,
10054    ) {
10055        self.manipulate_lines(window, cx, |lines| lines.sort())
10056    }
10057
10058    pub fn sort_lines_case_insensitive(
10059        &mut self,
10060        _: &SortLinesCaseInsensitive,
10061        window: &mut Window,
10062        cx: &mut Context<Self>,
10063    ) {
10064        self.manipulate_lines(window, cx, |lines| {
10065            lines.sort_by_key(|line| line.to_lowercase())
10066        })
10067    }
10068
10069    pub fn unique_lines_case_insensitive(
10070        &mut self,
10071        _: &UniqueLinesCaseInsensitive,
10072        window: &mut Window,
10073        cx: &mut Context<Self>,
10074    ) {
10075        self.manipulate_lines(window, cx, |lines| {
10076            let mut seen = HashSet::default();
10077            lines.retain(|line| seen.insert(line.to_lowercase()));
10078        })
10079    }
10080
10081    pub fn unique_lines_case_sensitive(
10082        &mut self,
10083        _: &UniqueLinesCaseSensitive,
10084        window: &mut Window,
10085        cx: &mut Context<Self>,
10086    ) {
10087        self.manipulate_lines(window, cx, |lines| {
10088            let mut seen = HashSet::default();
10089            lines.retain(|line| seen.insert(*line));
10090        })
10091    }
10092
10093    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10094        let Some(project) = self.project.clone() else {
10095            return;
10096        };
10097        self.reload(project, window, cx)
10098            .detach_and_notify_err(window, cx);
10099    }
10100
10101    pub fn restore_file(
10102        &mut self,
10103        _: &::git::RestoreFile,
10104        window: &mut Window,
10105        cx: &mut Context<Self>,
10106    ) {
10107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10108        let mut buffer_ids = HashSet::default();
10109        let snapshot = self.buffer().read(cx).snapshot(cx);
10110        for selection in self.selections.all::<usize>(cx) {
10111            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10112        }
10113
10114        let buffer = self.buffer().read(cx);
10115        let ranges = buffer_ids
10116            .into_iter()
10117            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10118            .collect::<Vec<_>>();
10119
10120        self.restore_hunks_in_ranges(ranges, window, cx);
10121    }
10122
10123    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10124        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10125        let selections = self
10126            .selections
10127            .all(cx)
10128            .into_iter()
10129            .map(|s| s.range())
10130            .collect();
10131        self.restore_hunks_in_ranges(selections, window, cx);
10132    }
10133
10134    pub fn restore_hunks_in_ranges(
10135        &mut self,
10136        ranges: Vec<Range<Point>>,
10137        window: &mut Window,
10138        cx: &mut Context<Editor>,
10139    ) {
10140        let mut revert_changes = HashMap::default();
10141        let chunk_by = self
10142            .snapshot(window, cx)
10143            .hunks_for_ranges(ranges)
10144            .into_iter()
10145            .chunk_by(|hunk| hunk.buffer_id);
10146        for (buffer_id, hunks) in &chunk_by {
10147            let hunks = hunks.collect::<Vec<_>>();
10148            for hunk in &hunks {
10149                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10150            }
10151            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10152        }
10153        drop(chunk_by);
10154        if !revert_changes.is_empty() {
10155            self.transact(window, cx, |editor, window, cx| {
10156                editor.restore(revert_changes, window, cx);
10157            });
10158        }
10159    }
10160
10161    pub fn open_active_item_in_terminal(
10162        &mut self,
10163        _: &OpenInTerminal,
10164        window: &mut Window,
10165        cx: &mut Context<Self>,
10166    ) {
10167        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10168            let project_path = buffer.read(cx).project_path(cx)?;
10169            let project = self.project.as_ref()?.read(cx);
10170            let entry = project.entry_for_path(&project_path, cx)?;
10171            let parent = match &entry.canonical_path {
10172                Some(canonical_path) => canonical_path.to_path_buf(),
10173                None => project.absolute_path(&project_path, cx)?,
10174            }
10175            .parent()?
10176            .to_path_buf();
10177            Some(parent)
10178        }) {
10179            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10180        }
10181    }
10182
10183    fn set_breakpoint_context_menu(
10184        &mut self,
10185        display_row: DisplayRow,
10186        position: Option<Anchor>,
10187        clicked_point: gpui::Point<Pixels>,
10188        window: &mut Window,
10189        cx: &mut Context<Self>,
10190    ) {
10191        let source = self
10192            .buffer
10193            .read(cx)
10194            .snapshot(cx)
10195            .anchor_before(Point::new(display_row.0, 0u32));
10196
10197        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10198
10199        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10200            self,
10201            source,
10202            clicked_point,
10203            context_menu,
10204            window,
10205            cx,
10206        );
10207    }
10208
10209    fn add_edit_breakpoint_block(
10210        &mut self,
10211        anchor: Anchor,
10212        breakpoint: &Breakpoint,
10213        edit_action: BreakpointPromptEditAction,
10214        window: &mut Window,
10215        cx: &mut Context<Self>,
10216    ) {
10217        let weak_editor = cx.weak_entity();
10218        let bp_prompt = cx.new(|cx| {
10219            BreakpointPromptEditor::new(
10220                weak_editor,
10221                anchor,
10222                breakpoint.clone(),
10223                edit_action,
10224                window,
10225                cx,
10226            )
10227        });
10228
10229        let height = bp_prompt.update(cx, |this, cx| {
10230            this.prompt
10231                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10232        });
10233        let cloned_prompt = bp_prompt.clone();
10234        let blocks = vec![BlockProperties {
10235            style: BlockStyle::Sticky,
10236            placement: BlockPlacement::Above(anchor),
10237            height: Some(height),
10238            render: Arc::new(move |cx| {
10239                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10240                cloned_prompt.clone().into_any_element()
10241            }),
10242            priority: 0,
10243            render_in_minimap: true,
10244        }];
10245
10246        let focus_handle = bp_prompt.focus_handle(cx);
10247        window.focus(&focus_handle);
10248
10249        let block_ids = self.insert_blocks(blocks, None, cx);
10250        bp_prompt.update(cx, |prompt, _| {
10251            prompt.add_block_ids(block_ids);
10252        });
10253    }
10254
10255    pub(crate) fn breakpoint_at_row(
10256        &self,
10257        row: u32,
10258        window: &mut Window,
10259        cx: &mut Context<Self>,
10260    ) -> Option<(Anchor, Breakpoint)> {
10261        let snapshot = self.snapshot(window, cx);
10262        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10263
10264        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10265    }
10266
10267    pub(crate) fn breakpoint_at_anchor(
10268        &self,
10269        breakpoint_position: Anchor,
10270        snapshot: &EditorSnapshot,
10271        cx: &mut Context<Self>,
10272    ) -> Option<(Anchor, Breakpoint)> {
10273        let project = self.project.clone()?;
10274
10275        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10276            snapshot
10277                .buffer_snapshot
10278                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10279        })?;
10280
10281        let enclosing_excerpt = breakpoint_position.excerpt_id;
10282        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10283        let buffer_snapshot = buffer.read(cx).snapshot();
10284
10285        let row = buffer_snapshot
10286            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10287            .row;
10288
10289        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10290        let anchor_end = snapshot
10291            .buffer_snapshot
10292            .anchor_after(Point::new(row, line_len));
10293
10294        let bp = self
10295            .breakpoint_store
10296            .as_ref()?
10297            .read_with(cx, |breakpoint_store, cx| {
10298                breakpoint_store
10299                    .breakpoints(
10300                        &buffer,
10301                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10302                        &buffer_snapshot,
10303                        cx,
10304                    )
10305                    .next()
10306                    .and_then(|(bp, _)| {
10307                        let breakpoint_row = buffer_snapshot
10308                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10309                            .row;
10310
10311                        if breakpoint_row == row {
10312                            snapshot
10313                                .buffer_snapshot
10314                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10315                                .map(|position| (position, bp.bp.clone()))
10316                        } else {
10317                            None
10318                        }
10319                    })
10320            });
10321        bp
10322    }
10323
10324    pub fn edit_log_breakpoint(
10325        &mut self,
10326        _: &EditLogBreakpoint,
10327        window: &mut Window,
10328        cx: &mut Context<Self>,
10329    ) {
10330        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10331            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10332                message: None,
10333                state: BreakpointState::Enabled,
10334                condition: None,
10335                hit_condition: None,
10336            });
10337
10338            self.add_edit_breakpoint_block(
10339                anchor,
10340                &breakpoint,
10341                BreakpointPromptEditAction::Log,
10342                window,
10343                cx,
10344            );
10345        }
10346    }
10347
10348    fn breakpoints_at_cursors(
10349        &self,
10350        window: &mut Window,
10351        cx: &mut Context<Self>,
10352    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10353        let snapshot = self.snapshot(window, cx);
10354        let cursors = self
10355            .selections
10356            .disjoint_anchors()
10357            .into_iter()
10358            .map(|selection| {
10359                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10360
10361                let breakpoint_position = self
10362                    .breakpoint_at_row(cursor_position.row, window, cx)
10363                    .map(|bp| bp.0)
10364                    .unwrap_or_else(|| {
10365                        snapshot
10366                            .display_snapshot
10367                            .buffer_snapshot
10368                            .anchor_after(Point::new(cursor_position.row, 0))
10369                    });
10370
10371                let breakpoint = self
10372                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10373                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10374
10375                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10376            })
10377            // 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.
10378            .collect::<HashMap<Anchor, _>>();
10379
10380        cursors.into_iter().collect()
10381    }
10382
10383    pub fn enable_breakpoint(
10384        &mut self,
10385        _: &crate::actions::EnableBreakpoint,
10386        window: &mut Window,
10387        cx: &mut Context<Self>,
10388    ) {
10389        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10390            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10391                continue;
10392            };
10393            self.edit_breakpoint_at_anchor(
10394                anchor,
10395                breakpoint,
10396                BreakpointEditAction::InvertState,
10397                cx,
10398            );
10399        }
10400    }
10401
10402    pub fn disable_breakpoint(
10403        &mut self,
10404        _: &crate::actions::DisableBreakpoint,
10405        window: &mut Window,
10406        cx: &mut Context<Self>,
10407    ) {
10408        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10409            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10410                continue;
10411            };
10412            self.edit_breakpoint_at_anchor(
10413                anchor,
10414                breakpoint,
10415                BreakpointEditAction::InvertState,
10416                cx,
10417            );
10418        }
10419    }
10420
10421    pub fn toggle_breakpoint(
10422        &mut self,
10423        _: &crate::actions::ToggleBreakpoint,
10424        window: &mut Window,
10425        cx: &mut Context<Self>,
10426    ) {
10427        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10428            if let Some(breakpoint) = breakpoint {
10429                self.edit_breakpoint_at_anchor(
10430                    anchor,
10431                    breakpoint,
10432                    BreakpointEditAction::Toggle,
10433                    cx,
10434                );
10435            } else {
10436                self.edit_breakpoint_at_anchor(
10437                    anchor,
10438                    Breakpoint::new_standard(),
10439                    BreakpointEditAction::Toggle,
10440                    cx,
10441                );
10442            }
10443        }
10444    }
10445
10446    pub fn edit_breakpoint_at_anchor(
10447        &mut self,
10448        breakpoint_position: Anchor,
10449        breakpoint: Breakpoint,
10450        edit_action: BreakpointEditAction,
10451        cx: &mut Context<Self>,
10452    ) {
10453        let Some(breakpoint_store) = &self.breakpoint_store else {
10454            return;
10455        };
10456
10457        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10458            if breakpoint_position == Anchor::min() {
10459                self.buffer()
10460                    .read(cx)
10461                    .excerpt_buffer_ids()
10462                    .into_iter()
10463                    .next()
10464            } else {
10465                None
10466            }
10467        }) else {
10468            return;
10469        };
10470
10471        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10472            return;
10473        };
10474
10475        breakpoint_store.update(cx, |breakpoint_store, cx| {
10476            breakpoint_store.toggle_breakpoint(
10477                buffer,
10478                BreakpointWithPosition {
10479                    position: breakpoint_position.text_anchor,
10480                    bp: breakpoint,
10481                },
10482                edit_action,
10483                cx,
10484            );
10485        });
10486
10487        cx.notify();
10488    }
10489
10490    #[cfg(any(test, feature = "test-support"))]
10491    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10492        self.breakpoint_store.clone()
10493    }
10494
10495    pub fn prepare_restore_change(
10496        &self,
10497        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10498        hunk: &MultiBufferDiffHunk,
10499        cx: &mut App,
10500    ) -> Option<()> {
10501        if hunk.is_created_file() {
10502            return None;
10503        }
10504        let buffer = self.buffer.read(cx);
10505        let diff = buffer.diff_for(hunk.buffer_id)?;
10506        let buffer = buffer.buffer(hunk.buffer_id)?;
10507        let buffer = buffer.read(cx);
10508        let original_text = diff
10509            .read(cx)
10510            .base_text()
10511            .as_rope()
10512            .slice(hunk.diff_base_byte_range.clone());
10513        let buffer_snapshot = buffer.snapshot();
10514        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10515        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10516            probe
10517                .0
10518                .start
10519                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10520                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10521        }) {
10522            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10523            Some(())
10524        } else {
10525            None
10526        }
10527    }
10528
10529    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10530        self.manipulate_lines(window, cx, |lines| lines.reverse())
10531    }
10532
10533    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10534        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10535    }
10536
10537    fn manipulate_lines<Fn>(
10538        &mut self,
10539        window: &mut Window,
10540        cx: &mut Context<Self>,
10541        mut callback: Fn,
10542    ) where
10543        Fn: FnMut(&mut Vec<&str>),
10544    {
10545        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10546
10547        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10548        let buffer = self.buffer.read(cx).snapshot(cx);
10549
10550        let mut edits = Vec::new();
10551
10552        let selections = self.selections.all::<Point>(cx);
10553        let mut selections = selections.iter().peekable();
10554        let mut contiguous_row_selections = Vec::new();
10555        let mut new_selections = Vec::new();
10556        let mut added_lines = 0;
10557        let mut removed_lines = 0;
10558
10559        while let Some(selection) = selections.next() {
10560            let (start_row, end_row) = consume_contiguous_rows(
10561                &mut contiguous_row_selections,
10562                selection,
10563                &display_map,
10564                &mut selections,
10565            );
10566
10567            let start_point = Point::new(start_row.0, 0);
10568            let end_point = Point::new(
10569                end_row.previous_row().0,
10570                buffer.line_len(end_row.previous_row()),
10571            );
10572            let text = buffer
10573                .text_for_range(start_point..end_point)
10574                .collect::<String>();
10575
10576            let mut lines = text.split('\n').collect_vec();
10577
10578            let lines_before = lines.len();
10579            callback(&mut lines);
10580            let lines_after = lines.len();
10581
10582            edits.push((start_point..end_point, lines.join("\n")));
10583
10584            // Selections must change based on added and removed line count
10585            let start_row =
10586                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10587            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10588            new_selections.push(Selection {
10589                id: selection.id,
10590                start: start_row,
10591                end: end_row,
10592                goal: SelectionGoal::None,
10593                reversed: selection.reversed,
10594            });
10595
10596            if lines_after > lines_before {
10597                added_lines += lines_after - lines_before;
10598            } else if lines_before > lines_after {
10599                removed_lines += lines_before - lines_after;
10600            }
10601        }
10602
10603        self.transact(window, cx, |this, window, cx| {
10604            let buffer = this.buffer.update(cx, |buffer, cx| {
10605                buffer.edit(edits, None, cx);
10606                buffer.snapshot(cx)
10607            });
10608
10609            // Recalculate offsets on newly edited buffer
10610            let new_selections = new_selections
10611                .iter()
10612                .map(|s| {
10613                    let start_point = Point::new(s.start.0, 0);
10614                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10615                    Selection {
10616                        id: s.id,
10617                        start: buffer.point_to_offset(start_point),
10618                        end: buffer.point_to_offset(end_point),
10619                        goal: s.goal,
10620                        reversed: s.reversed,
10621                    }
10622                })
10623                .collect();
10624
10625            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10626                s.select(new_selections);
10627            });
10628
10629            this.request_autoscroll(Autoscroll::fit(), cx);
10630        });
10631    }
10632
10633    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10634        self.manipulate_text(window, cx, |text| {
10635            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10636            if has_upper_case_characters {
10637                text.to_lowercase()
10638            } else {
10639                text.to_uppercase()
10640            }
10641        })
10642    }
10643
10644    pub fn convert_to_upper_case(
10645        &mut self,
10646        _: &ConvertToUpperCase,
10647        window: &mut Window,
10648        cx: &mut Context<Self>,
10649    ) {
10650        self.manipulate_text(window, cx, |text| text.to_uppercase())
10651    }
10652
10653    pub fn convert_to_lower_case(
10654        &mut self,
10655        _: &ConvertToLowerCase,
10656        window: &mut Window,
10657        cx: &mut Context<Self>,
10658    ) {
10659        self.manipulate_text(window, cx, |text| text.to_lowercase())
10660    }
10661
10662    pub fn convert_to_title_case(
10663        &mut self,
10664        _: &ConvertToTitleCase,
10665        window: &mut Window,
10666        cx: &mut Context<Self>,
10667    ) {
10668        self.manipulate_text(window, cx, |text| {
10669            text.split('\n')
10670                .map(|line| line.to_case(Case::Title))
10671                .join("\n")
10672        })
10673    }
10674
10675    pub fn convert_to_snake_case(
10676        &mut self,
10677        _: &ConvertToSnakeCase,
10678        window: &mut Window,
10679        cx: &mut Context<Self>,
10680    ) {
10681        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10682    }
10683
10684    pub fn convert_to_kebab_case(
10685        &mut self,
10686        _: &ConvertToKebabCase,
10687        window: &mut Window,
10688        cx: &mut Context<Self>,
10689    ) {
10690        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10691    }
10692
10693    pub fn convert_to_upper_camel_case(
10694        &mut self,
10695        _: &ConvertToUpperCamelCase,
10696        window: &mut Window,
10697        cx: &mut Context<Self>,
10698    ) {
10699        self.manipulate_text(window, cx, |text| {
10700            text.split('\n')
10701                .map(|line| line.to_case(Case::UpperCamel))
10702                .join("\n")
10703        })
10704    }
10705
10706    pub fn convert_to_lower_camel_case(
10707        &mut self,
10708        _: &ConvertToLowerCamelCase,
10709        window: &mut Window,
10710        cx: &mut Context<Self>,
10711    ) {
10712        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10713    }
10714
10715    pub fn convert_to_opposite_case(
10716        &mut self,
10717        _: &ConvertToOppositeCase,
10718        window: &mut Window,
10719        cx: &mut Context<Self>,
10720    ) {
10721        self.manipulate_text(window, cx, |text| {
10722            text.chars()
10723                .fold(String::with_capacity(text.len()), |mut t, c| {
10724                    if c.is_uppercase() {
10725                        t.extend(c.to_lowercase());
10726                    } else {
10727                        t.extend(c.to_uppercase());
10728                    }
10729                    t
10730                })
10731        })
10732    }
10733
10734    pub fn convert_to_rot13(
10735        &mut self,
10736        _: &ConvertToRot13,
10737        window: &mut Window,
10738        cx: &mut Context<Self>,
10739    ) {
10740        self.manipulate_text(window, cx, |text| {
10741            text.chars()
10742                .map(|c| match c {
10743                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10744                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10745                    _ => c,
10746                })
10747                .collect()
10748        })
10749    }
10750
10751    pub fn convert_to_rot47(
10752        &mut self,
10753        _: &ConvertToRot47,
10754        window: &mut Window,
10755        cx: &mut Context<Self>,
10756    ) {
10757        self.manipulate_text(window, cx, |text| {
10758            text.chars()
10759                .map(|c| {
10760                    let code_point = c as u32;
10761                    if code_point >= 33 && code_point <= 126 {
10762                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10763                    }
10764                    c
10765                })
10766                .collect()
10767        })
10768    }
10769
10770    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10771    where
10772        Fn: FnMut(&str) -> String,
10773    {
10774        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10775        let buffer = self.buffer.read(cx).snapshot(cx);
10776
10777        let mut new_selections = Vec::new();
10778        let mut edits = Vec::new();
10779        let mut selection_adjustment = 0i32;
10780
10781        for selection in self.selections.all::<usize>(cx) {
10782            let selection_is_empty = selection.is_empty();
10783
10784            let (start, end) = if selection_is_empty {
10785                let word_range = movement::surrounding_word(
10786                    &display_map,
10787                    selection.start.to_display_point(&display_map),
10788                );
10789                let start = word_range.start.to_offset(&display_map, Bias::Left);
10790                let end = word_range.end.to_offset(&display_map, Bias::Left);
10791                (start, end)
10792            } else {
10793                (selection.start, selection.end)
10794            };
10795
10796            let text = buffer.text_for_range(start..end).collect::<String>();
10797            let old_length = text.len() as i32;
10798            let text = callback(&text);
10799
10800            new_selections.push(Selection {
10801                start: (start as i32 - selection_adjustment) as usize,
10802                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10803                goal: SelectionGoal::None,
10804                ..selection
10805            });
10806
10807            selection_adjustment += old_length - text.len() as i32;
10808
10809            edits.push((start..end, text));
10810        }
10811
10812        self.transact(window, cx, |this, window, cx| {
10813            this.buffer.update(cx, |buffer, cx| {
10814                buffer.edit(edits, None, cx);
10815            });
10816
10817            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10818                s.select(new_selections);
10819            });
10820
10821            this.request_autoscroll(Autoscroll::fit(), cx);
10822        });
10823    }
10824
10825    pub fn move_selection_on_drop(
10826        &mut self,
10827        selection: &Selection<Anchor>,
10828        target: DisplayPoint,
10829        is_cut: bool,
10830        window: &mut Window,
10831        cx: &mut Context<Self>,
10832    ) {
10833        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10834        let buffer = &display_map.buffer_snapshot;
10835        let mut edits = Vec::new();
10836        let insert_point = display_map
10837            .clip_point(target, Bias::Left)
10838            .to_point(&display_map);
10839        let text = buffer
10840            .text_for_range(selection.start..selection.end)
10841            .collect::<String>();
10842        if is_cut {
10843            edits.push(((selection.start..selection.end), String::new()));
10844        }
10845        let insert_anchor = buffer.anchor_before(insert_point);
10846        edits.push(((insert_anchor..insert_anchor), text));
10847        let last_edit_start = insert_anchor.bias_left(buffer);
10848        let last_edit_end = insert_anchor.bias_right(buffer);
10849        self.transact(window, cx, |this, window, cx| {
10850            this.buffer.update(cx, |buffer, cx| {
10851                buffer.edit(edits, None, cx);
10852            });
10853            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10854                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10855            });
10856        });
10857    }
10858
10859    pub fn clear_selection_drag_state(&mut self) {
10860        self.selection_drag_state = SelectionDragState::None;
10861    }
10862
10863    pub fn duplicate(
10864        &mut self,
10865        upwards: bool,
10866        whole_lines: bool,
10867        window: &mut Window,
10868        cx: &mut Context<Self>,
10869    ) {
10870        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10871
10872        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10873        let buffer = &display_map.buffer_snapshot;
10874        let selections = self.selections.all::<Point>(cx);
10875
10876        let mut edits = Vec::new();
10877        let mut selections_iter = selections.iter().peekable();
10878        while let Some(selection) = selections_iter.next() {
10879            let mut rows = selection.spanned_rows(false, &display_map);
10880            // duplicate line-wise
10881            if whole_lines || selection.start == selection.end {
10882                // Avoid duplicating the same lines twice.
10883                while let Some(next_selection) = selections_iter.peek() {
10884                    let next_rows = next_selection.spanned_rows(false, &display_map);
10885                    if next_rows.start < rows.end {
10886                        rows.end = next_rows.end;
10887                        selections_iter.next().unwrap();
10888                    } else {
10889                        break;
10890                    }
10891                }
10892
10893                // Copy the text from the selected row region and splice it either at the start
10894                // or end of the region.
10895                let start = Point::new(rows.start.0, 0);
10896                let end = Point::new(
10897                    rows.end.previous_row().0,
10898                    buffer.line_len(rows.end.previous_row()),
10899                );
10900                let text = buffer
10901                    .text_for_range(start..end)
10902                    .chain(Some("\n"))
10903                    .collect::<String>();
10904                let insert_location = if upwards {
10905                    Point::new(rows.end.0, 0)
10906                } else {
10907                    start
10908                };
10909                edits.push((insert_location..insert_location, text));
10910            } else {
10911                // duplicate character-wise
10912                let start = selection.start;
10913                let end = selection.end;
10914                let text = buffer.text_for_range(start..end).collect::<String>();
10915                edits.push((selection.end..selection.end, text));
10916            }
10917        }
10918
10919        self.transact(window, cx, |this, _, cx| {
10920            this.buffer.update(cx, |buffer, cx| {
10921                buffer.edit(edits, None, cx);
10922            });
10923
10924            this.request_autoscroll(Autoscroll::fit(), cx);
10925        });
10926    }
10927
10928    pub fn duplicate_line_up(
10929        &mut self,
10930        _: &DuplicateLineUp,
10931        window: &mut Window,
10932        cx: &mut Context<Self>,
10933    ) {
10934        self.duplicate(true, true, window, cx);
10935    }
10936
10937    pub fn duplicate_line_down(
10938        &mut self,
10939        _: &DuplicateLineDown,
10940        window: &mut Window,
10941        cx: &mut Context<Self>,
10942    ) {
10943        self.duplicate(false, true, window, cx);
10944    }
10945
10946    pub fn duplicate_selection(
10947        &mut self,
10948        _: &DuplicateSelection,
10949        window: &mut Window,
10950        cx: &mut Context<Self>,
10951    ) {
10952        self.duplicate(false, false, window, cx);
10953    }
10954
10955    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10956        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10957        if self.mode.is_single_line() {
10958            cx.propagate();
10959            return;
10960        }
10961
10962        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10963        let buffer = self.buffer.read(cx).snapshot(cx);
10964
10965        let mut edits = Vec::new();
10966        let mut unfold_ranges = Vec::new();
10967        let mut refold_creases = Vec::new();
10968
10969        let selections = self.selections.all::<Point>(cx);
10970        let mut selections = selections.iter().peekable();
10971        let mut contiguous_row_selections = Vec::new();
10972        let mut new_selections = Vec::new();
10973
10974        while let Some(selection) = selections.next() {
10975            // Find all the selections that span a contiguous row range
10976            let (start_row, end_row) = consume_contiguous_rows(
10977                &mut contiguous_row_selections,
10978                selection,
10979                &display_map,
10980                &mut selections,
10981            );
10982
10983            // Move the text spanned by the row range to be before the line preceding the row range
10984            if start_row.0 > 0 {
10985                let range_to_move = Point::new(
10986                    start_row.previous_row().0,
10987                    buffer.line_len(start_row.previous_row()),
10988                )
10989                    ..Point::new(
10990                        end_row.previous_row().0,
10991                        buffer.line_len(end_row.previous_row()),
10992                    );
10993                let insertion_point = display_map
10994                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10995                    .0;
10996
10997                // Don't move lines across excerpts
10998                if buffer
10999                    .excerpt_containing(insertion_point..range_to_move.end)
11000                    .is_some()
11001                {
11002                    let text = buffer
11003                        .text_for_range(range_to_move.clone())
11004                        .flat_map(|s| s.chars())
11005                        .skip(1)
11006                        .chain(['\n'])
11007                        .collect::<String>();
11008
11009                    edits.push((
11010                        buffer.anchor_after(range_to_move.start)
11011                            ..buffer.anchor_before(range_to_move.end),
11012                        String::new(),
11013                    ));
11014                    let insertion_anchor = buffer.anchor_after(insertion_point);
11015                    edits.push((insertion_anchor..insertion_anchor, text));
11016
11017                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11018
11019                    // Move selections up
11020                    new_selections.extend(contiguous_row_selections.drain(..).map(
11021                        |mut selection| {
11022                            selection.start.row -= row_delta;
11023                            selection.end.row -= row_delta;
11024                            selection
11025                        },
11026                    ));
11027
11028                    // Move folds up
11029                    unfold_ranges.push(range_to_move.clone());
11030                    for fold in display_map.folds_in_range(
11031                        buffer.anchor_before(range_to_move.start)
11032                            ..buffer.anchor_after(range_to_move.end),
11033                    ) {
11034                        let mut start = fold.range.start.to_point(&buffer);
11035                        let mut end = fold.range.end.to_point(&buffer);
11036                        start.row -= row_delta;
11037                        end.row -= row_delta;
11038                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11039                    }
11040                }
11041            }
11042
11043            // If we didn't move line(s), preserve the existing selections
11044            new_selections.append(&mut contiguous_row_selections);
11045        }
11046
11047        self.transact(window, cx, |this, window, cx| {
11048            this.unfold_ranges(&unfold_ranges, true, true, cx);
11049            this.buffer.update(cx, |buffer, cx| {
11050                for (range, text) in edits {
11051                    buffer.edit([(range, text)], None, cx);
11052                }
11053            });
11054            this.fold_creases(refold_creases, true, window, cx);
11055            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11056                s.select(new_selections);
11057            })
11058        });
11059    }
11060
11061    pub fn move_line_down(
11062        &mut self,
11063        _: &MoveLineDown,
11064        window: &mut Window,
11065        cx: &mut Context<Self>,
11066    ) {
11067        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11068        if self.mode.is_single_line() {
11069            cx.propagate();
11070            return;
11071        }
11072
11073        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11074        let buffer = self.buffer.read(cx).snapshot(cx);
11075
11076        let mut edits = Vec::new();
11077        let mut unfold_ranges = Vec::new();
11078        let mut refold_creases = Vec::new();
11079
11080        let selections = self.selections.all::<Point>(cx);
11081        let mut selections = selections.iter().peekable();
11082        let mut contiguous_row_selections = Vec::new();
11083        let mut new_selections = Vec::new();
11084
11085        while let Some(selection) = selections.next() {
11086            // Find all the selections that span a contiguous row range
11087            let (start_row, end_row) = consume_contiguous_rows(
11088                &mut contiguous_row_selections,
11089                selection,
11090                &display_map,
11091                &mut selections,
11092            );
11093
11094            // Move the text spanned by the row range to be after the last line of the row range
11095            if end_row.0 <= buffer.max_point().row {
11096                let range_to_move =
11097                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11098                let insertion_point = display_map
11099                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11100                    .0;
11101
11102                // Don't move lines across excerpt boundaries
11103                if buffer
11104                    .excerpt_containing(range_to_move.start..insertion_point)
11105                    .is_some()
11106                {
11107                    let mut text = String::from("\n");
11108                    text.extend(buffer.text_for_range(range_to_move.clone()));
11109                    text.pop(); // Drop trailing newline
11110                    edits.push((
11111                        buffer.anchor_after(range_to_move.start)
11112                            ..buffer.anchor_before(range_to_move.end),
11113                        String::new(),
11114                    ));
11115                    let insertion_anchor = buffer.anchor_after(insertion_point);
11116                    edits.push((insertion_anchor..insertion_anchor, text));
11117
11118                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11119
11120                    // Move selections down
11121                    new_selections.extend(contiguous_row_selections.drain(..).map(
11122                        |mut selection| {
11123                            selection.start.row += row_delta;
11124                            selection.end.row += row_delta;
11125                            selection
11126                        },
11127                    ));
11128
11129                    // Move folds down
11130                    unfold_ranges.push(range_to_move.clone());
11131                    for fold in display_map.folds_in_range(
11132                        buffer.anchor_before(range_to_move.start)
11133                            ..buffer.anchor_after(range_to_move.end),
11134                    ) {
11135                        let mut start = fold.range.start.to_point(&buffer);
11136                        let mut end = fold.range.end.to_point(&buffer);
11137                        start.row += row_delta;
11138                        end.row += row_delta;
11139                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11140                    }
11141                }
11142            }
11143
11144            // If we didn't move line(s), preserve the existing selections
11145            new_selections.append(&mut contiguous_row_selections);
11146        }
11147
11148        self.transact(window, cx, |this, window, cx| {
11149            this.unfold_ranges(&unfold_ranges, true, true, cx);
11150            this.buffer.update(cx, |buffer, cx| {
11151                for (range, text) in edits {
11152                    buffer.edit([(range, text)], None, cx);
11153                }
11154            });
11155            this.fold_creases(refold_creases, true, window, cx);
11156            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11157                s.select(new_selections)
11158            });
11159        });
11160    }
11161
11162    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11163        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11164        let text_layout_details = &self.text_layout_details(window);
11165        self.transact(window, cx, |this, window, cx| {
11166            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11167                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11168                s.move_with(|display_map, selection| {
11169                    if !selection.is_empty() {
11170                        return;
11171                    }
11172
11173                    let mut head = selection.head();
11174                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11175                    if head.column() == display_map.line_len(head.row()) {
11176                        transpose_offset = display_map
11177                            .buffer_snapshot
11178                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11179                    }
11180
11181                    if transpose_offset == 0 {
11182                        return;
11183                    }
11184
11185                    *head.column_mut() += 1;
11186                    head = display_map.clip_point(head, Bias::Right);
11187                    let goal = SelectionGoal::HorizontalPosition(
11188                        display_map
11189                            .x_for_display_point(head, text_layout_details)
11190                            .into(),
11191                    );
11192                    selection.collapse_to(head, goal);
11193
11194                    let transpose_start = display_map
11195                        .buffer_snapshot
11196                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11197                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11198                        let transpose_end = display_map
11199                            .buffer_snapshot
11200                            .clip_offset(transpose_offset + 1, Bias::Right);
11201                        if let Some(ch) =
11202                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11203                        {
11204                            edits.push((transpose_start..transpose_offset, String::new()));
11205                            edits.push((transpose_end..transpose_end, ch.to_string()));
11206                        }
11207                    }
11208                });
11209                edits
11210            });
11211            this.buffer
11212                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11213            let selections = this.selections.all::<usize>(cx);
11214            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11215                s.select(selections);
11216            });
11217        });
11218    }
11219
11220    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11221        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11222        if self.mode.is_single_line() {
11223            cx.propagate();
11224            return;
11225        }
11226
11227        self.rewrap_impl(RewrapOptions::default(), cx)
11228    }
11229
11230    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11231        let buffer = self.buffer.read(cx).snapshot(cx);
11232        let selections = self.selections.all::<Point>(cx);
11233
11234        // Shrink and split selections to respect paragraph boundaries.
11235        let ranges = selections.into_iter().flat_map(|selection| {
11236            let language_settings = buffer.language_settings_at(selection.head(), cx);
11237            let language_scope = buffer.language_scope_at(selection.head());
11238
11239            let Some(start_row) = (selection.start.row..=selection.end.row)
11240                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11241            else {
11242                return vec![];
11243            };
11244            let Some(end_row) = (selection.start.row..=selection.end.row)
11245                .rev()
11246                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11247            else {
11248                return vec![];
11249            };
11250
11251            let mut row = start_row;
11252            let mut ranges = Vec::new();
11253            while let Some(blank_row) =
11254                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11255            {
11256                let next_paragraph_start = (blank_row + 1..=end_row)
11257                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11258                    .unwrap();
11259                ranges.push((
11260                    language_settings.clone(),
11261                    language_scope.clone(),
11262                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11263                ));
11264                row = next_paragraph_start;
11265            }
11266            ranges.push((
11267                language_settings.clone(),
11268                language_scope.clone(),
11269                Point::new(row, 0)..Point::new(end_row, 0),
11270            ));
11271
11272            ranges
11273        });
11274
11275        let mut edits = Vec::new();
11276        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11277
11278        for (language_settings, language_scope, range) in ranges {
11279            let mut start_row = range.start.row;
11280            let mut end_row = range.end.row;
11281
11282            // Skip selections that overlap with a range that has already been rewrapped.
11283            let selection_range = start_row..end_row;
11284            if rewrapped_row_ranges
11285                .iter()
11286                .any(|range| range.overlaps(&selection_range))
11287            {
11288                continue;
11289            }
11290
11291            let tab_size = language_settings.tab_size;
11292
11293            // Since not all lines in the selection may be at the same indent
11294            // level, choose the indent size that is the most common between all
11295            // of the lines.
11296            //
11297            // If there is a tie, we use the deepest indent.
11298            let (indent_size, indent_end) = {
11299                let mut indent_size_occurrences = HashMap::default();
11300                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11301
11302                for row in start_row..=end_row {
11303                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11304                    rows_by_indent_size.entry(indent).or_default().push(row);
11305                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11306                }
11307
11308                let indent_size = indent_size_occurrences
11309                    .into_iter()
11310                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11311                    .map(|(indent, _)| indent)
11312                    .unwrap_or_default();
11313                let row = rows_by_indent_size[&indent_size][0];
11314                let indent_end = Point::new(row, indent_size.len);
11315
11316                (indent_size, indent_end)
11317            };
11318
11319            let mut line_prefix = indent_size.chars().collect::<String>();
11320
11321            let mut inside_comment = false;
11322            if let Some(comment_prefix) = language_scope.and_then(|language| {
11323                language
11324                    .line_comment_prefixes()
11325                    .iter()
11326                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11327                    .cloned()
11328            }) {
11329                line_prefix.push_str(&comment_prefix);
11330                inside_comment = true;
11331            }
11332
11333            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11334                RewrapBehavior::InComments => inside_comment,
11335                RewrapBehavior::InSelections => !range.is_empty(),
11336                RewrapBehavior::Anywhere => true,
11337            };
11338
11339            let should_rewrap = options.override_language_settings
11340                || allow_rewrap_based_on_language
11341                || self.hard_wrap.is_some();
11342            if !should_rewrap {
11343                continue;
11344            }
11345
11346            if range.is_empty() {
11347                'expand_upwards: while start_row > 0 {
11348                    let prev_row = start_row - 1;
11349                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11350                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11351                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11352                    {
11353                        start_row = prev_row;
11354                    } else {
11355                        break 'expand_upwards;
11356                    }
11357                }
11358
11359                'expand_downwards: while end_row < buffer.max_point().row {
11360                    let next_row = end_row + 1;
11361                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11362                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11363                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11364                    {
11365                        end_row = next_row;
11366                    } else {
11367                        break 'expand_downwards;
11368                    }
11369                }
11370            }
11371
11372            let start = Point::new(start_row, 0);
11373            let start_offset = start.to_offset(&buffer);
11374            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11375            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11376            let Some(lines_without_prefixes) = selection_text
11377                .lines()
11378                .map(|line| {
11379                    line.strip_prefix(&line_prefix)
11380                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11381                        .with_context(|| {
11382                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11383                        })
11384                })
11385                .collect::<Result<Vec<_>, _>>()
11386                .log_err()
11387            else {
11388                continue;
11389            };
11390
11391            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11392                buffer
11393                    .language_settings_at(Point::new(start_row, 0), cx)
11394                    .preferred_line_length as usize
11395            });
11396            let wrapped_text = wrap_with_prefix(
11397                line_prefix,
11398                lines_without_prefixes.join("\n"),
11399                wrap_column,
11400                tab_size,
11401                options.preserve_existing_whitespace,
11402            );
11403
11404            // TODO: should always use char-based diff while still supporting cursor behavior that
11405            // matches vim.
11406            let mut diff_options = DiffOptions::default();
11407            if options.override_language_settings {
11408                diff_options.max_word_diff_len = 0;
11409                diff_options.max_word_diff_line_count = 0;
11410            } else {
11411                diff_options.max_word_diff_len = usize::MAX;
11412                diff_options.max_word_diff_line_count = usize::MAX;
11413            }
11414
11415            for (old_range, new_text) in
11416                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11417            {
11418                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11419                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11420                edits.push((edit_start..edit_end, new_text));
11421            }
11422
11423            rewrapped_row_ranges.push(start_row..=end_row);
11424        }
11425
11426        self.buffer
11427            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11428    }
11429
11430    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11431        let mut text = String::new();
11432        let buffer = self.buffer.read(cx).snapshot(cx);
11433        let mut selections = self.selections.all::<Point>(cx);
11434        let mut clipboard_selections = Vec::with_capacity(selections.len());
11435        {
11436            let max_point = buffer.max_point();
11437            let mut is_first = true;
11438            for selection in &mut selections {
11439                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11440                if is_entire_line {
11441                    selection.start = Point::new(selection.start.row, 0);
11442                    if !selection.is_empty() && selection.end.column == 0 {
11443                        selection.end = cmp::min(max_point, selection.end);
11444                    } else {
11445                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11446                    }
11447                    selection.goal = SelectionGoal::None;
11448                }
11449                if is_first {
11450                    is_first = false;
11451                } else {
11452                    text += "\n";
11453                }
11454                let mut len = 0;
11455                for chunk in buffer.text_for_range(selection.start..selection.end) {
11456                    text.push_str(chunk);
11457                    len += chunk.len();
11458                }
11459                clipboard_selections.push(ClipboardSelection {
11460                    len,
11461                    is_entire_line,
11462                    first_line_indent: buffer
11463                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11464                        .len,
11465                });
11466            }
11467        }
11468
11469        self.transact(window, cx, |this, window, cx| {
11470            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11471                s.select(selections);
11472            });
11473            this.insert("", window, cx);
11474        });
11475        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11476    }
11477
11478    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11479        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11480        let item = self.cut_common(window, cx);
11481        cx.write_to_clipboard(item);
11482    }
11483
11484    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11485        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11486        self.change_selections(None, window, cx, |s| {
11487            s.move_with(|snapshot, sel| {
11488                if sel.is_empty() {
11489                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11490                }
11491            });
11492        });
11493        let item = self.cut_common(window, cx);
11494        cx.set_global(KillRing(item))
11495    }
11496
11497    pub fn kill_ring_yank(
11498        &mut self,
11499        _: &KillRingYank,
11500        window: &mut Window,
11501        cx: &mut Context<Self>,
11502    ) {
11503        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11504        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11505            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11506                (kill_ring.text().to_string(), kill_ring.metadata_json())
11507            } else {
11508                return;
11509            }
11510        } else {
11511            return;
11512        };
11513        self.do_paste(&text, metadata, false, window, cx);
11514    }
11515
11516    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11517        self.do_copy(true, cx);
11518    }
11519
11520    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11521        self.do_copy(false, cx);
11522    }
11523
11524    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11525        let selections = self.selections.all::<Point>(cx);
11526        let buffer = self.buffer.read(cx).read(cx);
11527        let mut text = String::new();
11528
11529        let mut clipboard_selections = Vec::with_capacity(selections.len());
11530        {
11531            let max_point = buffer.max_point();
11532            let mut is_first = true;
11533            for selection in &selections {
11534                let mut start = selection.start;
11535                let mut end = selection.end;
11536                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11537                if is_entire_line {
11538                    start = Point::new(start.row, 0);
11539                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11540                }
11541
11542                let mut trimmed_selections = Vec::new();
11543                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11544                    let row = MultiBufferRow(start.row);
11545                    let first_indent = buffer.indent_size_for_line(row);
11546                    if first_indent.len == 0 || start.column > first_indent.len {
11547                        trimmed_selections.push(start..end);
11548                    } else {
11549                        trimmed_selections.push(
11550                            Point::new(row.0, first_indent.len)
11551                                ..Point::new(row.0, buffer.line_len(row)),
11552                        );
11553                        for row in start.row + 1..=end.row {
11554                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11555                            if row == end.row {
11556                                line_len = end.column;
11557                            }
11558                            if line_len == 0 {
11559                                trimmed_selections
11560                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11561                                continue;
11562                            }
11563                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11564                            if row_indent_size.len >= first_indent.len {
11565                                trimmed_selections.push(
11566                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11567                                );
11568                            } else {
11569                                trimmed_selections.clear();
11570                                trimmed_selections.push(start..end);
11571                                break;
11572                            }
11573                        }
11574                    }
11575                } else {
11576                    trimmed_selections.push(start..end);
11577                }
11578
11579                for trimmed_range in trimmed_selections {
11580                    if is_first {
11581                        is_first = false;
11582                    } else {
11583                        text += "\n";
11584                    }
11585                    let mut len = 0;
11586                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11587                        text.push_str(chunk);
11588                        len += chunk.len();
11589                    }
11590                    clipboard_selections.push(ClipboardSelection {
11591                        len,
11592                        is_entire_line,
11593                        first_line_indent: buffer
11594                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11595                            .len,
11596                    });
11597                }
11598            }
11599        }
11600
11601        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11602            text,
11603            clipboard_selections,
11604        ));
11605    }
11606
11607    pub fn do_paste(
11608        &mut self,
11609        text: &String,
11610        clipboard_selections: Option<Vec<ClipboardSelection>>,
11611        handle_entire_lines: bool,
11612        window: &mut Window,
11613        cx: &mut Context<Self>,
11614    ) {
11615        if self.read_only(cx) {
11616            return;
11617        }
11618
11619        let clipboard_text = Cow::Borrowed(text);
11620
11621        self.transact(window, cx, |this, window, cx| {
11622            if let Some(mut clipboard_selections) = clipboard_selections {
11623                let old_selections = this.selections.all::<usize>(cx);
11624                let all_selections_were_entire_line =
11625                    clipboard_selections.iter().all(|s| s.is_entire_line);
11626                let first_selection_indent_column =
11627                    clipboard_selections.first().map(|s| s.first_line_indent);
11628                if clipboard_selections.len() != old_selections.len() {
11629                    clipboard_selections.drain(..);
11630                }
11631                let cursor_offset = this.selections.last::<usize>(cx).head();
11632                let mut auto_indent_on_paste = true;
11633
11634                this.buffer.update(cx, |buffer, cx| {
11635                    let snapshot = buffer.read(cx);
11636                    auto_indent_on_paste = snapshot
11637                        .language_settings_at(cursor_offset, cx)
11638                        .auto_indent_on_paste;
11639
11640                    let mut start_offset = 0;
11641                    let mut edits = Vec::new();
11642                    let mut original_indent_columns = Vec::new();
11643                    for (ix, selection) in old_selections.iter().enumerate() {
11644                        let to_insert;
11645                        let entire_line;
11646                        let original_indent_column;
11647                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11648                            let end_offset = start_offset + clipboard_selection.len;
11649                            to_insert = &clipboard_text[start_offset..end_offset];
11650                            entire_line = clipboard_selection.is_entire_line;
11651                            start_offset = end_offset + 1;
11652                            original_indent_column = Some(clipboard_selection.first_line_indent);
11653                        } else {
11654                            to_insert = clipboard_text.as_str();
11655                            entire_line = all_selections_were_entire_line;
11656                            original_indent_column = first_selection_indent_column
11657                        }
11658
11659                        // If the corresponding selection was empty when this slice of the
11660                        // clipboard text was written, then the entire line containing the
11661                        // selection was copied. If this selection is also currently empty,
11662                        // then paste the line before the current line of the buffer.
11663                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11664                            let column = selection.start.to_point(&snapshot).column as usize;
11665                            let line_start = selection.start - column;
11666                            line_start..line_start
11667                        } else {
11668                            selection.range()
11669                        };
11670
11671                        edits.push((range, to_insert));
11672                        original_indent_columns.push(original_indent_column);
11673                    }
11674                    drop(snapshot);
11675
11676                    buffer.edit(
11677                        edits,
11678                        if auto_indent_on_paste {
11679                            Some(AutoindentMode::Block {
11680                                original_indent_columns,
11681                            })
11682                        } else {
11683                            None
11684                        },
11685                        cx,
11686                    );
11687                });
11688
11689                let selections = this.selections.all::<usize>(cx);
11690                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11691                    s.select(selections)
11692                });
11693            } else {
11694                this.insert(&clipboard_text, window, cx);
11695            }
11696        });
11697    }
11698
11699    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11700        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11701        if let Some(item) = cx.read_from_clipboard() {
11702            let entries = item.entries();
11703
11704            match entries.first() {
11705                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11706                // of all the pasted entries.
11707                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11708                    .do_paste(
11709                        clipboard_string.text(),
11710                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11711                        true,
11712                        window,
11713                        cx,
11714                    ),
11715                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11716            }
11717        }
11718    }
11719
11720    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11721        if self.read_only(cx) {
11722            return;
11723        }
11724
11725        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11726
11727        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11728            if let Some((selections, _)) =
11729                self.selection_history.transaction(transaction_id).cloned()
11730            {
11731                self.change_selections(None, window, cx, |s| {
11732                    s.select_anchors(selections.to_vec());
11733                });
11734            } else {
11735                log::error!(
11736                    "No entry in selection_history found for undo. \
11737                     This may correspond to a bug where undo does not update the selection. \
11738                     If this is occurring, please add details to \
11739                     https://github.com/zed-industries/zed/issues/22692"
11740                );
11741            }
11742            self.request_autoscroll(Autoscroll::fit(), cx);
11743            self.unmark_text(window, cx);
11744            self.refresh_inline_completion(true, false, window, cx);
11745            cx.emit(EditorEvent::Edited { transaction_id });
11746            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11747        }
11748    }
11749
11750    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11751        if self.read_only(cx) {
11752            return;
11753        }
11754
11755        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11756
11757        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11758            if let Some((_, Some(selections))) =
11759                self.selection_history.transaction(transaction_id).cloned()
11760            {
11761                self.change_selections(None, window, cx, |s| {
11762                    s.select_anchors(selections.to_vec());
11763                });
11764            } else {
11765                log::error!(
11766                    "No entry in selection_history found for redo. \
11767                     This may correspond to a bug where undo does not update the selection. \
11768                     If this is occurring, please add details to \
11769                     https://github.com/zed-industries/zed/issues/22692"
11770                );
11771            }
11772            self.request_autoscroll(Autoscroll::fit(), cx);
11773            self.unmark_text(window, cx);
11774            self.refresh_inline_completion(true, false, window, cx);
11775            cx.emit(EditorEvent::Edited { transaction_id });
11776        }
11777    }
11778
11779    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11780        self.buffer
11781            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11782    }
11783
11784    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11785        self.buffer
11786            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11787    }
11788
11789    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11790        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11791        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11792            s.move_with(|map, selection| {
11793                let cursor = if selection.is_empty() {
11794                    movement::left(map, selection.start)
11795                } else {
11796                    selection.start
11797                };
11798                selection.collapse_to(cursor, SelectionGoal::None);
11799            });
11800        })
11801    }
11802
11803    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11804        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11805        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11806            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11807        })
11808    }
11809
11810    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11811        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11812        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11813            s.move_with(|map, selection| {
11814                let cursor = if selection.is_empty() {
11815                    movement::right(map, selection.end)
11816                } else {
11817                    selection.end
11818                };
11819                selection.collapse_to(cursor, SelectionGoal::None)
11820            });
11821        })
11822    }
11823
11824    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11826        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11827            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11828        })
11829    }
11830
11831    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11832        if self.take_rename(true, window, cx).is_some() {
11833            return;
11834        }
11835
11836        if self.mode.is_single_line() {
11837            cx.propagate();
11838            return;
11839        }
11840
11841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11842
11843        let text_layout_details = &self.text_layout_details(window);
11844        let selection_count = self.selections.count();
11845        let first_selection = self.selections.first_anchor();
11846
11847        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11848            s.move_with(|map, selection| {
11849                if !selection.is_empty() {
11850                    selection.goal = SelectionGoal::None;
11851                }
11852                let (cursor, goal) = movement::up(
11853                    map,
11854                    selection.start,
11855                    selection.goal,
11856                    false,
11857                    text_layout_details,
11858                );
11859                selection.collapse_to(cursor, goal);
11860            });
11861        });
11862
11863        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11864        {
11865            cx.propagate();
11866        }
11867    }
11868
11869    pub fn move_up_by_lines(
11870        &mut self,
11871        action: &MoveUpByLines,
11872        window: &mut Window,
11873        cx: &mut Context<Self>,
11874    ) {
11875        if self.take_rename(true, window, cx).is_some() {
11876            return;
11877        }
11878
11879        if self.mode.is_single_line() {
11880            cx.propagate();
11881            return;
11882        }
11883
11884        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11885
11886        let text_layout_details = &self.text_layout_details(window);
11887
11888        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11889            s.move_with(|map, selection| {
11890                if !selection.is_empty() {
11891                    selection.goal = SelectionGoal::None;
11892                }
11893                let (cursor, goal) = movement::up_by_rows(
11894                    map,
11895                    selection.start,
11896                    action.lines,
11897                    selection.goal,
11898                    false,
11899                    text_layout_details,
11900                );
11901                selection.collapse_to(cursor, goal);
11902            });
11903        })
11904    }
11905
11906    pub fn move_down_by_lines(
11907        &mut self,
11908        action: &MoveDownByLines,
11909        window: &mut Window,
11910        cx: &mut Context<Self>,
11911    ) {
11912        if self.take_rename(true, window, cx).is_some() {
11913            return;
11914        }
11915
11916        if self.mode.is_single_line() {
11917            cx.propagate();
11918            return;
11919        }
11920
11921        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11922
11923        let text_layout_details = &self.text_layout_details(window);
11924
11925        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11926            s.move_with(|map, selection| {
11927                if !selection.is_empty() {
11928                    selection.goal = SelectionGoal::None;
11929                }
11930                let (cursor, goal) = movement::down_by_rows(
11931                    map,
11932                    selection.start,
11933                    action.lines,
11934                    selection.goal,
11935                    false,
11936                    text_layout_details,
11937                );
11938                selection.collapse_to(cursor, goal);
11939            });
11940        })
11941    }
11942
11943    pub fn select_down_by_lines(
11944        &mut self,
11945        action: &SelectDownByLines,
11946        window: &mut Window,
11947        cx: &mut Context<Self>,
11948    ) {
11949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11950        let text_layout_details = &self.text_layout_details(window);
11951        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11952            s.move_heads_with(|map, head, goal| {
11953                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11954            })
11955        })
11956    }
11957
11958    pub fn select_up_by_lines(
11959        &mut self,
11960        action: &SelectUpByLines,
11961        window: &mut Window,
11962        cx: &mut Context<Self>,
11963    ) {
11964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11965        let text_layout_details = &self.text_layout_details(window);
11966        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11967            s.move_heads_with(|map, head, goal| {
11968                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11969            })
11970        })
11971    }
11972
11973    pub fn select_page_up(
11974        &mut self,
11975        _: &SelectPageUp,
11976        window: &mut Window,
11977        cx: &mut Context<Self>,
11978    ) {
11979        let Some(row_count) = self.visible_row_count() else {
11980            return;
11981        };
11982
11983        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11984
11985        let text_layout_details = &self.text_layout_details(window);
11986
11987        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11988            s.move_heads_with(|map, head, goal| {
11989                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11990            })
11991        })
11992    }
11993
11994    pub fn move_page_up(
11995        &mut self,
11996        action: &MovePageUp,
11997        window: &mut Window,
11998        cx: &mut Context<Self>,
11999    ) {
12000        if self.take_rename(true, window, cx).is_some() {
12001            return;
12002        }
12003
12004        if self
12005            .context_menu
12006            .borrow_mut()
12007            .as_mut()
12008            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12009            .unwrap_or(false)
12010        {
12011            return;
12012        }
12013
12014        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12015            cx.propagate();
12016            return;
12017        }
12018
12019        let Some(row_count) = self.visible_row_count() else {
12020            return;
12021        };
12022
12023        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12024
12025        let autoscroll = if action.center_cursor {
12026            Autoscroll::center()
12027        } else {
12028            Autoscroll::fit()
12029        };
12030
12031        let text_layout_details = &self.text_layout_details(window);
12032
12033        self.change_selections(Some(autoscroll), window, cx, |s| {
12034            s.move_with(|map, selection| {
12035                if !selection.is_empty() {
12036                    selection.goal = SelectionGoal::None;
12037                }
12038                let (cursor, goal) = movement::up_by_rows(
12039                    map,
12040                    selection.end,
12041                    row_count,
12042                    selection.goal,
12043                    false,
12044                    text_layout_details,
12045                );
12046                selection.collapse_to(cursor, goal);
12047            });
12048        });
12049    }
12050
12051    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12052        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12053        let text_layout_details = &self.text_layout_details(window);
12054        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12055            s.move_heads_with(|map, head, goal| {
12056                movement::up(map, head, goal, false, text_layout_details)
12057            })
12058        })
12059    }
12060
12061    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12062        self.take_rename(true, window, cx);
12063
12064        if self.mode.is_single_line() {
12065            cx.propagate();
12066            return;
12067        }
12068
12069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12070
12071        let text_layout_details = &self.text_layout_details(window);
12072        let selection_count = self.selections.count();
12073        let first_selection = self.selections.first_anchor();
12074
12075        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12076            s.move_with(|map, selection| {
12077                if !selection.is_empty() {
12078                    selection.goal = SelectionGoal::None;
12079                }
12080                let (cursor, goal) = movement::down(
12081                    map,
12082                    selection.end,
12083                    selection.goal,
12084                    false,
12085                    text_layout_details,
12086                );
12087                selection.collapse_to(cursor, goal);
12088            });
12089        });
12090
12091        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12092        {
12093            cx.propagate();
12094        }
12095    }
12096
12097    pub fn select_page_down(
12098        &mut self,
12099        _: &SelectPageDown,
12100        window: &mut Window,
12101        cx: &mut Context<Self>,
12102    ) {
12103        let Some(row_count) = self.visible_row_count() else {
12104            return;
12105        };
12106
12107        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12108
12109        let text_layout_details = &self.text_layout_details(window);
12110
12111        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12112            s.move_heads_with(|map, head, goal| {
12113                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12114            })
12115        })
12116    }
12117
12118    pub fn move_page_down(
12119        &mut self,
12120        action: &MovePageDown,
12121        window: &mut Window,
12122        cx: &mut Context<Self>,
12123    ) {
12124        if self.take_rename(true, window, cx).is_some() {
12125            return;
12126        }
12127
12128        if self
12129            .context_menu
12130            .borrow_mut()
12131            .as_mut()
12132            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12133            .unwrap_or(false)
12134        {
12135            return;
12136        }
12137
12138        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12139            cx.propagate();
12140            return;
12141        }
12142
12143        let Some(row_count) = self.visible_row_count() else {
12144            return;
12145        };
12146
12147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12148
12149        let autoscroll = if action.center_cursor {
12150            Autoscroll::center()
12151        } else {
12152            Autoscroll::fit()
12153        };
12154
12155        let text_layout_details = &self.text_layout_details(window);
12156        self.change_selections(Some(autoscroll), window, cx, |s| {
12157            s.move_with(|map, selection| {
12158                if !selection.is_empty() {
12159                    selection.goal = SelectionGoal::None;
12160                }
12161                let (cursor, goal) = movement::down_by_rows(
12162                    map,
12163                    selection.end,
12164                    row_count,
12165                    selection.goal,
12166                    false,
12167                    text_layout_details,
12168                );
12169                selection.collapse_to(cursor, goal);
12170            });
12171        });
12172    }
12173
12174    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12175        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12176        let text_layout_details = &self.text_layout_details(window);
12177        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12178            s.move_heads_with(|map, head, goal| {
12179                movement::down(map, head, goal, false, text_layout_details)
12180            })
12181        });
12182    }
12183
12184    pub fn context_menu_first(
12185        &mut self,
12186        _: &ContextMenuFirst,
12187        window: &mut Window,
12188        cx: &mut Context<Self>,
12189    ) {
12190        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12191            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12192        }
12193    }
12194
12195    pub fn context_menu_prev(
12196        &mut self,
12197        _: &ContextMenuPrevious,
12198        window: &mut Window,
12199        cx: &mut Context<Self>,
12200    ) {
12201        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12202            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12203        }
12204    }
12205
12206    pub fn context_menu_next(
12207        &mut self,
12208        _: &ContextMenuNext,
12209        window: &mut Window,
12210        cx: &mut Context<Self>,
12211    ) {
12212        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12213            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12214        }
12215    }
12216
12217    pub fn context_menu_last(
12218        &mut self,
12219        _: &ContextMenuLast,
12220        window: &mut Window,
12221        cx: &mut Context<Self>,
12222    ) {
12223        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12224            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12225        }
12226    }
12227
12228    pub fn move_to_previous_word_start(
12229        &mut self,
12230        _: &MoveToPreviousWordStart,
12231        window: &mut Window,
12232        cx: &mut Context<Self>,
12233    ) {
12234        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12235        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12236            s.move_cursors_with(|map, head, _| {
12237                (
12238                    movement::previous_word_start(map, head),
12239                    SelectionGoal::None,
12240                )
12241            });
12242        })
12243    }
12244
12245    pub fn move_to_previous_subword_start(
12246        &mut self,
12247        _: &MoveToPreviousSubwordStart,
12248        window: &mut Window,
12249        cx: &mut Context<Self>,
12250    ) {
12251        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12252        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12253            s.move_cursors_with(|map, head, _| {
12254                (
12255                    movement::previous_subword_start(map, head),
12256                    SelectionGoal::None,
12257                )
12258            });
12259        })
12260    }
12261
12262    pub fn select_to_previous_word_start(
12263        &mut self,
12264        _: &SelectToPreviousWordStart,
12265        window: &mut Window,
12266        cx: &mut Context<Self>,
12267    ) {
12268        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12269        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12270            s.move_heads_with(|map, head, _| {
12271                (
12272                    movement::previous_word_start(map, head),
12273                    SelectionGoal::None,
12274                )
12275            });
12276        })
12277    }
12278
12279    pub fn select_to_previous_subword_start(
12280        &mut self,
12281        _: &SelectToPreviousSubwordStart,
12282        window: &mut Window,
12283        cx: &mut Context<Self>,
12284    ) {
12285        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12286        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12287            s.move_heads_with(|map, head, _| {
12288                (
12289                    movement::previous_subword_start(map, head),
12290                    SelectionGoal::None,
12291                )
12292            });
12293        })
12294    }
12295
12296    pub fn delete_to_previous_word_start(
12297        &mut self,
12298        action: &DeleteToPreviousWordStart,
12299        window: &mut Window,
12300        cx: &mut Context<Self>,
12301    ) {
12302        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12303        self.transact(window, cx, |this, window, cx| {
12304            this.select_autoclose_pair(window, cx);
12305            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12306                s.move_with(|map, selection| {
12307                    if selection.is_empty() {
12308                        let cursor = if action.ignore_newlines {
12309                            movement::previous_word_start(map, selection.head())
12310                        } else {
12311                            movement::previous_word_start_or_newline(map, selection.head())
12312                        };
12313                        selection.set_head(cursor, SelectionGoal::None);
12314                    }
12315                });
12316            });
12317            this.insert("", window, cx);
12318        });
12319    }
12320
12321    pub fn delete_to_previous_subword_start(
12322        &mut self,
12323        _: &DeleteToPreviousSubwordStart,
12324        window: &mut Window,
12325        cx: &mut Context<Self>,
12326    ) {
12327        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12328        self.transact(window, cx, |this, window, cx| {
12329            this.select_autoclose_pair(window, cx);
12330            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12331                s.move_with(|map, selection| {
12332                    if selection.is_empty() {
12333                        let cursor = movement::previous_subword_start(map, selection.head());
12334                        selection.set_head(cursor, SelectionGoal::None);
12335                    }
12336                });
12337            });
12338            this.insert("", window, cx);
12339        });
12340    }
12341
12342    pub fn move_to_next_word_end(
12343        &mut self,
12344        _: &MoveToNextWordEnd,
12345        window: &mut Window,
12346        cx: &mut Context<Self>,
12347    ) {
12348        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12349        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12350            s.move_cursors_with(|map, head, _| {
12351                (movement::next_word_end(map, head), SelectionGoal::None)
12352            });
12353        })
12354    }
12355
12356    pub fn move_to_next_subword_end(
12357        &mut self,
12358        _: &MoveToNextSubwordEnd,
12359        window: &mut Window,
12360        cx: &mut Context<Self>,
12361    ) {
12362        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12363        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12364            s.move_cursors_with(|map, head, _| {
12365                (movement::next_subword_end(map, head), SelectionGoal::None)
12366            });
12367        })
12368    }
12369
12370    pub fn select_to_next_word_end(
12371        &mut self,
12372        _: &SelectToNextWordEnd,
12373        window: &mut Window,
12374        cx: &mut Context<Self>,
12375    ) {
12376        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12377        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12378            s.move_heads_with(|map, head, _| {
12379                (movement::next_word_end(map, head), SelectionGoal::None)
12380            });
12381        })
12382    }
12383
12384    pub fn select_to_next_subword_end(
12385        &mut self,
12386        _: &SelectToNextSubwordEnd,
12387        window: &mut Window,
12388        cx: &mut Context<Self>,
12389    ) {
12390        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12391        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12392            s.move_heads_with(|map, head, _| {
12393                (movement::next_subword_end(map, head), SelectionGoal::None)
12394            });
12395        })
12396    }
12397
12398    pub fn delete_to_next_word_end(
12399        &mut self,
12400        action: &DeleteToNextWordEnd,
12401        window: &mut Window,
12402        cx: &mut Context<Self>,
12403    ) {
12404        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12405        self.transact(window, cx, |this, window, cx| {
12406            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12407                s.move_with(|map, selection| {
12408                    if selection.is_empty() {
12409                        let cursor = if action.ignore_newlines {
12410                            movement::next_word_end(map, selection.head())
12411                        } else {
12412                            movement::next_word_end_or_newline(map, selection.head())
12413                        };
12414                        selection.set_head(cursor, SelectionGoal::None);
12415                    }
12416                });
12417            });
12418            this.insert("", window, cx);
12419        });
12420    }
12421
12422    pub fn delete_to_next_subword_end(
12423        &mut self,
12424        _: &DeleteToNextSubwordEnd,
12425        window: &mut Window,
12426        cx: &mut Context<Self>,
12427    ) {
12428        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12429        self.transact(window, cx, |this, window, cx| {
12430            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12431                s.move_with(|map, selection| {
12432                    if selection.is_empty() {
12433                        let cursor = movement::next_subword_end(map, selection.head());
12434                        selection.set_head(cursor, SelectionGoal::None);
12435                    }
12436                });
12437            });
12438            this.insert("", window, cx);
12439        });
12440    }
12441
12442    pub fn move_to_beginning_of_line(
12443        &mut self,
12444        action: &MoveToBeginningOfLine,
12445        window: &mut Window,
12446        cx: &mut Context<Self>,
12447    ) {
12448        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12449        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12450            s.move_cursors_with(|map, head, _| {
12451                (
12452                    movement::indented_line_beginning(
12453                        map,
12454                        head,
12455                        action.stop_at_soft_wraps,
12456                        action.stop_at_indent,
12457                    ),
12458                    SelectionGoal::None,
12459                )
12460            });
12461        })
12462    }
12463
12464    pub fn select_to_beginning_of_line(
12465        &mut self,
12466        action: &SelectToBeginningOfLine,
12467        window: &mut Window,
12468        cx: &mut Context<Self>,
12469    ) {
12470        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12471        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12472            s.move_heads_with(|map, head, _| {
12473                (
12474                    movement::indented_line_beginning(
12475                        map,
12476                        head,
12477                        action.stop_at_soft_wraps,
12478                        action.stop_at_indent,
12479                    ),
12480                    SelectionGoal::None,
12481                )
12482            });
12483        });
12484    }
12485
12486    pub fn delete_to_beginning_of_line(
12487        &mut self,
12488        action: &DeleteToBeginningOfLine,
12489        window: &mut Window,
12490        cx: &mut Context<Self>,
12491    ) {
12492        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12493        self.transact(window, cx, |this, window, cx| {
12494            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12495                s.move_with(|_, selection| {
12496                    selection.reversed = true;
12497                });
12498            });
12499
12500            this.select_to_beginning_of_line(
12501                &SelectToBeginningOfLine {
12502                    stop_at_soft_wraps: false,
12503                    stop_at_indent: action.stop_at_indent,
12504                },
12505                window,
12506                cx,
12507            );
12508            this.backspace(&Backspace, window, cx);
12509        });
12510    }
12511
12512    pub fn move_to_end_of_line(
12513        &mut self,
12514        action: &MoveToEndOfLine,
12515        window: &mut Window,
12516        cx: &mut Context<Self>,
12517    ) {
12518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12519        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12520            s.move_cursors_with(|map, head, _| {
12521                (
12522                    movement::line_end(map, head, action.stop_at_soft_wraps),
12523                    SelectionGoal::None,
12524                )
12525            });
12526        })
12527    }
12528
12529    pub fn select_to_end_of_line(
12530        &mut self,
12531        action: &SelectToEndOfLine,
12532        window: &mut Window,
12533        cx: &mut Context<Self>,
12534    ) {
12535        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12536        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12537            s.move_heads_with(|map, head, _| {
12538                (
12539                    movement::line_end(map, head, action.stop_at_soft_wraps),
12540                    SelectionGoal::None,
12541                )
12542            });
12543        })
12544    }
12545
12546    pub fn delete_to_end_of_line(
12547        &mut self,
12548        _: &DeleteToEndOfLine,
12549        window: &mut Window,
12550        cx: &mut Context<Self>,
12551    ) {
12552        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12553        self.transact(window, cx, |this, window, cx| {
12554            this.select_to_end_of_line(
12555                &SelectToEndOfLine {
12556                    stop_at_soft_wraps: false,
12557                },
12558                window,
12559                cx,
12560            );
12561            this.delete(&Delete, window, cx);
12562        });
12563    }
12564
12565    pub fn cut_to_end_of_line(
12566        &mut self,
12567        _: &CutToEndOfLine,
12568        window: &mut Window,
12569        cx: &mut Context<Self>,
12570    ) {
12571        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12572        self.transact(window, cx, |this, window, cx| {
12573            this.select_to_end_of_line(
12574                &SelectToEndOfLine {
12575                    stop_at_soft_wraps: false,
12576                },
12577                window,
12578                cx,
12579            );
12580            this.cut(&Cut, window, cx);
12581        });
12582    }
12583
12584    pub fn move_to_start_of_paragraph(
12585        &mut self,
12586        _: &MoveToStartOfParagraph,
12587        window: &mut Window,
12588        cx: &mut Context<Self>,
12589    ) {
12590        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12591            cx.propagate();
12592            return;
12593        }
12594        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12595        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12596            s.move_with(|map, selection| {
12597                selection.collapse_to(
12598                    movement::start_of_paragraph(map, selection.head(), 1),
12599                    SelectionGoal::None,
12600                )
12601            });
12602        })
12603    }
12604
12605    pub fn move_to_end_of_paragraph(
12606        &mut self,
12607        _: &MoveToEndOfParagraph,
12608        window: &mut Window,
12609        cx: &mut Context<Self>,
12610    ) {
12611        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12612            cx.propagate();
12613            return;
12614        }
12615        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12616        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12617            s.move_with(|map, selection| {
12618                selection.collapse_to(
12619                    movement::end_of_paragraph(map, selection.head(), 1),
12620                    SelectionGoal::None,
12621                )
12622            });
12623        })
12624    }
12625
12626    pub fn select_to_start_of_paragraph(
12627        &mut self,
12628        _: &SelectToStartOfParagraph,
12629        window: &mut Window,
12630        cx: &mut Context<Self>,
12631    ) {
12632        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12633            cx.propagate();
12634            return;
12635        }
12636        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12637        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12638            s.move_heads_with(|map, head, _| {
12639                (
12640                    movement::start_of_paragraph(map, head, 1),
12641                    SelectionGoal::None,
12642                )
12643            });
12644        })
12645    }
12646
12647    pub fn select_to_end_of_paragraph(
12648        &mut self,
12649        _: &SelectToEndOfParagraph,
12650        window: &mut Window,
12651        cx: &mut Context<Self>,
12652    ) {
12653        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12654            cx.propagate();
12655            return;
12656        }
12657        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12658        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12659            s.move_heads_with(|map, head, _| {
12660                (
12661                    movement::end_of_paragraph(map, head, 1),
12662                    SelectionGoal::None,
12663                )
12664            });
12665        })
12666    }
12667
12668    pub fn move_to_start_of_excerpt(
12669        &mut self,
12670        _: &MoveToStartOfExcerpt,
12671        window: &mut Window,
12672        cx: &mut Context<Self>,
12673    ) {
12674        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12675            cx.propagate();
12676            return;
12677        }
12678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12679        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12680            s.move_with(|map, selection| {
12681                selection.collapse_to(
12682                    movement::start_of_excerpt(
12683                        map,
12684                        selection.head(),
12685                        workspace::searchable::Direction::Prev,
12686                    ),
12687                    SelectionGoal::None,
12688                )
12689            });
12690        })
12691    }
12692
12693    pub fn move_to_start_of_next_excerpt(
12694        &mut self,
12695        _: &MoveToStartOfNextExcerpt,
12696        window: &mut Window,
12697        cx: &mut Context<Self>,
12698    ) {
12699        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12700            cx.propagate();
12701            return;
12702        }
12703
12704        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12705            s.move_with(|map, selection| {
12706                selection.collapse_to(
12707                    movement::start_of_excerpt(
12708                        map,
12709                        selection.head(),
12710                        workspace::searchable::Direction::Next,
12711                    ),
12712                    SelectionGoal::None,
12713                )
12714            });
12715        })
12716    }
12717
12718    pub fn move_to_end_of_excerpt(
12719        &mut self,
12720        _: &MoveToEndOfExcerpt,
12721        window: &mut Window,
12722        cx: &mut Context<Self>,
12723    ) {
12724        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12725            cx.propagate();
12726            return;
12727        }
12728        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12729        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12730            s.move_with(|map, selection| {
12731                selection.collapse_to(
12732                    movement::end_of_excerpt(
12733                        map,
12734                        selection.head(),
12735                        workspace::searchable::Direction::Next,
12736                    ),
12737                    SelectionGoal::None,
12738                )
12739            });
12740        })
12741    }
12742
12743    pub fn move_to_end_of_previous_excerpt(
12744        &mut self,
12745        _: &MoveToEndOfPreviousExcerpt,
12746        window: &mut Window,
12747        cx: &mut Context<Self>,
12748    ) {
12749        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12750            cx.propagate();
12751            return;
12752        }
12753        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12754        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12755            s.move_with(|map, selection| {
12756                selection.collapse_to(
12757                    movement::end_of_excerpt(
12758                        map,
12759                        selection.head(),
12760                        workspace::searchable::Direction::Prev,
12761                    ),
12762                    SelectionGoal::None,
12763                )
12764            });
12765        })
12766    }
12767
12768    pub fn select_to_start_of_excerpt(
12769        &mut self,
12770        _: &SelectToStartOfExcerpt,
12771        window: &mut Window,
12772        cx: &mut Context<Self>,
12773    ) {
12774        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12775            cx.propagate();
12776            return;
12777        }
12778        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12779        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12780            s.move_heads_with(|map, head, _| {
12781                (
12782                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12783                    SelectionGoal::None,
12784                )
12785            });
12786        })
12787    }
12788
12789    pub fn select_to_start_of_next_excerpt(
12790        &mut self,
12791        _: &SelectToStartOfNextExcerpt,
12792        window: &mut Window,
12793        cx: &mut Context<Self>,
12794    ) {
12795        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12796            cx.propagate();
12797            return;
12798        }
12799        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12800        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12801            s.move_heads_with(|map, head, _| {
12802                (
12803                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12804                    SelectionGoal::None,
12805                )
12806            });
12807        })
12808    }
12809
12810    pub fn select_to_end_of_excerpt(
12811        &mut self,
12812        _: &SelectToEndOfExcerpt,
12813        window: &mut Window,
12814        cx: &mut Context<Self>,
12815    ) {
12816        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12817            cx.propagate();
12818            return;
12819        }
12820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12821        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12822            s.move_heads_with(|map, head, _| {
12823                (
12824                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12825                    SelectionGoal::None,
12826                )
12827            });
12828        })
12829    }
12830
12831    pub fn select_to_end_of_previous_excerpt(
12832        &mut self,
12833        _: &SelectToEndOfPreviousExcerpt,
12834        window: &mut Window,
12835        cx: &mut Context<Self>,
12836    ) {
12837        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12838            cx.propagate();
12839            return;
12840        }
12841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12842        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12843            s.move_heads_with(|map, head, _| {
12844                (
12845                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12846                    SelectionGoal::None,
12847                )
12848            });
12849        })
12850    }
12851
12852    pub fn move_to_beginning(
12853        &mut self,
12854        _: &MoveToBeginning,
12855        window: &mut Window,
12856        cx: &mut Context<Self>,
12857    ) {
12858        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12859            cx.propagate();
12860            return;
12861        }
12862        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12863        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12864            s.select_ranges(vec![0..0]);
12865        });
12866    }
12867
12868    pub fn select_to_beginning(
12869        &mut self,
12870        _: &SelectToBeginning,
12871        window: &mut Window,
12872        cx: &mut Context<Self>,
12873    ) {
12874        let mut selection = self.selections.last::<Point>(cx);
12875        selection.set_head(Point::zero(), SelectionGoal::None);
12876        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12877        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12878            s.select(vec![selection]);
12879        });
12880    }
12881
12882    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12883        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12884            cx.propagate();
12885            return;
12886        }
12887        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12888        let cursor = self.buffer.read(cx).read(cx).len();
12889        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12890            s.select_ranges(vec![cursor..cursor])
12891        });
12892    }
12893
12894    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12895        self.nav_history = nav_history;
12896    }
12897
12898    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12899        self.nav_history.as_ref()
12900    }
12901
12902    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12903        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12904    }
12905
12906    fn push_to_nav_history(
12907        &mut self,
12908        cursor_anchor: Anchor,
12909        new_position: Option<Point>,
12910        is_deactivate: bool,
12911        cx: &mut Context<Self>,
12912    ) {
12913        if let Some(nav_history) = self.nav_history.as_mut() {
12914            let buffer = self.buffer.read(cx).read(cx);
12915            let cursor_position = cursor_anchor.to_point(&buffer);
12916            let scroll_state = self.scroll_manager.anchor();
12917            let scroll_top_row = scroll_state.top_row(&buffer);
12918            drop(buffer);
12919
12920            if let Some(new_position) = new_position {
12921                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12922                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12923                    return;
12924                }
12925            }
12926
12927            nav_history.push(
12928                Some(NavigationData {
12929                    cursor_anchor,
12930                    cursor_position,
12931                    scroll_anchor: scroll_state,
12932                    scroll_top_row,
12933                }),
12934                cx,
12935            );
12936            cx.emit(EditorEvent::PushedToNavHistory {
12937                anchor: cursor_anchor,
12938                is_deactivate,
12939            })
12940        }
12941    }
12942
12943    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12944        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12945        let buffer = self.buffer.read(cx).snapshot(cx);
12946        let mut selection = self.selections.first::<usize>(cx);
12947        selection.set_head(buffer.len(), SelectionGoal::None);
12948        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12949            s.select(vec![selection]);
12950        });
12951    }
12952
12953    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12954        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12955        let end = self.buffer.read(cx).read(cx).len();
12956        self.change_selections(None, window, cx, |s| {
12957            s.select_ranges(vec![0..end]);
12958        });
12959    }
12960
12961    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12962        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12963        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12964        let mut selections = self.selections.all::<Point>(cx);
12965        let max_point = display_map.buffer_snapshot.max_point();
12966        for selection in &mut selections {
12967            let rows = selection.spanned_rows(true, &display_map);
12968            selection.start = Point::new(rows.start.0, 0);
12969            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12970            selection.reversed = false;
12971        }
12972        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12973            s.select(selections);
12974        });
12975    }
12976
12977    pub fn split_selection_into_lines(
12978        &mut self,
12979        _: &SplitSelectionIntoLines,
12980        window: &mut Window,
12981        cx: &mut Context<Self>,
12982    ) {
12983        let selections = self
12984            .selections
12985            .all::<Point>(cx)
12986            .into_iter()
12987            .map(|selection| selection.start..selection.end)
12988            .collect::<Vec<_>>();
12989        self.unfold_ranges(&selections, true, true, cx);
12990
12991        let mut new_selection_ranges = Vec::new();
12992        {
12993            let buffer = self.buffer.read(cx).read(cx);
12994            for selection in selections {
12995                for row in selection.start.row..selection.end.row {
12996                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12997                    new_selection_ranges.push(cursor..cursor);
12998                }
12999
13000                let is_multiline_selection = selection.start.row != selection.end.row;
13001                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13002                // so this action feels more ergonomic when paired with other selection operations
13003                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13004                if !should_skip_last {
13005                    new_selection_ranges.push(selection.end..selection.end);
13006                }
13007            }
13008        }
13009        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13010            s.select_ranges(new_selection_ranges);
13011        });
13012    }
13013
13014    pub fn add_selection_above(
13015        &mut self,
13016        _: &AddSelectionAbove,
13017        window: &mut Window,
13018        cx: &mut Context<Self>,
13019    ) {
13020        self.add_selection(true, window, cx);
13021    }
13022
13023    pub fn add_selection_below(
13024        &mut self,
13025        _: &AddSelectionBelow,
13026        window: &mut Window,
13027        cx: &mut Context<Self>,
13028    ) {
13029        self.add_selection(false, window, cx);
13030    }
13031
13032    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13033        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13034
13035        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13036        let all_selections = self.selections.all::<Point>(cx);
13037        let text_layout_details = self.text_layout_details(window);
13038
13039        let (mut columnar_selections, new_selections_to_columnarize) = {
13040            if let Some(state) = self.add_selections_state.as_ref() {
13041                let columnar_selection_ids: HashSet<_> = state
13042                    .groups
13043                    .iter()
13044                    .flat_map(|group| group.stack.iter())
13045                    .copied()
13046                    .collect();
13047
13048                all_selections
13049                    .into_iter()
13050                    .partition(|s| columnar_selection_ids.contains(&s.id))
13051            } else {
13052                (Vec::new(), all_selections)
13053            }
13054        };
13055
13056        let mut state = self
13057            .add_selections_state
13058            .take()
13059            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13060
13061        for selection in new_selections_to_columnarize {
13062            let range = selection.display_range(&display_map).sorted();
13063            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13064            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13065            let positions = start_x.min(end_x)..start_x.max(end_x);
13066            let mut stack = Vec::new();
13067            for row in range.start.row().0..=range.end.row().0 {
13068                if let Some(selection) = self.selections.build_columnar_selection(
13069                    &display_map,
13070                    DisplayRow(row),
13071                    &positions,
13072                    selection.reversed,
13073                    &text_layout_details,
13074                ) {
13075                    stack.push(selection.id);
13076                    columnar_selections.push(selection);
13077                }
13078            }
13079            if !stack.is_empty() {
13080                if above {
13081                    stack.reverse();
13082                }
13083                state.groups.push(AddSelectionsGroup { above, stack });
13084            }
13085        }
13086
13087        let mut final_selections = Vec::new();
13088        let end_row = if above {
13089            DisplayRow(0)
13090        } else {
13091            display_map.max_point().row()
13092        };
13093
13094        let mut last_added_item_per_group = HashMap::default();
13095        for group in state.groups.iter_mut() {
13096            if let Some(last_id) = group.stack.last() {
13097                last_added_item_per_group.insert(*last_id, group);
13098            }
13099        }
13100
13101        for selection in columnar_selections {
13102            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13103                if above == group.above {
13104                    let range = selection.display_range(&display_map).sorted();
13105                    debug_assert_eq!(range.start.row(), range.end.row());
13106                    let mut row = range.start.row();
13107                    let positions =
13108                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13109                            px(start)..px(end)
13110                        } else {
13111                            let start_x =
13112                                display_map.x_for_display_point(range.start, &text_layout_details);
13113                            let end_x =
13114                                display_map.x_for_display_point(range.end, &text_layout_details);
13115                            start_x.min(end_x)..start_x.max(end_x)
13116                        };
13117
13118                    let mut maybe_new_selection = None;
13119                    while row != end_row {
13120                        if above {
13121                            row.0 -= 1;
13122                        } else {
13123                            row.0 += 1;
13124                        }
13125                        if let Some(new_selection) = self.selections.build_columnar_selection(
13126                            &display_map,
13127                            row,
13128                            &positions,
13129                            selection.reversed,
13130                            &text_layout_details,
13131                        ) {
13132                            maybe_new_selection = Some(new_selection);
13133                            break;
13134                        }
13135                    }
13136
13137                    if let Some(new_selection) = maybe_new_selection {
13138                        group.stack.push(new_selection.id);
13139                        if above {
13140                            final_selections.push(new_selection);
13141                            final_selections.push(selection);
13142                        } else {
13143                            final_selections.push(selection);
13144                            final_selections.push(new_selection);
13145                        }
13146                    } else {
13147                        final_selections.push(selection);
13148                    }
13149                } else {
13150                    group.stack.pop();
13151                }
13152            } else {
13153                final_selections.push(selection);
13154            }
13155        }
13156
13157        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13158            s.select(final_selections);
13159        });
13160
13161        let final_selection_ids: HashSet<_> = self
13162            .selections
13163            .all::<Point>(cx)
13164            .iter()
13165            .map(|s| s.id)
13166            .collect();
13167        state.groups.retain_mut(|group| {
13168            // selections might get merged above so we remove invalid items from stacks
13169            group.stack.retain(|id| final_selection_ids.contains(id));
13170
13171            // single selection in stack can be treated as initial state
13172            group.stack.len() > 1
13173        });
13174
13175        if !state.groups.is_empty() {
13176            self.add_selections_state = Some(state);
13177        }
13178    }
13179
13180    fn select_match_ranges(
13181        &mut self,
13182        range: Range<usize>,
13183        reversed: bool,
13184        replace_newest: bool,
13185        auto_scroll: Option<Autoscroll>,
13186        window: &mut Window,
13187        cx: &mut Context<Editor>,
13188    ) {
13189        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13190        self.change_selections(auto_scroll, window, cx, |s| {
13191            if replace_newest {
13192                s.delete(s.newest_anchor().id);
13193            }
13194            if reversed {
13195                s.insert_range(range.end..range.start);
13196            } else {
13197                s.insert_range(range);
13198            }
13199        });
13200    }
13201
13202    pub fn select_next_match_internal(
13203        &mut self,
13204        display_map: &DisplaySnapshot,
13205        replace_newest: bool,
13206        autoscroll: Option<Autoscroll>,
13207        window: &mut Window,
13208        cx: &mut Context<Self>,
13209    ) -> Result<()> {
13210        let buffer = &display_map.buffer_snapshot;
13211        let mut selections = self.selections.all::<usize>(cx);
13212        if let Some(mut select_next_state) = self.select_next_state.take() {
13213            let query = &select_next_state.query;
13214            if !select_next_state.done {
13215                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13216                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13217                let mut next_selected_range = None;
13218
13219                let bytes_after_last_selection =
13220                    buffer.bytes_in_range(last_selection.end..buffer.len());
13221                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13222                let query_matches = query
13223                    .stream_find_iter(bytes_after_last_selection)
13224                    .map(|result| (last_selection.end, result))
13225                    .chain(
13226                        query
13227                            .stream_find_iter(bytes_before_first_selection)
13228                            .map(|result| (0, result)),
13229                    );
13230
13231                for (start_offset, query_match) in query_matches {
13232                    let query_match = query_match.unwrap(); // can only fail due to I/O
13233                    let offset_range =
13234                        start_offset + query_match.start()..start_offset + query_match.end();
13235                    let display_range = offset_range.start.to_display_point(display_map)
13236                        ..offset_range.end.to_display_point(display_map);
13237
13238                    if !select_next_state.wordwise
13239                        || (!movement::is_inside_word(display_map, display_range.start)
13240                            && !movement::is_inside_word(display_map, display_range.end))
13241                    {
13242                        // TODO: This is n^2, because we might check all the selections
13243                        if !selections
13244                            .iter()
13245                            .any(|selection| selection.range().overlaps(&offset_range))
13246                        {
13247                            next_selected_range = Some(offset_range);
13248                            break;
13249                        }
13250                    }
13251                }
13252
13253                if let Some(next_selected_range) = next_selected_range {
13254                    self.select_match_ranges(
13255                        next_selected_range,
13256                        last_selection.reversed,
13257                        replace_newest,
13258                        autoscroll,
13259                        window,
13260                        cx,
13261                    );
13262                } else {
13263                    select_next_state.done = true;
13264                }
13265            }
13266
13267            self.select_next_state = Some(select_next_state);
13268        } else {
13269            let mut only_carets = true;
13270            let mut same_text_selected = true;
13271            let mut selected_text = None;
13272
13273            let mut selections_iter = selections.iter().peekable();
13274            while let Some(selection) = selections_iter.next() {
13275                if selection.start != selection.end {
13276                    only_carets = false;
13277                }
13278
13279                if same_text_selected {
13280                    if selected_text.is_none() {
13281                        selected_text =
13282                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13283                    }
13284
13285                    if let Some(next_selection) = selections_iter.peek() {
13286                        if next_selection.range().len() == selection.range().len() {
13287                            let next_selected_text = buffer
13288                                .text_for_range(next_selection.range())
13289                                .collect::<String>();
13290                            if Some(next_selected_text) != selected_text {
13291                                same_text_selected = false;
13292                                selected_text = None;
13293                            }
13294                        } else {
13295                            same_text_selected = false;
13296                            selected_text = None;
13297                        }
13298                    }
13299                }
13300            }
13301
13302            if only_carets {
13303                for selection in &mut selections {
13304                    let word_range = movement::surrounding_word(
13305                        display_map,
13306                        selection.start.to_display_point(display_map),
13307                    );
13308                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13309                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13310                    selection.goal = SelectionGoal::None;
13311                    selection.reversed = false;
13312                    self.select_match_ranges(
13313                        selection.start..selection.end,
13314                        selection.reversed,
13315                        replace_newest,
13316                        autoscroll,
13317                        window,
13318                        cx,
13319                    );
13320                }
13321
13322                if selections.len() == 1 {
13323                    let selection = selections
13324                        .last()
13325                        .expect("ensured that there's only one selection");
13326                    let query = buffer
13327                        .text_for_range(selection.start..selection.end)
13328                        .collect::<String>();
13329                    let is_empty = query.is_empty();
13330                    let select_state = SelectNextState {
13331                        query: AhoCorasick::new(&[query])?,
13332                        wordwise: true,
13333                        done: is_empty,
13334                    };
13335                    self.select_next_state = Some(select_state);
13336                } else {
13337                    self.select_next_state = None;
13338                }
13339            } else if let Some(selected_text) = selected_text {
13340                self.select_next_state = Some(SelectNextState {
13341                    query: AhoCorasick::new(&[selected_text])?,
13342                    wordwise: false,
13343                    done: false,
13344                });
13345                self.select_next_match_internal(
13346                    display_map,
13347                    replace_newest,
13348                    autoscroll,
13349                    window,
13350                    cx,
13351                )?;
13352            }
13353        }
13354        Ok(())
13355    }
13356
13357    pub fn select_all_matches(
13358        &mut self,
13359        _action: &SelectAllMatches,
13360        window: &mut Window,
13361        cx: &mut Context<Self>,
13362    ) -> Result<()> {
13363        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13364
13365        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13366
13367        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13368        let Some(select_next_state) = self.select_next_state.as_mut() else {
13369            return Ok(());
13370        };
13371        if select_next_state.done {
13372            return Ok(());
13373        }
13374
13375        let mut new_selections = Vec::new();
13376
13377        let reversed = self.selections.oldest::<usize>(cx).reversed;
13378        let buffer = &display_map.buffer_snapshot;
13379        let query_matches = select_next_state
13380            .query
13381            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13382
13383        for query_match in query_matches.into_iter() {
13384            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13385            let offset_range = if reversed {
13386                query_match.end()..query_match.start()
13387            } else {
13388                query_match.start()..query_match.end()
13389            };
13390            let display_range = offset_range.start.to_display_point(&display_map)
13391                ..offset_range.end.to_display_point(&display_map);
13392
13393            if !select_next_state.wordwise
13394                || (!movement::is_inside_word(&display_map, display_range.start)
13395                    && !movement::is_inside_word(&display_map, display_range.end))
13396            {
13397                new_selections.push(offset_range.start..offset_range.end);
13398            }
13399        }
13400
13401        select_next_state.done = true;
13402        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13403        self.change_selections(None, window, cx, |selections| {
13404            selections.select_ranges(new_selections)
13405        });
13406
13407        Ok(())
13408    }
13409
13410    pub fn select_next(
13411        &mut self,
13412        action: &SelectNext,
13413        window: &mut Window,
13414        cx: &mut Context<Self>,
13415    ) -> Result<()> {
13416        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13417        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13418        self.select_next_match_internal(
13419            &display_map,
13420            action.replace_newest,
13421            Some(Autoscroll::newest()),
13422            window,
13423            cx,
13424        )?;
13425        Ok(())
13426    }
13427
13428    pub fn select_previous(
13429        &mut self,
13430        action: &SelectPrevious,
13431        window: &mut Window,
13432        cx: &mut Context<Self>,
13433    ) -> Result<()> {
13434        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13435        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13436        let buffer = &display_map.buffer_snapshot;
13437        let mut selections = self.selections.all::<usize>(cx);
13438        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13439            let query = &select_prev_state.query;
13440            if !select_prev_state.done {
13441                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13442                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13443                let mut next_selected_range = None;
13444                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13445                let bytes_before_last_selection =
13446                    buffer.reversed_bytes_in_range(0..last_selection.start);
13447                let bytes_after_first_selection =
13448                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13449                let query_matches = query
13450                    .stream_find_iter(bytes_before_last_selection)
13451                    .map(|result| (last_selection.start, result))
13452                    .chain(
13453                        query
13454                            .stream_find_iter(bytes_after_first_selection)
13455                            .map(|result| (buffer.len(), result)),
13456                    );
13457                for (end_offset, query_match) in query_matches {
13458                    let query_match = query_match.unwrap(); // can only fail due to I/O
13459                    let offset_range =
13460                        end_offset - query_match.end()..end_offset - query_match.start();
13461                    let display_range = offset_range.start.to_display_point(&display_map)
13462                        ..offset_range.end.to_display_point(&display_map);
13463
13464                    if !select_prev_state.wordwise
13465                        || (!movement::is_inside_word(&display_map, display_range.start)
13466                            && !movement::is_inside_word(&display_map, display_range.end))
13467                    {
13468                        next_selected_range = Some(offset_range);
13469                        break;
13470                    }
13471                }
13472
13473                if let Some(next_selected_range) = next_selected_range {
13474                    self.select_match_ranges(
13475                        next_selected_range,
13476                        last_selection.reversed,
13477                        action.replace_newest,
13478                        Some(Autoscroll::newest()),
13479                        window,
13480                        cx,
13481                    );
13482                } else {
13483                    select_prev_state.done = true;
13484                }
13485            }
13486
13487            self.select_prev_state = Some(select_prev_state);
13488        } else {
13489            let mut only_carets = true;
13490            let mut same_text_selected = true;
13491            let mut selected_text = None;
13492
13493            let mut selections_iter = selections.iter().peekable();
13494            while let Some(selection) = selections_iter.next() {
13495                if selection.start != selection.end {
13496                    only_carets = false;
13497                }
13498
13499                if same_text_selected {
13500                    if selected_text.is_none() {
13501                        selected_text =
13502                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13503                    }
13504
13505                    if let Some(next_selection) = selections_iter.peek() {
13506                        if next_selection.range().len() == selection.range().len() {
13507                            let next_selected_text = buffer
13508                                .text_for_range(next_selection.range())
13509                                .collect::<String>();
13510                            if Some(next_selected_text) != selected_text {
13511                                same_text_selected = false;
13512                                selected_text = None;
13513                            }
13514                        } else {
13515                            same_text_selected = false;
13516                            selected_text = None;
13517                        }
13518                    }
13519                }
13520            }
13521
13522            if only_carets {
13523                for selection in &mut selections {
13524                    let word_range = movement::surrounding_word(
13525                        &display_map,
13526                        selection.start.to_display_point(&display_map),
13527                    );
13528                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13529                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13530                    selection.goal = SelectionGoal::None;
13531                    selection.reversed = false;
13532                    self.select_match_ranges(
13533                        selection.start..selection.end,
13534                        selection.reversed,
13535                        action.replace_newest,
13536                        Some(Autoscroll::newest()),
13537                        window,
13538                        cx,
13539                    );
13540                }
13541                if selections.len() == 1 {
13542                    let selection = selections
13543                        .last()
13544                        .expect("ensured that there's only one selection");
13545                    let query = buffer
13546                        .text_for_range(selection.start..selection.end)
13547                        .collect::<String>();
13548                    let is_empty = query.is_empty();
13549                    let select_state = SelectNextState {
13550                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13551                        wordwise: true,
13552                        done: is_empty,
13553                    };
13554                    self.select_prev_state = Some(select_state);
13555                } else {
13556                    self.select_prev_state = None;
13557                }
13558            } else if let Some(selected_text) = selected_text {
13559                self.select_prev_state = Some(SelectNextState {
13560                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13561                    wordwise: false,
13562                    done: false,
13563                });
13564                self.select_previous(action, window, cx)?;
13565            }
13566        }
13567        Ok(())
13568    }
13569
13570    pub fn find_next_match(
13571        &mut self,
13572        _: &FindNextMatch,
13573        window: &mut Window,
13574        cx: &mut Context<Self>,
13575    ) -> Result<()> {
13576        let selections = self.selections.disjoint_anchors();
13577        match selections.first() {
13578            Some(first) if selections.len() >= 2 => {
13579                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13580                    s.select_ranges([first.range()]);
13581                });
13582            }
13583            _ => self.select_next(
13584                &SelectNext {
13585                    replace_newest: true,
13586                },
13587                window,
13588                cx,
13589            )?,
13590        }
13591        Ok(())
13592    }
13593
13594    pub fn find_previous_match(
13595        &mut self,
13596        _: &FindPreviousMatch,
13597        window: &mut Window,
13598        cx: &mut Context<Self>,
13599    ) -> Result<()> {
13600        let selections = self.selections.disjoint_anchors();
13601        match selections.last() {
13602            Some(last) if selections.len() >= 2 => {
13603                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13604                    s.select_ranges([last.range()]);
13605                });
13606            }
13607            _ => self.select_previous(
13608                &SelectPrevious {
13609                    replace_newest: true,
13610                },
13611                window,
13612                cx,
13613            )?,
13614        }
13615        Ok(())
13616    }
13617
13618    pub fn toggle_comments(
13619        &mut self,
13620        action: &ToggleComments,
13621        window: &mut Window,
13622        cx: &mut Context<Self>,
13623    ) {
13624        if self.read_only(cx) {
13625            return;
13626        }
13627        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13628        let text_layout_details = &self.text_layout_details(window);
13629        self.transact(window, cx, |this, window, cx| {
13630            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13631            let mut edits = Vec::new();
13632            let mut selection_edit_ranges = Vec::new();
13633            let mut last_toggled_row = None;
13634            let snapshot = this.buffer.read(cx).read(cx);
13635            let empty_str: Arc<str> = Arc::default();
13636            let mut suffixes_inserted = Vec::new();
13637            let ignore_indent = action.ignore_indent;
13638
13639            fn comment_prefix_range(
13640                snapshot: &MultiBufferSnapshot,
13641                row: MultiBufferRow,
13642                comment_prefix: &str,
13643                comment_prefix_whitespace: &str,
13644                ignore_indent: bool,
13645            ) -> Range<Point> {
13646                let indent_size = if ignore_indent {
13647                    0
13648                } else {
13649                    snapshot.indent_size_for_line(row).len
13650                };
13651
13652                let start = Point::new(row.0, indent_size);
13653
13654                let mut line_bytes = snapshot
13655                    .bytes_in_range(start..snapshot.max_point())
13656                    .flatten()
13657                    .copied();
13658
13659                // If this line currently begins with the line comment prefix, then record
13660                // the range containing the prefix.
13661                if line_bytes
13662                    .by_ref()
13663                    .take(comment_prefix.len())
13664                    .eq(comment_prefix.bytes())
13665                {
13666                    // Include any whitespace that matches the comment prefix.
13667                    let matching_whitespace_len = line_bytes
13668                        .zip(comment_prefix_whitespace.bytes())
13669                        .take_while(|(a, b)| a == b)
13670                        .count() as u32;
13671                    let end = Point::new(
13672                        start.row,
13673                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13674                    );
13675                    start..end
13676                } else {
13677                    start..start
13678                }
13679            }
13680
13681            fn comment_suffix_range(
13682                snapshot: &MultiBufferSnapshot,
13683                row: MultiBufferRow,
13684                comment_suffix: &str,
13685                comment_suffix_has_leading_space: bool,
13686            ) -> Range<Point> {
13687                let end = Point::new(row.0, snapshot.line_len(row));
13688                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13689
13690                let mut line_end_bytes = snapshot
13691                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13692                    .flatten()
13693                    .copied();
13694
13695                let leading_space_len = if suffix_start_column > 0
13696                    && line_end_bytes.next() == Some(b' ')
13697                    && comment_suffix_has_leading_space
13698                {
13699                    1
13700                } else {
13701                    0
13702                };
13703
13704                // If this line currently begins with the line comment prefix, then record
13705                // the range containing the prefix.
13706                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13707                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13708                    start..end
13709                } else {
13710                    end..end
13711                }
13712            }
13713
13714            // TODO: Handle selections that cross excerpts
13715            for selection in &mut selections {
13716                let start_column = snapshot
13717                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13718                    .len;
13719                let language = if let Some(language) =
13720                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13721                {
13722                    language
13723                } else {
13724                    continue;
13725                };
13726
13727                selection_edit_ranges.clear();
13728
13729                // If multiple selections contain a given row, avoid processing that
13730                // row more than once.
13731                let mut start_row = MultiBufferRow(selection.start.row);
13732                if last_toggled_row == Some(start_row) {
13733                    start_row = start_row.next_row();
13734                }
13735                let end_row =
13736                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13737                        MultiBufferRow(selection.end.row - 1)
13738                    } else {
13739                        MultiBufferRow(selection.end.row)
13740                    };
13741                last_toggled_row = Some(end_row);
13742
13743                if start_row > end_row {
13744                    continue;
13745                }
13746
13747                // If the language has line comments, toggle those.
13748                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13749
13750                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13751                if ignore_indent {
13752                    full_comment_prefixes = full_comment_prefixes
13753                        .into_iter()
13754                        .map(|s| Arc::from(s.trim_end()))
13755                        .collect();
13756                }
13757
13758                if !full_comment_prefixes.is_empty() {
13759                    let first_prefix = full_comment_prefixes
13760                        .first()
13761                        .expect("prefixes is non-empty");
13762                    let prefix_trimmed_lengths = full_comment_prefixes
13763                        .iter()
13764                        .map(|p| p.trim_end_matches(' ').len())
13765                        .collect::<SmallVec<[usize; 4]>>();
13766
13767                    let mut all_selection_lines_are_comments = true;
13768
13769                    for row in start_row.0..=end_row.0 {
13770                        let row = MultiBufferRow(row);
13771                        if start_row < end_row && snapshot.is_line_blank(row) {
13772                            continue;
13773                        }
13774
13775                        let prefix_range = full_comment_prefixes
13776                            .iter()
13777                            .zip(prefix_trimmed_lengths.iter().copied())
13778                            .map(|(prefix, trimmed_prefix_len)| {
13779                                comment_prefix_range(
13780                                    snapshot.deref(),
13781                                    row,
13782                                    &prefix[..trimmed_prefix_len],
13783                                    &prefix[trimmed_prefix_len..],
13784                                    ignore_indent,
13785                                )
13786                            })
13787                            .max_by_key(|range| range.end.column - range.start.column)
13788                            .expect("prefixes is non-empty");
13789
13790                        if prefix_range.is_empty() {
13791                            all_selection_lines_are_comments = false;
13792                        }
13793
13794                        selection_edit_ranges.push(prefix_range);
13795                    }
13796
13797                    if all_selection_lines_are_comments {
13798                        edits.extend(
13799                            selection_edit_ranges
13800                                .iter()
13801                                .cloned()
13802                                .map(|range| (range, empty_str.clone())),
13803                        );
13804                    } else {
13805                        let min_column = selection_edit_ranges
13806                            .iter()
13807                            .map(|range| range.start.column)
13808                            .min()
13809                            .unwrap_or(0);
13810                        edits.extend(selection_edit_ranges.iter().map(|range| {
13811                            let position = Point::new(range.start.row, min_column);
13812                            (position..position, first_prefix.clone())
13813                        }));
13814                    }
13815                } else if let Some((full_comment_prefix, comment_suffix)) =
13816                    language.block_comment_delimiters()
13817                {
13818                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13819                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13820                    let prefix_range = comment_prefix_range(
13821                        snapshot.deref(),
13822                        start_row,
13823                        comment_prefix,
13824                        comment_prefix_whitespace,
13825                        ignore_indent,
13826                    );
13827                    let suffix_range = comment_suffix_range(
13828                        snapshot.deref(),
13829                        end_row,
13830                        comment_suffix.trim_start_matches(' '),
13831                        comment_suffix.starts_with(' '),
13832                    );
13833
13834                    if prefix_range.is_empty() || suffix_range.is_empty() {
13835                        edits.push((
13836                            prefix_range.start..prefix_range.start,
13837                            full_comment_prefix.clone(),
13838                        ));
13839                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13840                        suffixes_inserted.push((end_row, comment_suffix.len()));
13841                    } else {
13842                        edits.push((prefix_range, empty_str.clone()));
13843                        edits.push((suffix_range, empty_str.clone()));
13844                    }
13845                } else {
13846                    continue;
13847                }
13848            }
13849
13850            drop(snapshot);
13851            this.buffer.update(cx, |buffer, cx| {
13852                buffer.edit(edits, None, cx);
13853            });
13854
13855            // Adjust selections so that they end before any comment suffixes that
13856            // were inserted.
13857            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13858            let mut selections = this.selections.all::<Point>(cx);
13859            let snapshot = this.buffer.read(cx).read(cx);
13860            for selection in &mut selections {
13861                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13862                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13863                        Ordering::Less => {
13864                            suffixes_inserted.next();
13865                            continue;
13866                        }
13867                        Ordering::Greater => break,
13868                        Ordering::Equal => {
13869                            if selection.end.column == snapshot.line_len(row) {
13870                                if selection.is_empty() {
13871                                    selection.start.column -= suffix_len as u32;
13872                                }
13873                                selection.end.column -= suffix_len as u32;
13874                            }
13875                            break;
13876                        }
13877                    }
13878                }
13879            }
13880
13881            drop(snapshot);
13882            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13883                s.select(selections)
13884            });
13885
13886            let selections = this.selections.all::<Point>(cx);
13887            let selections_on_single_row = selections.windows(2).all(|selections| {
13888                selections[0].start.row == selections[1].start.row
13889                    && selections[0].end.row == selections[1].end.row
13890                    && selections[0].start.row == selections[0].end.row
13891            });
13892            let selections_selecting = selections
13893                .iter()
13894                .any(|selection| selection.start != selection.end);
13895            let advance_downwards = action.advance_downwards
13896                && selections_on_single_row
13897                && !selections_selecting
13898                && !matches!(this.mode, EditorMode::SingleLine { .. });
13899
13900            if advance_downwards {
13901                let snapshot = this.buffer.read(cx).snapshot(cx);
13902
13903                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13904                    s.move_cursors_with(|display_snapshot, display_point, _| {
13905                        let mut point = display_point.to_point(display_snapshot);
13906                        point.row += 1;
13907                        point = snapshot.clip_point(point, Bias::Left);
13908                        let display_point = point.to_display_point(display_snapshot);
13909                        let goal = SelectionGoal::HorizontalPosition(
13910                            display_snapshot
13911                                .x_for_display_point(display_point, text_layout_details)
13912                                .into(),
13913                        );
13914                        (display_point, goal)
13915                    })
13916                });
13917            }
13918        });
13919    }
13920
13921    pub fn select_enclosing_symbol(
13922        &mut self,
13923        _: &SelectEnclosingSymbol,
13924        window: &mut Window,
13925        cx: &mut Context<Self>,
13926    ) {
13927        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13928
13929        let buffer = self.buffer.read(cx).snapshot(cx);
13930        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13931
13932        fn update_selection(
13933            selection: &Selection<usize>,
13934            buffer_snap: &MultiBufferSnapshot,
13935        ) -> Option<Selection<usize>> {
13936            let cursor = selection.head();
13937            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13938            for symbol in symbols.iter().rev() {
13939                let start = symbol.range.start.to_offset(buffer_snap);
13940                let end = symbol.range.end.to_offset(buffer_snap);
13941                let new_range = start..end;
13942                if start < selection.start || end > selection.end {
13943                    return Some(Selection {
13944                        id: selection.id,
13945                        start: new_range.start,
13946                        end: new_range.end,
13947                        goal: SelectionGoal::None,
13948                        reversed: selection.reversed,
13949                    });
13950                }
13951            }
13952            None
13953        }
13954
13955        let mut selected_larger_symbol = false;
13956        let new_selections = old_selections
13957            .iter()
13958            .map(|selection| match update_selection(selection, &buffer) {
13959                Some(new_selection) => {
13960                    if new_selection.range() != selection.range() {
13961                        selected_larger_symbol = true;
13962                    }
13963                    new_selection
13964                }
13965                None => selection.clone(),
13966            })
13967            .collect::<Vec<_>>();
13968
13969        if selected_larger_symbol {
13970            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13971                s.select(new_selections);
13972            });
13973        }
13974    }
13975
13976    pub fn select_larger_syntax_node(
13977        &mut self,
13978        _: &SelectLargerSyntaxNode,
13979        window: &mut Window,
13980        cx: &mut Context<Self>,
13981    ) {
13982        let Some(visible_row_count) = self.visible_row_count() else {
13983            return;
13984        };
13985        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13986        if old_selections.is_empty() {
13987            return;
13988        }
13989
13990        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13991
13992        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13993        let buffer = self.buffer.read(cx).snapshot(cx);
13994
13995        let mut selected_larger_node = false;
13996        let mut new_selections = old_selections
13997            .iter()
13998            .map(|selection| {
13999                let old_range = selection.start..selection.end;
14000
14001                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14002                    // manually select word at selection
14003                    if ["string_content", "inline"].contains(&node.kind()) {
14004                        let word_range = {
14005                            let display_point = buffer
14006                                .offset_to_point(old_range.start)
14007                                .to_display_point(&display_map);
14008                            let Range { start, end } =
14009                                movement::surrounding_word(&display_map, display_point);
14010                            start.to_point(&display_map).to_offset(&buffer)
14011                                ..end.to_point(&display_map).to_offset(&buffer)
14012                        };
14013                        // ignore if word is already selected
14014                        if !word_range.is_empty() && old_range != word_range {
14015                            let last_word_range = {
14016                                let display_point = buffer
14017                                    .offset_to_point(old_range.end)
14018                                    .to_display_point(&display_map);
14019                                let Range { start, end } =
14020                                    movement::surrounding_word(&display_map, display_point);
14021                                start.to_point(&display_map).to_offset(&buffer)
14022                                    ..end.to_point(&display_map).to_offset(&buffer)
14023                            };
14024                            // only select word if start and end point belongs to same word
14025                            if word_range == last_word_range {
14026                                selected_larger_node = true;
14027                                return Selection {
14028                                    id: selection.id,
14029                                    start: word_range.start,
14030                                    end: word_range.end,
14031                                    goal: SelectionGoal::None,
14032                                    reversed: selection.reversed,
14033                                };
14034                            }
14035                        }
14036                    }
14037                }
14038
14039                let mut new_range = old_range.clone();
14040                while let Some((_node, containing_range)) =
14041                    buffer.syntax_ancestor(new_range.clone())
14042                {
14043                    new_range = match containing_range {
14044                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14045                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14046                    };
14047                    if !display_map.intersects_fold(new_range.start)
14048                        && !display_map.intersects_fold(new_range.end)
14049                    {
14050                        break;
14051                    }
14052                }
14053
14054                selected_larger_node |= new_range != old_range;
14055                Selection {
14056                    id: selection.id,
14057                    start: new_range.start,
14058                    end: new_range.end,
14059                    goal: SelectionGoal::None,
14060                    reversed: selection.reversed,
14061                }
14062            })
14063            .collect::<Vec<_>>();
14064
14065        if !selected_larger_node {
14066            return; // don't put this call in the history
14067        }
14068
14069        // scroll based on transformation done to the last selection created by the user
14070        let (last_old, last_new) = old_selections
14071            .last()
14072            .zip(new_selections.last().cloned())
14073            .expect("old_selections isn't empty");
14074
14075        // revert selection
14076        let is_selection_reversed = {
14077            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14078            new_selections.last_mut().expect("checked above").reversed =
14079                should_newest_selection_be_reversed;
14080            should_newest_selection_be_reversed
14081        };
14082
14083        if selected_larger_node {
14084            self.select_syntax_node_history.disable_clearing = true;
14085            self.change_selections(None, window, cx, |s| {
14086                s.select(new_selections.clone());
14087            });
14088            self.select_syntax_node_history.disable_clearing = false;
14089        }
14090
14091        let start_row = last_new.start.to_display_point(&display_map).row().0;
14092        let end_row = last_new.end.to_display_point(&display_map).row().0;
14093        let selection_height = end_row - start_row + 1;
14094        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14095
14096        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14097        let scroll_behavior = if fits_on_the_screen {
14098            self.request_autoscroll(Autoscroll::fit(), cx);
14099            SelectSyntaxNodeScrollBehavior::FitSelection
14100        } else if is_selection_reversed {
14101            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14102            SelectSyntaxNodeScrollBehavior::CursorTop
14103        } else {
14104            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14105            SelectSyntaxNodeScrollBehavior::CursorBottom
14106        };
14107
14108        self.select_syntax_node_history.push((
14109            old_selections,
14110            scroll_behavior,
14111            is_selection_reversed,
14112        ));
14113    }
14114
14115    pub fn select_smaller_syntax_node(
14116        &mut self,
14117        _: &SelectSmallerSyntaxNode,
14118        window: &mut Window,
14119        cx: &mut Context<Self>,
14120    ) {
14121        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14122
14123        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14124            self.select_syntax_node_history.pop()
14125        {
14126            if let Some(selection) = selections.last_mut() {
14127                selection.reversed = is_selection_reversed;
14128            }
14129
14130            self.select_syntax_node_history.disable_clearing = true;
14131            self.change_selections(None, window, cx, |s| {
14132                s.select(selections.to_vec());
14133            });
14134            self.select_syntax_node_history.disable_clearing = false;
14135
14136            match scroll_behavior {
14137                SelectSyntaxNodeScrollBehavior::CursorTop => {
14138                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14139                }
14140                SelectSyntaxNodeScrollBehavior::FitSelection => {
14141                    self.request_autoscroll(Autoscroll::fit(), cx);
14142                }
14143                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14144                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14145                }
14146            }
14147        }
14148    }
14149
14150    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14151        if !EditorSettings::get_global(cx).gutter.runnables {
14152            self.clear_tasks();
14153            return Task::ready(());
14154        }
14155        let project = self.project.as_ref().map(Entity::downgrade);
14156        let task_sources = self.lsp_task_sources(cx);
14157        let multi_buffer = self.buffer.downgrade();
14158        cx.spawn_in(window, async move |editor, cx| {
14159            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14160            let Some(project) = project.and_then(|p| p.upgrade()) else {
14161                return;
14162            };
14163            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14164                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14165            }) else {
14166                return;
14167            };
14168
14169            let hide_runnables = project
14170                .update(cx, |project, cx| {
14171                    // Do not display any test indicators in non-dev server remote projects.
14172                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14173                })
14174                .unwrap_or(true);
14175            if hide_runnables {
14176                return;
14177            }
14178            let new_rows =
14179                cx.background_spawn({
14180                    let snapshot = display_snapshot.clone();
14181                    async move {
14182                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14183                    }
14184                })
14185                    .await;
14186            let Ok(lsp_tasks) =
14187                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14188            else {
14189                return;
14190            };
14191            let lsp_tasks = lsp_tasks.await;
14192
14193            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14194                lsp_tasks
14195                    .into_iter()
14196                    .flat_map(|(kind, tasks)| {
14197                        tasks.into_iter().filter_map(move |(location, task)| {
14198                            Some((kind.clone(), location?, task))
14199                        })
14200                    })
14201                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14202                        let buffer = location.target.buffer;
14203                        let buffer_snapshot = buffer.read(cx).snapshot();
14204                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14205                            |(excerpt_id, snapshot, _)| {
14206                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14207                                    display_snapshot
14208                                        .buffer_snapshot
14209                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14210                                } else {
14211                                    None
14212                                }
14213                            },
14214                        );
14215                        if let Some(offset) = offset {
14216                            let task_buffer_range =
14217                                location.target.range.to_point(&buffer_snapshot);
14218                            let context_buffer_range =
14219                                task_buffer_range.to_offset(&buffer_snapshot);
14220                            let context_range = BufferOffset(context_buffer_range.start)
14221                                ..BufferOffset(context_buffer_range.end);
14222
14223                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14224                                .or_insert_with(|| RunnableTasks {
14225                                    templates: Vec::new(),
14226                                    offset,
14227                                    column: task_buffer_range.start.column,
14228                                    extra_variables: HashMap::default(),
14229                                    context_range,
14230                                })
14231                                .templates
14232                                .push((kind, task.original_task().clone()));
14233                        }
14234
14235                        acc
14236                    })
14237            }) else {
14238                return;
14239            };
14240
14241            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14242                buffer.language_settings(cx).tasks.prefer_lsp
14243            }) else {
14244                return;
14245            };
14246
14247            let rows = Self::runnable_rows(
14248                project,
14249                display_snapshot,
14250                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14251                new_rows,
14252                cx.clone(),
14253            )
14254            .await;
14255            editor
14256                .update(cx, |editor, _| {
14257                    editor.clear_tasks();
14258                    for (key, mut value) in rows {
14259                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14260                            value.templates.extend(lsp_tasks.templates);
14261                        }
14262
14263                        editor.insert_tasks(key, value);
14264                    }
14265                    for (key, value) in lsp_tasks_by_rows {
14266                        editor.insert_tasks(key, value);
14267                    }
14268                })
14269                .ok();
14270        })
14271    }
14272    fn fetch_runnable_ranges(
14273        snapshot: &DisplaySnapshot,
14274        range: Range<Anchor>,
14275    ) -> Vec<language::RunnableRange> {
14276        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14277    }
14278
14279    fn runnable_rows(
14280        project: Entity<Project>,
14281        snapshot: DisplaySnapshot,
14282        prefer_lsp: bool,
14283        runnable_ranges: Vec<RunnableRange>,
14284        cx: AsyncWindowContext,
14285    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14286        cx.spawn(async move |cx| {
14287            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14288            for mut runnable in runnable_ranges {
14289                let Some(tasks) = cx
14290                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14291                    .ok()
14292                else {
14293                    continue;
14294                };
14295                let mut tasks = tasks.await;
14296
14297                if prefer_lsp {
14298                    tasks.retain(|(task_kind, _)| {
14299                        !matches!(task_kind, TaskSourceKind::Language { .. })
14300                    });
14301                }
14302                if tasks.is_empty() {
14303                    continue;
14304                }
14305
14306                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14307                let Some(row) = snapshot
14308                    .buffer_snapshot
14309                    .buffer_line_for_row(MultiBufferRow(point.row))
14310                    .map(|(_, range)| range.start.row)
14311                else {
14312                    continue;
14313                };
14314
14315                let context_range =
14316                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14317                runnable_rows.push((
14318                    (runnable.buffer_id, row),
14319                    RunnableTasks {
14320                        templates: tasks,
14321                        offset: snapshot
14322                            .buffer_snapshot
14323                            .anchor_before(runnable.run_range.start),
14324                        context_range,
14325                        column: point.column,
14326                        extra_variables: runnable.extra_captures,
14327                    },
14328                ));
14329            }
14330            runnable_rows
14331        })
14332    }
14333
14334    fn templates_with_tags(
14335        project: &Entity<Project>,
14336        runnable: &mut Runnable,
14337        cx: &mut App,
14338    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14339        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14340            let (worktree_id, file) = project
14341                .buffer_for_id(runnable.buffer, cx)
14342                .and_then(|buffer| buffer.read(cx).file())
14343                .map(|file| (file.worktree_id(cx), file.clone()))
14344                .unzip();
14345
14346            (
14347                project.task_store().read(cx).task_inventory().cloned(),
14348                worktree_id,
14349                file,
14350            )
14351        });
14352
14353        let tags = mem::take(&mut runnable.tags);
14354        let language = runnable.language.clone();
14355        cx.spawn(async move |cx| {
14356            let mut templates_with_tags = Vec::new();
14357            if let Some(inventory) = inventory {
14358                for RunnableTag(tag) in tags {
14359                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14360                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14361                    }) else {
14362                        return templates_with_tags;
14363                    };
14364                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14365                        move |(_, template)| {
14366                            template.tags.iter().any(|source_tag| source_tag == &tag)
14367                        },
14368                    ));
14369                }
14370            }
14371            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14372
14373            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14374                // Strongest source wins; if we have worktree tag binding, prefer that to
14375                // global and language bindings;
14376                // if we have a global binding, prefer that to language binding.
14377                let first_mismatch = templates_with_tags
14378                    .iter()
14379                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14380                if let Some(index) = first_mismatch {
14381                    templates_with_tags.truncate(index);
14382                }
14383            }
14384
14385            templates_with_tags
14386        })
14387    }
14388
14389    pub fn move_to_enclosing_bracket(
14390        &mut self,
14391        _: &MoveToEnclosingBracket,
14392        window: &mut Window,
14393        cx: &mut Context<Self>,
14394    ) {
14395        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14396        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14397            s.move_offsets_with(|snapshot, selection| {
14398                let Some(enclosing_bracket_ranges) =
14399                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14400                else {
14401                    return;
14402                };
14403
14404                let mut best_length = usize::MAX;
14405                let mut best_inside = false;
14406                let mut best_in_bracket_range = false;
14407                let mut best_destination = None;
14408                for (open, close) in enclosing_bracket_ranges {
14409                    let close = close.to_inclusive();
14410                    let length = close.end() - open.start;
14411                    let inside = selection.start >= open.end && selection.end <= *close.start();
14412                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14413                        || close.contains(&selection.head());
14414
14415                    // If best is next to a bracket and current isn't, skip
14416                    if !in_bracket_range && best_in_bracket_range {
14417                        continue;
14418                    }
14419
14420                    // Prefer smaller lengths unless best is inside and current isn't
14421                    if length > best_length && (best_inside || !inside) {
14422                        continue;
14423                    }
14424
14425                    best_length = length;
14426                    best_inside = inside;
14427                    best_in_bracket_range = in_bracket_range;
14428                    best_destination = Some(
14429                        if close.contains(&selection.start) && close.contains(&selection.end) {
14430                            if inside { open.end } else { open.start }
14431                        } else if inside {
14432                            *close.start()
14433                        } else {
14434                            *close.end()
14435                        },
14436                    );
14437                }
14438
14439                if let Some(destination) = best_destination {
14440                    selection.collapse_to(destination, SelectionGoal::None);
14441                }
14442            })
14443        });
14444    }
14445
14446    pub fn undo_selection(
14447        &mut self,
14448        _: &UndoSelection,
14449        window: &mut Window,
14450        cx: &mut Context<Self>,
14451    ) {
14452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14453        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14454            self.selection_history.mode = SelectionHistoryMode::Undoing;
14455            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14456                this.end_selection(window, cx);
14457                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14458                    s.select_anchors(entry.selections.to_vec())
14459                });
14460            });
14461            self.selection_history.mode = SelectionHistoryMode::Normal;
14462
14463            self.select_next_state = entry.select_next_state;
14464            self.select_prev_state = entry.select_prev_state;
14465            self.add_selections_state = entry.add_selections_state;
14466        }
14467    }
14468
14469    pub fn redo_selection(
14470        &mut self,
14471        _: &RedoSelection,
14472        window: &mut Window,
14473        cx: &mut Context<Self>,
14474    ) {
14475        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14476        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14477            self.selection_history.mode = SelectionHistoryMode::Redoing;
14478            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14479                this.end_selection(window, cx);
14480                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14481                    s.select_anchors(entry.selections.to_vec())
14482                });
14483            });
14484            self.selection_history.mode = SelectionHistoryMode::Normal;
14485
14486            self.select_next_state = entry.select_next_state;
14487            self.select_prev_state = entry.select_prev_state;
14488            self.add_selections_state = entry.add_selections_state;
14489        }
14490    }
14491
14492    pub fn expand_excerpts(
14493        &mut self,
14494        action: &ExpandExcerpts,
14495        _: &mut Window,
14496        cx: &mut Context<Self>,
14497    ) {
14498        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14499    }
14500
14501    pub fn expand_excerpts_down(
14502        &mut self,
14503        action: &ExpandExcerptsDown,
14504        _: &mut Window,
14505        cx: &mut Context<Self>,
14506    ) {
14507        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14508    }
14509
14510    pub fn expand_excerpts_up(
14511        &mut self,
14512        action: &ExpandExcerptsUp,
14513        _: &mut Window,
14514        cx: &mut Context<Self>,
14515    ) {
14516        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14517    }
14518
14519    pub fn expand_excerpts_for_direction(
14520        &mut self,
14521        lines: u32,
14522        direction: ExpandExcerptDirection,
14523
14524        cx: &mut Context<Self>,
14525    ) {
14526        let selections = self.selections.disjoint_anchors();
14527
14528        let lines = if lines == 0 {
14529            EditorSettings::get_global(cx).expand_excerpt_lines
14530        } else {
14531            lines
14532        };
14533
14534        self.buffer.update(cx, |buffer, cx| {
14535            let snapshot = buffer.snapshot(cx);
14536            let mut excerpt_ids = selections
14537                .iter()
14538                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14539                .collect::<Vec<_>>();
14540            excerpt_ids.sort();
14541            excerpt_ids.dedup();
14542            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14543        })
14544    }
14545
14546    pub fn expand_excerpt(
14547        &mut self,
14548        excerpt: ExcerptId,
14549        direction: ExpandExcerptDirection,
14550        window: &mut Window,
14551        cx: &mut Context<Self>,
14552    ) {
14553        let current_scroll_position = self.scroll_position(cx);
14554        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14555        let mut should_scroll_up = false;
14556
14557        if direction == ExpandExcerptDirection::Down {
14558            let multi_buffer = self.buffer.read(cx);
14559            let snapshot = multi_buffer.snapshot(cx);
14560            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14561                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14562                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14563                        let buffer_snapshot = buffer.read(cx).snapshot();
14564                        let excerpt_end_row =
14565                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14566                        let last_row = buffer_snapshot.max_point().row;
14567                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14568                        should_scroll_up = lines_below >= lines_to_expand;
14569                    }
14570                }
14571            }
14572        }
14573
14574        self.buffer.update(cx, |buffer, cx| {
14575            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14576        });
14577
14578        if should_scroll_up {
14579            let new_scroll_position =
14580                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14581            self.set_scroll_position(new_scroll_position, window, cx);
14582        }
14583    }
14584
14585    pub fn go_to_singleton_buffer_point(
14586        &mut self,
14587        point: Point,
14588        window: &mut Window,
14589        cx: &mut Context<Self>,
14590    ) {
14591        self.go_to_singleton_buffer_range(point..point, window, cx);
14592    }
14593
14594    pub fn go_to_singleton_buffer_range(
14595        &mut self,
14596        range: Range<Point>,
14597        window: &mut Window,
14598        cx: &mut Context<Self>,
14599    ) {
14600        let multibuffer = self.buffer().read(cx);
14601        let Some(buffer) = multibuffer.as_singleton() else {
14602            return;
14603        };
14604        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14605            return;
14606        };
14607        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14608            return;
14609        };
14610        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14611            s.select_anchor_ranges([start..end])
14612        });
14613    }
14614
14615    pub fn go_to_diagnostic(
14616        &mut self,
14617        _: &GoToDiagnostic,
14618        window: &mut Window,
14619        cx: &mut Context<Self>,
14620    ) {
14621        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14622        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14623    }
14624
14625    pub fn go_to_prev_diagnostic(
14626        &mut self,
14627        _: &GoToPreviousDiagnostic,
14628        window: &mut Window,
14629        cx: &mut Context<Self>,
14630    ) {
14631        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14632        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14633    }
14634
14635    pub fn go_to_diagnostic_impl(
14636        &mut self,
14637        direction: Direction,
14638        window: &mut Window,
14639        cx: &mut Context<Self>,
14640    ) {
14641        let buffer = self.buffer.read(cx).snapshot(cx);
14642        let selection = self.selections.newest::<usize>(cx);
14643
14644        let mut active_group_id = None;
14645        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14646            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14647                active_group_id = Some(active_group.group_id);
14648            }
14649        }
14650
14651        fn filtered(
14652            snapshot: EditorSnapshot,
14653            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14654        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14655            diagnostics
14656                .filter(|entry| entry.range.start != entry.range.end)
14657                .filter(|entry| !entry.diagnostic.is_unnecessary)
14658                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14659        }
14660
14661        let snapshot = self.snapshot(window, cx);
14662        let before = filtered(
14663            snapshot.clone(),
14664            buffer
14665                .diagnostics_in_range(0..selection.start)
14666                .filter(|entry| entry.range.start <= selection.start),
14667        );
14668        let after = filtered(
14669            snapshot,
14670            buffer
14671                .diagnostics_in_range(selection.start..buffer.len())
14672                .filter(|entry| entry.range.start >= selection.start),
14673        );
14674
14675        let mut found: Option<DiagnosticEntry<usize>> = None;
14676        if direction == Direction::Prev {
14677            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14678            {
14679                for diagnostic in prev_diagnostics.into_iter().rev() {
14680                    if diagnostic.range.start != selection.start
14681                        || active_group_id
14682                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14683                    {
14684                        found = Some(diagnostic);
14685                        break 'outer;
14686                    }
14687                }
14688            }
14689        } else {
14690            for diagnostic in after.chain(before) {
14691                if diagnostic.range.start != selection.start
14692                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14693                {
14694                    found = Some(diagnostic);
14695                    break;
14696                }
14697            }
14698        }
14699        let Some(next_diagnostic) = found else {
14700            return;
14701        };
14702
14703        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14704            return;
14705        };
14706        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14707            s.select_ranges(vec![
14708                next_diagnostic.range.start..next_diagnostic.range.start,
14709            ])
14710        });
14711        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14712        self.refresh_inline_completion(false, true, window, cx);
14713    }
14714
14715    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14716        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14717        let snapshot = self.snapshot(window, cx);
14718        let selection = self.selections.newest::<Point>(cx);
14719        self.go_to_hunk_before_or_after_position(
14720            &snapshot,
14721            selection.head(),
14722            Direction::Next,
14723            window,
14724            cx,
14725        );
14726    }
14727
14728    pub fn go_to_hunk_before_or_after_position(
14729        &mut self,
14730        snapshot: &EditorSnapshot,
14731        position: Point,
14732        direction: Direction,
14733        window: &mut Window,
14734        cx: &mut Context<Editor>,
14735    ) {
14736        let row = if direction == Direction::Next {
14737            self.hunk_after_position(snapshot, position)
14738                .map(|hunk| hunk.row_range.start)
14739        } else {
14740            self.hunk_before_position(snapshot, position)
14741        };
14742
14743        if let Some(row) = row {
14744            let destination = Point::new(row.0, 0);
14745            let autoscroll = Autoscroll::center();
14746
14747            self.unfold_ranges(&[destination..destination], false, false, cx);
14748            self.change_selections(Some(autoscroll), window, cx, |s| {
14749                s.select_ranges([destination..destination]);
14750            });
14751        }
14752    }
14753
14754    fn hunk_after_position(
14755        &mut self,
14756        snapshot: &EditorSnapshot,
14757        position: Point,
14758    ) -> Option<MultiBufferDiffHunk> {
14759        snapshot
14760            .buffer_snapshot
14761            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14762            .find(|hunk| hunk.row_range.start.0 > position.row)
14763            .or_else(|| {
14764                snapshot
14765                    .buffer_snapshot
14766                    .diff_hunks_in_range(Point::zero()..position)
14767                    .find(|hunk| hunk.row_range.end.0 < position.row)
14768            })
14769    }
14770
14771    fn go_to_prev_hunk(
14772        &mut self,
14773        _: &GoToPreviousHunk,
14774        window: &mut Window,
14775        cx: &mut Context<Self>,
14776    ) {
14777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14778        let snapshot = self.snapshot(window, cx);
14779        let selection = self.selections.newest::<Point>(cx);
14780        self.go_to_hunk_before_or_after_position(
14781            &snapshot,
14782            selection.head(),
14783            Direction::Prev,
14784            window,
14785            cx,
14786        );
14787    }
14788
14789    fn hunk_before_position(
14790        &mut self,
14791        snapshot: &EditorSnapshot,
14792        position: Point,
14793    ) -> Option<MultiBufferRow> {
14794        snapshot
14795            .buffer_snapshot
14796            .diff_hunk_before(position)
14797            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14798    }
14799
14800    fn go_to_next_change(
14801        &mut self,
14802        _: &GoToNextChange,
14803        window: &mut Window,
14804        cx: &mut Context<Self>,
14805    ) {
14806        if let Some(selections) = self
14807            .change_list
14808            .next_change(1, Direction::Next)
14809            .map(|s| s.to_vec())
14810        {
14811            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14812                let map = s.display_map();
14813                s.select_display_ranges(selections.iter().map(|a| {
14814                    let point = a.to_display_point(&map);
14815                    point..point
14816                }))
14817            })
14818        }
14819    }
14820
14821    fn go_to_previous_change(
14822        &mut self,
14823        _: &GoToPreviousChange,
14824        window: &mut Window,
14825        cx: &mut Context<Self>,
14826    ) {
14827        if let Some(selections) = self
14828            .change_list
14829            .next_change(1, Direction::Prev)
14830            .map(|s| s.to_vec())
14831        {
14832            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14833                let map = s.display_map();
14834                s.select_display_ranges(selections.iter().map(|a| {
14835                    let point = a.to_display_point(&map);
14836                    point..point
14837                }))
14838            })
14839        }
14840    }
14841
14842    fn go_to_line<T: 'static>(
14843        &mut self,
14844        position: Anchor,
14845        highlight_color: Option<Hsla>,
14846        window: &mut Window,
14847        cx: &mut Context<Self>,
14848    ) {
14849        let snapshot = self.snapshot(window, cx).display_snapshot;
14850        let position = position.to_point(&snapshot.buffer_snapshot);
14851        let start = snapshot
14852            .buffer_snapshot
14853            .clip_point(Point::new(position.row, 0), Bias::Left);
14854        let end = start + Point::new(1, 0);
14855        let start = snapshot.buffer_snapshot.anchor_before(start);
14856        let end = snapshot.buffer_snapshot.anchor_before(end);
14857
14858        self.highlight_rows::<T>(
14859            start..end,
14860            highlight_color
14861                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14862            Default::default(),
14863            cx,
14864        );
14865
14866        if self.buffer.read(cx).is_singleton() {
14867            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14868        }
14869    }
14870
14871    pub fn go_to_definition(
14872        &mut self,
14873        _: &GoToDefinition,
14874        window: &mut Window,
14875        cx: &mut Context<Self>,
14876    ) -> Task<Result<Navigated>> {
14877        let definition =
14878            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14879        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14880        cx.spawn_in(window, async move |editor, cx| {
14881            if definition.await? == Navigated::Yes {
14882                return Ok(Navigated::Yes);
14883            }
14884            match fallback_strategy {
14885                GoToDefinitionFallback::None => Ok(Navigated::No),
14886                GoToDefinitionFallback::FindAllReferences => {
14887                    match editor.update_in(cx, |editor, window, cx| {
14888                        editor.find_all_references(&FindAllReferences, window, cx)
14889                    })? {
14890                        Some(references) => references.await,
14891                        None => Ok(Navigated::No),
14892                    }
14893                }
14894            }
14895        })
14896    }
14897
14898    pub fn go_to_declaration(
14899        &mut self,
14900        _: &GoToDeclaration,
14901        window: &mut Window,
14902        cx: &mut Context<Self>,
14903    ) -> Task<Result<Navigated>> {
14904        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14905    }
14906
14907    pub fn go_to_declaration_split(
14908        &mut self,
14909        _: &GoToDeclaration,
14910        window: &mut Window,
14911        cx: &mut Context<Self>,
14912    ) -> Task<Result<Navigated>> {
14913        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14914    }
14915
14916    pub fn go_to_implementation(
14917        &mut self,
14918        _: &GoToImplementation,
14919        window: &mut Window,
14920        cx: &mut Context<Self>,
14921    ) -> Task<Result<Navigated>> {
14922        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14923    }
14924
14925    pub fn go_to_implementation_split(
14926        &mut self,
14927        _: &GoToImplementationSplit,
14928        window: &mut Window,
14929        cx: &mut Context<Self>,
14930    ) -> Task<Result<Navigated>> {
14931        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14932    }
14933
14934    pub fn go_to_type_definition(
14935        &mut self,
14936        _: &GoToTypeDefinition,
14937        window: &mut Window,
14938        cx: &mut Context<Self>,
14939    ) -> Task<Result<Navigated>> {
14940        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14941    }
14942
14943    pub fn go_to_definition_split(
14944        &mut self,
14945        _: &GoToDefinitionSplit,
14946        window: &mut Window,
14947        cx: &mut Context<Self>,
14948    ) -> Task<Result<Navigated>> {
14949        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14950    }
14951
14952    pub fn go_to_type_definition_split(
14953        &mut self,
14954        _: &GoToTypeDefinitionSplit,
14955        window: &mut Window,
14956        cx: &mut Context<Self>,
14957    ) -> Task<Result<Navigated>> {
14958        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14959    }
14960
14961    fn go_to_definition_of_kind(
14962        &mut self,
14963        kind: GotoDefinitionKind,
14964        split: bool,
14965        window: &mut Window,
14966        cx: &mut Context<Self>,
14967    ) -> Task<Result<Navigated>> {
14968        let Some(provider) = self.semantics_provider.clone() else {
14969            return Task::ready(Ok(Navigated::No));
14970        };
14971        let head = self.selections.newest::<usize>(cx).head();
14972        let buffer = self.buffer.read(cx);
14973        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14974            text_anchor
14975        } else {
14976            return Task::ready(Ok(Navigated::No));
14977        };
14978
14979        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14980            return Task::ready(Ok(Navigated::No));
14981        };
14982
14983        cx.spawn_in(window, async move |editor, cx| {
14984            let definitions = definitions.await?;
14985            let navigated = editor
14986                .update_in(cx, |editor, window, cx| {
14987                    editor.navigate_to_hover_links(
14988                        Some(kind),
14989                        definitions
14990                            .into_iter()
14991                            .filter(|location| {
14992                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14993                            })
14994                            .map(HoverLink::Text)
14995                            .collect::<Vec<_>>(),
14996                        split,
14997                        window,
14998                        cx,
14999                    )
15000                })?
15001                .await?;
15002            anyhow::Ok(navigated)
15003        })
15004    }
15005
15006    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15007        let selection = self.selections.newest_anchor();
15008        let head = selection.head();
15009        let tail = selection.tail();
15010
15011        let Some((buffer, start_position)) =
15012            self.buffer.read(cx).text_anchor_for_position(head, cx)
15013        else {
15014            return;
15015        };
15016
15017        let end_position = if head != tail {
15018            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15019                return;
15020            };
15021            Some(pos)
15022        } else {
15023            None
15024        };
15025
15026        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15027            let url = if let Some(end_pos) = end_position {
15028                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15029            } else {
15030                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15031            };
15032
15033            if let Some(url) = url {
15034                editor.update(cx, |_, cx| {
15035                    cx.open_url(&url);
15036                })
15037            } else {
15038                Ok(())
15039            }
15040        });
15041
15042        url_finder.detach();
15043    }
15044
15045    pub fn open_selected_filename(
15046        &mut self,
15047        _: &OpenSelectedFilename,
15048        window: &mut Window,
15049        cx: &mut Context<Self>,
15050    ) {
15051        let Some(workspace) = self.workspace() else {
15052            return;
15053        };
15054
15055        let position = self.selections.newest_anchor().head();
15056
15057        let Some((buffer, buffer_position)) =
15058            self.buffer.read(cx).text_anchor_for_position(position, cx)
15059        else {
15060            return;
15061        };
15062
15063        let project = self.project.clone();
15064
15065        cx.spawn_in(window, async move |_, cx| {
15066            let result = find_file(&buffer, project, buffer_position, cx).await;
15067
15068            if let Some((_, path)) = result {
15069                workspace
15070                    .update_in(cx, |workspace, window, cx| {
15071                        workspace.open_resolved_path(path, window, cx)
15072                    })?
15073                    .await?;
15074            }
15075            anyhow::Ok(())
15076        })
15077        .detach();
15078    }
15079
15080    pub(crate) fn navigate_to_hover_links(
15081        &mut self,
15082        kind: Option<GotoDefinitionKind>,
15083        mut definitions: Vec<HoverLink>,
15084        split: bool,
15085        window: &mut Window,
15086        cx: &mut Context<Editor>,
15087    ) -> Task<Result<Navigated>> {
15088        // If there is one definition, just open it directly
15089        if definitions.len() == 1 {
15090            let definition = definitions.pop().unwrap();
15091
15092            enum TargetTaskResult {
15093                Location(Option<Location>),
15094                AlreadyNavigated,
15095            }
15096
15097            let target_task = match definition {
15098                HoverLink::Text(link) => {
15099                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15100                }
15101                HoverLink::InlayHint(lsp_location, server_id) => {
15102                    let computation =
15103                        self.compute_target_location(lsp_location, server_id, window, cx);
15104                    cx.background_spawn(async move {
15105                        let location = computation.await?;
15106                        Ok(TargetTaskResult::Location(location))
15107                    })
15108                }
15109                HoverLink::Url(url) => {
15110                    cx.open_url(&url);
15111                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15112                }
15113                HoverLink::File(path) => {
15114                    if let Some(workspace) = self.workspace() {
15115                        cx.spawn_in(window, async move |_, cx| {
15116                            workspace
15117                                .update_in(cx, |workspace, window, cx| {
15118                                    workspace.open_resolved_path(path, window, cx)
15119                                })?
15120                                .await
15121                                .map(|_| TargetTaskResult::AlreadyNavigated)
15122                        })
15123                    } else {
15124                        Task::ready(Ok(TargetTaskResult::Location(None)))
15125                    }
15126                }
15127            };
15128            cx.spawn_in(window, async move |editor, cx| {
15129                let target = match target_task.await.context("target resolution task")? {
15130                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15131                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15132                    TargetTaskResult::Location(Some(target)) => target,
15133                };
15134
15135                editor.update_in(cx, |editor, window, cx| {
15136                    let Some(workspace) = editor.workspace() else {
15137                        return Navigated::No;
15138                    };
15139                    let pane = workspace.read(cx).active_pane().clone();
15140
15141                    let range = target.range.to_point(target.buffer.read(cx));
15142                    let range = editor.range_for_match(&range);
15143                    let range = collapse_multiline_range(range);
15144
15145                    if !split
15146                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15147                    {
15148                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15149                    } else {
15150                        window.defer(cx, move |window, cx| {
15151                            let target_editor: Entity<Self> =
15152                                workspace.update(cx, |workspace, cx| {
15153                                    let pane = if split {
15154                                        workspace.adjacent_pane(window, cx)
15155                                    } else {
15156                                        workspace.active_pane().clone()
15157                                    };
15158
15159                                    workspace.open_project_item(
15160                                        pane,
15161                                        target.buffer.clone(),
15162                                        true,
15163                                        true,
15164                                        window,
15165                                        cx,
15166                                    )
15167                                });
15168                            target_editor.update(cx, |target_editor, cx| {
15169                                // When selecting a definition in a different buffer, disable the nav history
15170                                // to avoid creating a history entry at the previous cursor location.
15171                                pane.update(cx, |pane, _| pane.disable_history());
15172                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15173                                pane.update(cx, |pane, _| pane.enable_history());
15174                            });
15175                        });
15176                    }
15177                    Navigated::Yes
15178                })
15179            })
15180        } else if !definitions.is_empty() {
15181            cx.spawn_in(window, async move |editor, cx| {
15182                let (title, location_tasks, workspace) = editor
15183                    .update_in(cx, |editor, window, cx| {
15184                        let tab_kind = match kind {
15185                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15186                            _ => "Definitions",
15187                        };
15188                        let title = definitions
15189                            .iter()
15190                            .find_map(|definition| match definition {
15191                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15192                                    let buffer = origin.buffer.read(cx);
15193                                    format!(
15194                                        "{} for {}",
15195                                        tab_kind,
15196                                        buffer
15197                                            .text_for_range(origin.range.clone())
15198                                            .collect::<String>()
15199                                    )
15200                                }),
15201                                HoverLink::InlayHint(_, _) => None,
15202                                HoverLink::Url(_) => None,
15203                                HoverLink::File(_) => None,
15204                            })
15205                            .unwrap_or(tab_kind.to_string());
15206                        let location_tasks = definitions
15207                            .into_iter()
15208                            .map(|definition| match definition {
15209                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15210                                HoverLink::InlayHint(lsp_location, server_id) => editor
15211                                    .compute_target_location(lsp_location, server_id, window, cx),
15212                                HoverLink::Url(_) => Task::ready(Ok(None)),
15213                                HoverLink::File(_) => Task::ready(Ok(None)),
15214                            })
15215                            .collect::<Vec<_>>();
15216                        (title, location_tasks, editor.workspace().clone())
15217                    })
15218                    .context("location tasks preparation")?;
15219
15220                let locations: Vec<Location> = future::join_all(location_tasks)
15221                    .await
15222                    .into_iter()
15223                    .filter_map(|location| location.transpose())
15224                    .collect::<Result<_>>()
15225                    .context("location tasks")?;
15226
15227                if locations.is_empty() {
15228                    return Ok(Navigated::No);
15229                }
15230
15231                let Some(workspace) = workspace else {
15232                    return Ok(Navigated::No);
15233                };
15234
15235                let opened = workspace
15236                    .update_in(cx, |workspace, window, cx| {
15237                        Self::open_locations_in_multibuffer(
15238                            workspace,
15239                            locations,
15240                            title,
15241                            split,
15242                            MultibufferSelectionMode::First,
15243                            window,
15244                            cx,
15245                        )
15246                    })
15247                    .ok();
15248
15249                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15250            })
15251        } else {
15252            Task::ready(Ok(Navigated::No))
15253        }
15254    }
15255
15256    fn compute_target_location(
15257        &self,
15258        lsp_location: lsp::Location,
15259        server_id: LanguageServerId,
15260        window: &mut Window,
15261        cx: &mut Context<Self>,
15262    ) -> Task<anyhow::Result<Option<Location>>> {
15263        let Some(project) = self.project.clone() else {
15264            return Task::ready(Ok(None));
15265        };
15266
15267        cx.spawn_in(window, async move |editor, cx| {
15268            let location_task = editor.update(cx, |_, cx| {
15269                project.update(cx, |project, cx| {
15270                    let language_server_name = project
15271                        .language_server_statuses(cx)
15272                        .find(|(id, _)| server_id == *id)
15273                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15274                    language_server_name.map(|language_server_name| {
15275                        project.open_local_buffer_via_lsp(
15276                            lsp_location.uri.clone(),
15277                            server_id,
15278                            language_server_name,
15279                            cx,
15280                        )
15281                    })
15282                })
15283            })?;
15284            let location = match location_task {
15285                Some(task) => Some({
15286                    let target_buffer_handle = task.await.context("open local buffer")?;
15287                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15288                        let target_start = target_buffer
15289                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15290                        let target_end = target_buffer
15291                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15292                        target_buffer.anchor_after(target_start)
15293                            ..target_buffer.anchor_before(target_end)
15294                    })?;
15295                    Location {
15296                        buffer: target_buffer_handle,
15297                        range,
15298                    }
15299                }),
15300                None => None,
15301            };
15302            Ok(location)
15303        })
15304    }
15305
15306    pub fn find_all_references(
15307        &mut self,
15308        _: &FindAllReferences,
15309        window: &mut Window,
15310        cx: &mut Context<Self>,
15311    ) -> Option<Task<Result<Navigated>>> {
15312        let selection = self.selections.newest::<usize>(cx);
15313        let multi_buffer = self.buffer.read(cx);
15314        let head = selection.head();
15315
15316        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15317        let head_anchor = multi_buffer_snapshot.anchor_at(
15318            head,
15319            if head < selection.tail() {
15320                Bias::Right
15321            } else {
15322                Bias::Left
15323            },
15324        );
15325
15326        match self
15327            .find_all_references_task_sources
15328            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15329        {
15330            Ok(_) => {
15331                log::info!(
15332                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15333                );
15334                return None;
15335            }
15336            Err(i) => {
15337                self.find_all_references_task_sources.insert(i, head_anchor);
15338            }
15339        }
15340
15341        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15342        let workspace = self.workspace()?;
15343        let project = workspace.read(cx).project().clone();
15344        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15345        Some(cx.spawn_in(window, async move |editor, cx| {
15346            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15347                if let Ok(i) = editor
15348                    .find_all_references_task_sources
15349                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15350                {
15351                    editor.find_all_references_task_sources.remove(i);
15352                }
15353            });
15354
15355            let locations = references.await?;
15356            if locations.is_empty() {
15357                return anyhow::Ok(Navigated::No);
15358            }
15359
15360            workspace.update_in(cx, |workspace, window, cx| {
15361                let title = locations
15362                    .first()
15363                    .as_ref()
15364                    .map(|location| {
15365                        let buffer = location.buffer.read(cx);
15366                        format!(
15367                            "References to `{}`",
15368                            buffer
15369                                .text_for_range(location.range.clone())
15370                                .collect::<String>()
15371                        )
15372                    })
15373                    .unwrap();
15374                Self::open_locations_in_multibuffer(
15375                    workspace,
15376                    locations,
15377                    title,
15378                    false,
15379                    MultibufferSelectionMode::First,
15380                    window,
15381                    cx,
15382                );
15383                Navigated::Yes
15384            })
15385        }))
15386    }
15387
15388    /// Opens a multibuffer with the given project locations in it
15389    pub fn open_locations_in_multibuffer(
15390        workspace: &mut Workspace,
15391        mut locations: Vec<Location>,
15392        title: String,
15393        split: bool,
15394        multibuffer_selection_mode: MultibufferSelectionMode,
15395        window: &mut Window,
15396        cx: &mut Context<Workspace>,
15397    ) {
15398        if locations.is_empty() {
15399            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15400            return;
15401        }
15402
15403        // If there are multiple definitions, open them in a multibuffer
15404        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15405        let mut locations = locations.into_iter().peekable();
15406        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15407        let capability = workspace.project().read(cx).capability();
15408
15409        let excerpt_buffer = cx.new(|cx| {
15410            let mut multibuffer = MultiBuffer::new(capability);
15411            while let Some(location) = locations.next() {
15412                let buffer = location.buffer.read(cx);
15413                let mut ranges_for_buffer = Vec::new();
15414                let range = location.range.to_point(buffer);
15415                ranges_for_buffer.push(range.clone());
15416
15417                while let Some(next_location) = locations.peek() {
15418                    if next_location.buffer == location.buffer {
15419                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15420                        locations.next();
15421                    } else {
15422                        break;
15423                    }
15424                }
15425
15426                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15427                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15428                    PathKey::for_buffer(&location.buffer, cx),
15429                    location.buffer.clone(),
15430                    ranges_for_buffer,
15431                    DEFAULT_MULTIBUFFER_CONTEXT,
15432                    cx,
15433                );
15434                ranges.extend(new_ranges)
15435            }
15436
15437            multibuffer.with_title(title)
15438        });
15439
15440        let editor = cx.new(|cx| {
15441            Editor::for_multibuffer(
15442                excerpt_buffer,
15443                Some(workspace.project().clone()),
15444                window,
15445                cx,
15446            )
15447        });
15448        editor.update(cx, |editor, cx| {
15449            match multibuffer_selection_mode {
15450                MultibufferSelectionMode::First => {
15451                    if let Some(first_range) = ranges.first() {
15452                        editor.change_selections(None, window, cx, |selections| {
15453                            selections.clear_disjoint();
15454                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15455                        });
15456                    }
15457                    editor.highlight_background::<Self>(
15458                        &ranges,
15459                        |theme| theme.colors().editor_highlighted_line_background,
15460                        cx,
15461                    );
15462                }
15463                MultibufferSelectionMode::All => {
15464                    editor.change_selections(None, window, cx, |selections| {
15465                        selections.clear_disjoint();
15466                        selections.select_anchor_ranges(ranges);
15467                    });
15468                }
15469            }
15470            editor.register_buffers_with_language_servers(cx);
15471        });
15472
15473        let item = Box::new(editor);
15474        let item_id = item.item_id();
15475
15476        if split {
15477            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15478        } else {
15479            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15480                let (preview_item_id, preview_item_idx) =
15481                    workspace.active_pane().read_with(cx, |pane, _| {
15482                        (pane.preview_item_id(), pane.preview_item_idx())
15483                    });
15484
15485                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15486
15487                if let Some(preview_item_id) = preview_item_id {
15488                    workspace.active_pane().update(cx, |pane, cx| {
15489                        pane.remove_item(preview_item_id, false, false, window, cx);
15490                    });
15491                }
15492            } else {
15493                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15494            }
15495        }
15496        workspace.active_pane().update(cx, |pane, cx| {
15497            pane.set_preview_item_id(Some(item_id), cx);
15498        });
15499    }
15500
15501    pub fn rename(
15502        &mut self,
15503        _: &Rename,
15504        window: &mut Window,
15505        cx: &mut Context<Self>,
15506    ) -> Option<Task<Result<()>>> {
15507        use language::ToOffset as _;
15508
15509        let provider = self.semantics_provider.clone()?;
15510        let selection = self.selections.newest_anchor().clone();
15511        let (cursor_buffer, cursor_buffer_position) = self
15512            .buffer
15513            .read(cx)
15514            .text_anchor_for_position(selection.head(), cx)?;
15515        let (tail_buffer, cursor_buffer_position_end) = self
15516            .buffer
15517            .read(cx)
15518            .text_anchor_for_position(selection.tail(), cx)?;
15519        if tail_buffer != cursor_buffer {
15520            return None;
15521        }
15522
15523        let snapshot = cursor_buffer.read(cx).snapshot();
15524        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15525        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15526        let prepare_rename = provider
15527            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15528            .unwrap_or_else(|| Task::ready(Ok(None)));
15529        drop(snapshot);
15530
15531        Some(cx.spawn_in(window, async move |this, cx| {
15532            let rename_range = if let Some(range) = prepare_rename.await? {
15533                Some(range)
15534            } else {
15535                this.update(cx, |this, cx| {
15536                    let buffer = this.buffer.read(cx).snapshot(cx);
15537                    let mut buffer_highlights = this
15538                        .document_highlights_for_position(selection.head(), &buffer)
15539                        .filter(|highlight| {
15540                            highlight.start.excerpt_id == selection.head().excerpt_id
15541                                && highlight.end.excerpt_id == selection.head().excerpt_id
15542                        });
15543                    buffer_highlights
15544                        .next()
15545                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15546                })?
15547            };
15548            if let Some(rename_range) = rename_range {
15549                this.update_in(cx, |this, window, cx| {
15550                    let snapshot = cursor_buffer.read(cx).snapshot();
15551                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15552                    let cursor_offset_in_rename_range =
15553                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15554                    let cursor_offset_in_rename_range_end =
15555                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15556
15557                    this.take_rename(false, window, cx);
15558                    let buffer = this.buffer.read(cx).read(cx);
15559                    let cursor_offset = selection.head().to_offset(&buffer);
15560                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15561                    let rename_end = rename_start + rename_buffer_range.len();
15562                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15563                    let mut old_highlight_id = None;
15564                    let old_name: Arc<str> = buffer
15565                        .chunks(rename_start..rename_end, true)
15566                        .map(|chunk| {
15567                            if old_highlight_id.is_none() {
15568                                old_highlight_id = chunk.syntax_highlight_id;
15569                            }
15570                            chunk.text
15571                        })
15572                        .collect::<String>()
15573                        .into();
15574
15575                    drop(buffer);
15576
15577                    // Position the selection in the rename editor so that it matches the current selection.
15578                    this.show_local_selections = false;
15579                    let rename_editor = cx.new(|cx| {
15580                        let mut editor = Editor::single_line(window, cx);
15581                        editor.buffer.update(cx, |buffer, cx| {
15582                            buffer.edit([(0..0, old_name.clone())], None, cx)
15583                        });
15584                        let rename_selection_range = match cursor_offset_in_rename_range
15585                            .cmp(&cursor_offset_in_rename_range_end)
15586                        {
15587                            Ordering::Equal => {
15588                                editor.select_all(&SelectAll, window, cx);
15589                                return editor;
15590                            }
15591                            Ordering::Less => {
15592                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15593                            }
15594                            Ordering::Greater => {
15595                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15596                            }
15597                        };
15598                        if rename_selection_range.end > old_name.len() {
15599                            editor.select_all(&SelectAll, window, cx);
15600                        } else {
15601                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15602                                s.select_ranges([rename_selection_range]);
15603                            });
15604                        }
15605                        editor
15606                    });
15607                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15608                        if e == &EditorEvent::Focused {
15609                            cx.emit(EditorEvent::FocusedIn)
15610                        }
15611                    })
15612                    .detach();
15613
15614                    let write_highlights =
15615                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15616                    let read_highlights =
15617                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15618                    let ranges = write_highlights
15619                        .iter()
15620                        .flat_map(|(_, ranges)| ranges.iter())
15621                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15622                        .cloned()
15623                        .collect();
15624
15625                    this.highlight_text::<Rename>(
15626                        ranges,
15627                        HighlightStyle {
15628                            fade_out: Some(0.6),
15629                            ..Default::default()
15630                        },
15631                        cx,
15632                    );
15633                    let rename_focus_handle = rename_editor.focus_handle(cx);
15634                    window.focus(&rename_focus_handle);
15635                    let block_id = this.insert_blocks(
15636                        [BlockProperties {
15637                            style: BlockStyle::Flex,
15638                            placement: BlockPlacement::Below(range.start),
15639                            height: Some(1),
15640                            render: Arc::new({
15641                                let rename_editor = rename_editor.clone();
15642                                move |cx: &mut BlockContext| {
15643                                    let mut text_style = cx.editor_style.text.clone();
15644                                    if let Some(highlight_style) = old_highlight_id
15645                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15646                                    {
15647                                        text_style = text_style.highlight(highlight_style);
15648                                    }
15649                                    div()
15650                                        .block_mouse_except_scroll()
15651                                        .pl(cx.anchor_x)
15652                                        .child(EditorElement::new(
15653                                            &rename_editor,
15654                                            EditorStyle {
15655                                                background: cx.theme().system().transparent,
15656                                                local_player: cx.editor_style.local_player,
15657                                                text: text_style,
15658                                                scrollbar_width: cx.editor_style.scrollbar_width,
15659                                                syntax: cx.editor_style.syntax.clone(),
15660                                                status: cx.editor_style.status.clone(),
15661                                                inlay_hints_style: HighlightStyle {
15662                                                    font_weight: Some(FontWeight::BOLD),
15663                                                    ..make_inlay_hints_style(cx.app)
15664                                                },
15665                                                inline_completion_styles: make_suggestion_styles(
15666                                                    cx.app,
15667                                                ),
15668                                                ..EditorStyle::default()
15669                                            },
15670                                        ))
15671                                        .into_any_element()
15672                                }
15673                            }),
15674                            priority: 0,
15675                            render_in_minimap: true,
15676                        }],
15677                        Some(Autoscroll::fit()),
15678                        cx,
15679                    )[0];
15680                    this.pending_rename = Some(RenameState {
15681                        range,
15682                        old_name,
15683                        editor: rename_editor,
15684                        block_id,
15685                    });
15686                })?;
15687            }
15688
15689            Ok(())
15690        }))
15691    }
15692
15693    pub fn confirm_rename(
15694        &mut self,
15695        _: &ConfirmRename,
15696        window: &mut Window,
15697        cx: &mut Context<Self>,
15698    ) -> Option<Task<Result<()>>> {
15699        let rename = self.take_rename(false, window, cx)?;
15700        let workspace = self.workspace()?.downgrade();
15701        let (buffer, start) = self
15702            .buffer
15703            .read(cx)
15704            .text_anchor_for_position(rename.range.start, cx)?;
15705        let (end_buffer, _) = self
15706            .buffer
15707            .read(cx)
15708            .text_anchor_for_position(rename.range.end, cx)?;
15709        if buffer != end_buffer {
15710            return None;
15711        }
15712
15713        let old_name = rename.old_name;
15714        let new_name = rename.editor.read(cx).text(cx);
15715
15716        let rename = self.semantics_provider.as_ref()?.perform_rename(
15717            &buffer,
15718            start,
15719            new_name.clone(),
15720            cx,
15721        )?;
15722
15723        Some(cx.spawn_in(window, async move |editor, cx| {
15724            let project_transaction = rename.await?;
15725            Self::open_project_transaction(
15726                &editor,
15727                workspace,
15728                project_transaction,
15729                format!("Rename: {}{}", old_name, new_name),
15730                cx,
15731            )
15732            .await?;
15733
15734            editor.update(cx, |editor, cx| {
15735                editor.refresh_document_highlights(cx);
15736            })?;
15737            Ok(())
15738        }))
15739    }
15740
15741    fn take_rename(
15742        &mut self,
15743        moving_cursor: bool,
15744        window: &mut Window,
15745        cx: &mut Context<Self>,
15746    ) -> Option<RenameState> {
15747        let rename = self.pending_rename.take()?;
15748        if rename.editor.focus_handle(cx).is_focused(window) {
15749            window.focus(&self.focus_handle);
15750        }
15751
15752        self.remove_blocks(
15753            [rename.block_id].into_iter().collect(),
15754            Some(Autoscroll::fit()),
15755            cx,
15756        );
15757        self.clear_highlights::<Rename>(cx);
15758        self.show_local_selections = true;
15759
15760        if moving_cursor {
15761            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15762                editor.selections.newest::<usize>(cx).head()
15763            });
15764
15765            // Update the selection to match the position of the selection inside
15766            // the rename editor.
15767            let snapshot = self.buffer.read(cx).read(cx);
15768            let rename_range = rename.range.to_offset(&snapshot);
15769            let cursor_in_editor = snapshot
15770                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15771                .min(rename_range.end);
15772            drop(snapshot);
15773
15774            self.change_selections(None, window, cx, |s| {
15775                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15776            });
15777        } else {
15778            self.refresh_document_highlights(cx);
15779        }
15780
15781        Some(rename)
15782    }
15783
15784    pub fn pending_rename(&self) -> Option<&RenameState> {
15785        self.pending_rename.as_ref()
15786    }
15787
15788    fn format(
15789        &mut self,
15790        _: &Format,
15791        window: &mut Window,
15792        cx: &mut Context<Self>,
15793    ) -> Option<Task<Result<()>>> {
15794        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15795
15796        let project = match &self.project {
15797            Some(project) => project.clone(),
15798            None => return None,
15799        };
15800
15801        Some(self.perform_format(
15802            project,
15803            FormatTrigger::Manual,
15804            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15805            window,
15806            cx,
15807        ))
15808    }
15809
15810    fn format_selections(
15811        &mut self,
15812        _: &FormatSelections,
15813        window: &mut Window,
15814        cx: &mut Context<Self>,
15815    ) -> Option<Task<Result<()>>> {
15816        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15817
15818        let project = match &self.project {
15819            Some(project) => project.clone(),
15820            None => return None,
15821        };
15822
15823        let ranges = self
15824            .selections
15825            .all_adjusted(cx)
15826            .into_iter()
15827            .map(|selection| selection.range())
15828            .collect_vec();
15829
15830        Some(self.perform_format(
15831            project,
15832            FormatTrigger::Manual,
15833            FormatTarget::Ranges(ranges),
15834            window,
15835            cx,
15836        ))
15837    }
15838
15839    fn perform_format(
15840        &mut self,
15841        project: Entity<Project>,
15842        trigger: FormatTrigger,
15843        target: FormatTarget,
15844        window: &mut Window,
15845        cx: &mut Context<Self>,
15846    ) -> Task<Result<()>> {
15847        let buffer = self.buffer.clone();
15848        let (buffers, target) = match target {
15849            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
15850            FormatTarget::Ranges(selection_ranges) => {
15851                let multi_buffer = buffer.read(cx);
15852                let snapshot = multi_buffer.read(cx);
15853                let mut buffers = HashSet::default();
15854                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15855                    BTreeMap::new();
15856                for selection_range in selection_ranges {
15857                    for (buffer, buffer_range, _) in
15858                        snapshot.range_to_buffer_ranges(selection_range)
15859                    {
15860                        let buffer_id = buffer.remote_id();
15861                        let start = buffer.anchor_before(buffer_range.start);
15862                        let end = buffer.anchor_after(buffer_range.end);
15863                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15864                        buffer_id_to_ranges
15865                            .entry(buffer_id)
15866                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15867                            .or_insert_with(|| vec![start..end]);
15868                    }
15869                }
15870                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15871            }
15872        };
15873
15874        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15875        let selections_prev = transaction_id_prev
15876            .and_then(|transaction_id_prev| {
15877                // default to selections as they were after the last edit, if we have them,
15878                // instead of how they are now.
15879                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15880                // will take you back to where you made the last edit, instead of staying where you scrolled
15881                self.selection_history
15882                    .transaction(transaction_id_prev)
15883                    .map(|t| t.0.clone())
15884            })
15885            .unwrap_or_else(|| {
15886                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15887                self.selections.disjoint_anchors()
15888            });
15889
15890        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15891        let format = project.update(cx, |project, cx| {
15892            project.format(buffers, target, true, trigger, cx)
15893        });
15894
15895        cx.spawn_in(window, async move |editor, cx| {
15896            let transaction = futures::select_biased! {
15897                transaction = format.log_err().fuse() => transaction,
15898                () = timeout => {
15899                    log::warn!("timed out waiting for formatting");
15900                    None
15901                }
15902            };
15903
15904            buffer
15905                .update(cx, |buffer, cx| {
15906                    if let Some(transaction) = transaction {
15907                        if !buffer.is_singleton() {
15908                            buffer.push_transaction(&transaction.0, cx);
15909                        }
15910                    }
15911                    cx.notify();
15912                })
15913                .ok();
15914
15915            if let Some(transaction_id_now) =
15916                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15917            {
15918                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15919                if has_new_transaction {
15920                    _ = editor.update(cx, |editor, _| {
15921                        editor
15922                            .selection_history
15923                            .insert_transaction(transaction_id_now, selections_prev);
15924                    });
15925                }
15926            }
15927
15928            Ok(())
15929        })
15930    }
15931
15932    fn organize_imports(
15933        &mut self,
15934        _: &OrganizeImports,
15935        window: &mut Window,
15936        cx: &mut Context<Self>,
15937    ) -> Option<Task<Result<()>>> {
15938        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15939        let project = match &self.project {
15940            Some(project) => project.clone(),
15941            None => return None,
15942        };
15943        Some(self.perform_code_action_kind(
15944            project,
15945            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15946            window,
15947            cx,
15948        ))
15949    }
15950
15951    fn perform_code_action_kind(
15952        &mut self,
15953        project: Entity<Project>,
15954        kind: CodeActionKind,
15955        window: &mut Window,
15956        cx: &mut Context<Self>,
15957    ) -> Task<Result<()>> {
15958        let buffer = self.buffer.clone();
15959        let buffers = buffer.read(cx).all_buffers();
15960        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15961        let apply_action = project.update(cx, |project, cx| {
15962            project.apply_code_action_kind(buffers, kind, true, cx)
15963        });
15964        cx.spawn_in(window, async move |_, cx| {
15965            let transaction = futures::select_biased! {
15966                () = timeout => {
15967                    log::warn!("timed out waiting for executing code action");
15968                    None
15969                }
15970                transaction = apply_action.log_err().fuse() => transaction,
15971            };
15972            buffer
15973                .update(cx, |buffer, cx| {
15974                    // check if we need this
15975                    if let Some(transaction) = transaction {
15976                        if !buffer.is_singleton() {
15977                            buffer.push_transaction(&transaction.0, cx);
15978                        }
15979                    }
15980                    cx.notify();
15981                })
15982                .ok();
15983            Ok(())
15984        })
15985    }
15986
15987    fn restart_language_server(
15988        &mut self,
15989        _: &RestartLanguageServer,
15990        _: &mut Window,
15991        cx: &mut Context<Self>,
15992    ) {
15993        if let Some(project) = self.project.clone() {
15994            self.buffer.update(cx, |multi_buffer, cx| {
15995                project.update(cx, |project, cx| {
15996                    project.restart_language_servers_for_buffers(
15997                        multi_buffer.all_buffers().into_iter().collect(),
15998                        cx,
15999                    );
16000                });
16001            })
16002        }
16003    }
16004
16005    fn stop_language_server(
16006        &mut self,
16007        _: &StopLanguageServer,
16008        _: &mut Window,
16009        cx: &mut Context<Self>,
16010    ) {
16011        if let Some(project) = self.project.clone() {
16012            self.buffer.update(cx, |multi_buffer, cx| {
16013                project.update(cx, |project, cx| {
16014                    project.stop_language_servers_for_buffers(
16015                        multi_buffer.all_buffers().into_iter().collect(),
16016                        cx,
16017                    );
16018                    cx.emit(project::Event::RefreshInlayHints);
16019                });
16020            });
16021        }
16022    }
16023
16024    fn cancel_language_server_work(
16025        workspace: &mut Workspace,
16026        _: &actions::CancelLanguageServerWork,
16027        _: &mut Window,
16028        cx: &mut Context<Workspace>,
16029    ) {
16030        let project = workspace.project();
16031        let buffers = workspace
16032            .active_item(cx)
16033            .and_then(|item| item.act_as::<Editor>(cx))
16034            .map_or(HashSet::default(), |editor| {
16035                editor.read(cx).buffer.read(cx).all_buffers()
16036            });
16037        project.update(cx, |project, cx| {
16038            project.cancel_language_server_work_for_buffers(buffers, cx);
16039        });
16040    }
16041
16042    fn show_character_palette(
16043        &mut self,
16044        _: &ShowCharacterPalette,
16045        window: &mut Window,
16046        _: &mut Context<Self>,
16047    ) {
16048        window.show_character_palette();
16049    }
16050
16051    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16052        if self.mode.is_minimap() {
16053            return;
16054        }
16055
16056        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16057            let buffer = self.buffer.read(cx).snapshot(cx);
16058            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16059            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16060            let is_valid = buffer
16061                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16062                .any(|entry| {
16063                    entry.diagnostic.is_primary
16064                        && !entry.range.is_empty()
16065                        && entry.range.start == primary_range_start
16066                        && entry.diagnostic.message == active_diagnostics.active_message
16067                });
16068
16069            if !is_valid {
16070                self.dismiss_diagnostics(cx);
16071            }
16072        }
16073    }
16074
16075    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16076        match &self.active_diagnostics {
16077            ActiveDiagnostic::Group(group) => Some(group),
16078            _ => None,
16079        }
16080    }
16081
16082    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16083        self.dismiss_diagnostics(cx);
16084        self.active_diagnostics = ActiveDiagnostic::All;
16085    }
16086
16087    fn activate_diagnostics(
16088        &mut self,
16089        buffer_id: BufferId,
16090        diagnostic: DiagnosticEntry<usize>,
16091        window: &mut Window,
16092        cx: &mut Context<Self>,
16093    ) {
16094        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16095            return;
16096        }
16097        self.dismiss_diagnostics(cx);
16098        let snapshot = self.snapshot(window, cx);
16099        let buffer = self.buffer.read(cx).snapshot(cx);
16100        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16101            return;
16102        };
16103
16104        let diagnostic_group = buffer
16105            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16106            .collect::<Vec<_>>();
16107
16108        let blocks =
16109            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16110
16111        let blocks = self.display_map.update(cx, |display_map, cx| {
16112            display_map.insert_blocks(blocks, cx).into_iter().collect()
16113        });
16114        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16115            active_range: buffer.anchor_before(diagnostic.range.start)
16116                ..buffer.anchor_after(diagnostic.range.end),
16117            active_message: diagnostic.diagnostic.message.clone(),
16118            group_id: diagnostic.diagnostic.group_id,
16119            blocks,
16120        });
16121        cx.notify();
16122    }
16123
16124    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16125        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16126            return;
16127        };
16128
16129        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16130        if let ActiveDiagnostic::Group(group) = prev {
16131            self.display_map.update(cx, |display_map, cx| {
16132                display_map.remove_blocks(group.blocks, cx);
16133            });
16134            cx.notify();
16135        }
16136    }
16137
16138    /// Disable inline diagnostics rendering for this editor.
16139    pub fn disable_inline_diagnostics(&mut self) {
16140        self.inline_diagnostics_enabled = false;
16141        self.inline_diagnostics_update = Task::ready(());
16142        self.inline_diagnostics.clear();
16143    }
16144
16145    pub fn diagnostics_enabled(&self) -> bool {
16146        self.mode.is_full()
16147    }
16148
16149    pub fn inline_diagnostics_enabled(&self) -> bool {
16150        self.diagnostics_enabled() && self.inline_diagnostics_enabled
16151    }
16152
16153    pub fn show_inline_diagnostics(&self) -> bool {
16154        self.show_inline_diagnostics
16155    }
16156
16157    pub fn toggle_inline_diagnostics(
16158        &mut self,
16159        _: &ToggleInlineDiagnostics,
16160        window: &mut Window,
16161        cx: &mut Context<Editor>,
16162    ) {
16163        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16164        self.refresh_inline_diagnostics(false, window, cx);
16165    }
16166
16167    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16168        self.diagnostics_max_severity = severity;
16169        self.display_map.update(cx, |display_map, _| {
16170            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16171        });
16172    }
16173
16174    pub fn toggle_diagnostics(
16175        &mut self,
16176        _: &ToggleDiagnostics,
16177        window: &mut Window,
16178        cx: &mut Context<Editor>,
16179    ) {
16180        if !self.diagnostics_enabled() {
16181            return;
16182        }
16183
16184        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16185            EditorSettings::get_global(cx)
16186                .diagnostics_max_severity
16187                .filter(|severity| severity != &DiagnosticSeverity::Off)
16188                .unwrap_or(DiagnosticSeverity::Hint)
16189        } else {
16190            DiagnosticSeverity::Off
16191        };
16192        self.set_max_diagnostics_severity(new_severity, cx);
16193        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16194            self.active_diagnostics = ActiveDiagnostic::None;
16195            self.inline_diagnostics_update = Task::ready(());
16196            self.inline_diagnostics.clear();
16197        } else {
16198            self.refresh_inline_diagnostics(false, window, cx);
16199        }
16200
16201        cx.notify();
16202    }
16203
16204    pub fn toggle_minimap(
16205        &mut self,
16206        _: &ToggleMinimap,
16207        window: &mut Window,
16208        cx: &mut Context<Editor>,
16209    ) {
16210        if self.supports_minimap(cx) {
16211            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16212        }
16213    }
16214
16215    fn refresh_inline_diagnostics(
16216        &mut self,
16217        debounce: bool,
16218        window: &mut Window,
16219        cx: &mut Context<Self>,
16220    ) {
16221        let max_severity = ProjectSettings::get_global(cx)
16222            .diagnostics
16223            .inline
16224            .max_severity
16225            .unwrap_or(self.diagnostics_max_severity);
16226
16227        if !self.inline_diagnostics_enabled()
16228            || !self.show_inline_diagnostics
16229            || max_severity == DiagnosticSeverity::Off
16230        {
16231            self.inline_diagnostics_update = Task::ready(());
16232            self.inline_diagnostics.clear();
16233            return;
16234        }
16235
16236        let debounce_ms = ProjectSettings::get_global(cx)
16237            .diagnostics
16238            .inline
16239            .update_debounce_ms;
16240        let debounce = if debounce && debounce_ms > 0 {
16241            Some(Duration::from_millis(debounce_ms))
16242        } else {
16243            None
16244        };
16245        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16246            if let Some(debounce) = debounce {
16247                cx.background_executor().timer(debounce).await;
16248            }
16249            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16250                editor
16251                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16252                    .ok()
16253            }) else {
16254                return;
16255            };
16256
16257            let new_inline_diagnostics = cx
16258                .background_spawn(async move {
16259                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16260                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16261                        let message = diagnostic_entry
16262                            .diagnostic
16263                            .message
16264                            .split_once('\n')
16265                            .map(|(line, _)| line)
16266                            .map(SharedString::new)
16267                            .unwrap_or_else(|| {
16268                                SharedString::from(diagnostic_entry.diagnostic.message)
16269                            });
16270                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16271                        let (Ok(i) | Err(i)) = inline_diagnostics
16272                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16273                        inline_diagnostics.insert(
16274                            i,
16275                            (
16276                                start_anchor,
16277                                InlineDiagnostic {
16278                                    message,
16279                                    group_id: diagnostic_entry.diagnostic.group_id,
16280                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16281                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16282                                    severity: diagnostic_entry.diagnostic.severity,
16283                                },
16284                            ),
16285                        );
16286                    }
16287                    inline_diagnostics
16288                })
16289                .await;
16290
16291            editor
16292                .update(cx, |editor, cx| {
16293                    editor.inline_diagnostics = new_inline_diagnostics;
16294                    cx.notify();
16295                })
16296                .ok();
16297        });
16298    }
16299
16300    fn pull_diagnostics(
16301        &mut self,
16302        buffer_id: Option<BufferId>,
16303        window: &Window,
16304        cx: &mut Context<Self>,
16305    ) -> Option<()> {
16306        if !self.mode().is_full() {
16307            return None;
16308        }
16309        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16310            .diagnostics
16311            .lsp_pull_diagnostics;
16312        if !pull_diagnostics_settings.enabled {
16313            return None;
16314        }
16315        let project = self.project.as_ref()?.downgrade();
16316        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16317        let mut buffers = self.buffer.read(cx).all_buffers();
16318        if let Some(buffer_id) = buffer_id {
16319            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16320        }
16321
16322        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16323            cx.background_executor().timer(debounce).await;
16324
16325            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16326                buffers
16327                    .into_iter()
16328                    .filter_map(|buffer| {
16329                        project
16330                            .update(cx, |project, cx| {
16331                                project.lsp_store().update(cx, |lsp_store, cx| {
16332                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16333                                })
16334                            })
16335                            .ok()
16336                    })
16337                    .collect::<FuturesUnordered<_>>()
16338            }) else {
16339                return;
16340            };
16341
16342            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16343                match pull_task {
16344                    Ok(()) => {
16345                        if editor
16346                            .update_in(cx, |editor, window, cx| {
16347                                editor.update_diagnostics_state(window, cx);
16348                            })
16349                            .is_err()
16350                        {
16351                            return;
16352                        }
16353                    }
16354                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16355                }
16356            }
16357        });
16358
16359        Some(())
16360    }
16361
16362    pub fn set_selections_from_remote(
16363        &mut self,
16364        selections: Vec<Selection<Anchor>>,
16365        pending_selection: Option<Selection<Anchor>>,
16366        window: &mut Window,
16367        cx: &mut Context<Self>,
16368    ) {
16369        let old_cursor_position = self.selections.newest_anchor().head();
16370        self.selections.change_with(cx, |s| {
16371            s.select_anchors(selections);
16372            if let Some(pending_selection) = pending_selection {
16373                s.set_pending(pending_selection, SelectMode::Character);
16374            } else {
16375                s.clear_pending();
16376            }
16377        });
16378        self.selections_did_change(
16379            false,
16380            &old_cursor_position,
16381            SelectionEffects::default(),
16382            window,
16383            cx,
16384        );
16385    }
16386
16387    pub fn transact(
16388        &mut self,
16389        window: &mut Window,
16390        cx: &mut Context<Self>,
16391        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16392    ) -> Option<TransactionId> {
16393        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16394            this.start_transaction_at(Instant::now(), window, cx);
16395            update(this, window, cx);
16396            this.end_transaction_at(Instant::now(), cx)
16397        })
16398    }
16399
16400    pub fn start_transaction_at(
16401        &mut self,
16402        now: Instant,
16403        window: &mut Window,
16404        cx: &mut Context<Self>,
16405    ) {
16406        self.end_selection(window, cx);
16407        if let Some(tx_id) = self
16408            .buffer
16409            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16410        {
16411            self.selection_history
16412                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16413            cx.emit(EditorEvent::TransactionBegun {
16414                transaction_id: tx_id,
16415            })
16416        }
16417    }
16418
16419    pub fn end_transaction_at(
16420        &mut self,
16421        now: Instant,
16422        cx: &mut Context<Self>,
16423    ) -> Option<TransactionId> {
16424        if let Some(transaction_id) = self
16425            .buffer
16426            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16427        {
16428            if let Some((_, end_selections)) =
16429                self.selection_history.transaction_mut(transaction_id)
16430            {
16431                *end_selections = Some(self.selections.disjoint_anchors());
16432            } else {
16433                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16434            }
16435
16436            cx.emit(EditorEvent::Edited { transaction_id });
16437            Some(transaction_id)
16438        } else {
16439            None
16440        }
16441    }
16442
16443    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16444        if self.selection_mark_mode {
16445            self.change_selections(None, window, cx, |s| {
16446                s.move_with(|_, sel| {
16447                    sel.collapse_to(sel.head(), SelectionGoal::None);
16448                });
16449            })
16450        }
16451        self.selection_mark_mode = true;
16452        cx.notify();
16453    }
16454
16455    pub fn swap_selection_ends(
16456        &mut self,
16457        _: &actions::SwapSelectionEnds,
16458        window: &mut Window,
16459        cx: &mut Context<Self>,
16460    ) {
16461        self.change_selections(None, window, cx, |s| {
16462            s.move_with(|_, sel| {
16463                if sel.start != sel.end {
16464                    sel.reversed = !sel.reversed
16465                }
16466            });
16467        });
16468        self.request_autoscroll(Autoscroll::newest(), cx);
16469        cx.notify();
16470    }
16471
16472    pub fn toggle_fold(
16473        &mut self,
16474        _: &actions::ToggleFold,
16475        window: &mut Window,
16476        cx: &mut Context<Self>,
16477    ) {
16478        if self.is_singleton(cx) {
16479            let selection = self.selections.newest::<Point>(cx);
16480
16481            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16482            let range = if selection.is_empty() {
16483                let point = selection.head().to_display_point(&display_map);
16484                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16485                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16486                    .to_point(&display_map);
16487                start..end
16488            } else {
16489                selection.range()
16490            };
16491            if display_map.folds_in_range(range).next().is_some() {
16492                self.unfold_lines(&Default::default(), window, cx)
16493            } else {
16494                self.fold(&Default::default(), window, cx)
16495            }
16496        } else {
16497            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16498            let buffer_ids: HashSet<_> = self
16499                .selections
16500                .disjoint_anchor_ranges()
16501                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16502                .collect();
16503
16504            let should_unfold = buffer_ids
16505                .iter()
16506                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16507
16508            for buffer_id in buffer_ids {
16509                if should_unfold {
16510                    self.unfold_buffer(buffer_id, cx);
16511                } else {
16512                    self.fold_buffer(buffer_id, cx);
16513                }
16514            }
16515        }
16516    }
16517
16518    pub fn toggle_fold_recursive(
16519        &mut self,
16520        _: &actions::ToggleFoldRecursive,
16521        window: &mut Window,
16522        cx: &mut Context<Self>,
16523    ) {
16524        let selection = self.selections.newest::<Point>(cx);
16525
16526        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16527        let range = if selection.is_empty() {
16528            let point = selection.head().to_display_point(&display_map);
16529            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16530            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16531                .to_point(&display_map);
16532            start..end
16533        } else {
16534            selection.range()
16535        };
16536        if display_map.folds_in_range(range).next().is_some() {
16537            self.unfold_recursive(&Default::default(), window, cx)
16538        } else {
16539            self.fold_recursive(&Default::default(), window, cx)
16540        }
16541    }
16542
16543    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16544        if self.is_singleton(cx) {
16545            let mut to_fold = Vec::new();
16546            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16547            let selections = self.selections.all_adjusted(cx);
16548
16549            for selection in selections {
16550                let range = selection.range().sorted();
16551                let buffer_start_row = range.start.row;
16552
16553                if range.start.row != range.end.row {
16554                    let mut found = false;
16555                    let mut row = range.start.row;
16556                    while row <= range.end.row {
16557                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16558                        {
16559                            found = true;
16560                            row = crease.range().end.row + 1;
16561                            to_fold.push(crease);
16562                        } else {
16563                            row += 1
16564                        }
16565                    }
16566                    if found {
16567                        continue;
16568                    }
16569                }
16570
16571                for row in (0..=range.start.row).rev() {
16572                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16573                        if crease.range().end.row >= buffer_start_row {
16574                            to_fold.push(crease);
16575                            if row <= range.start.row {
16576                                break;
16577                            }
16578                        }
16579                    }
16580                }
16581            }
16582
16583            self.fold_creases(to_fold, true, window, cx);
16584        } else {
16585            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16586            let buffer_ids = self
16587                .selections
16588                .disjoint_anchor_ranges()
16589                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16590                .collect::<HashSet<_>>();
16591            for buffer_id in buffer_ids {
16592                self.fold_buffer(buffer_id, cx);
16593            }
16594        }
16595    }
16596
16597    fn fold_at_level(
16598        &mut self,
16599        fold_at: &FoldAtLevel,
16600        window: &mut Window,
16601        cx: &mut Context<Self>,
16602    ) {
16603        if !self.buffer.read(cx).is_singleton() {
16604            return;
16605        }
16606
16607        let fold_at_level = fold_at.0;
16608        let snapshot = self.buffer.read(cx).snapshot(cx);
16609        let mut to_fold = Vec::new();
16610        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16611
16612        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16613            while start_row < end_row {
16614                match self
16615                    .snapshot(window, cx)
16616                    .crease_for_buffer_row(MultiBufferRow(start_row))
16617                {
16618                    Some(crease) => {
16619                        let nested_start_row = crease.range().start.row + 1;
16620                        let nested_end_row = crease.range().end.row;
16621
16622                        if current_level < fold_at_level {
16623                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16624                        } else if current_level == fold_at_level {
16625                            to_fold.push(crease);
16626                        }
16627
16628                        start_row = nested_end_row + 1;
16629                    }
16630                    None => start_row += 1,
16631                }
16632            }
16633        }
16634
16635        self.fold_creases(to_fold, true, window, cx);
16636    }
16637
16638    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16639        if self.buffer.read(cx).is_singleton() {
16640            let mut fold_ranges = Vec::new();
16641            let snapshot = self.buffer.read(cx).snapshot(cx);
16642
16643            for row in 0..snapshot.max_row().0 {
16644                if let Some(foldable_range) = self
16645                    .snapshot(window, cx)
16646                    .crease_for_buffer_row(MultiBufferRow(row))
16647                {
16648                    fold_ranges.push(foldable_range);
16649                }
16650            }
16651
16652            self.fold_creases(fold_ranges, true, window, cx);
16653        } else {
16654            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16655                editor
16656                    .update_in(cx, |editor, _, cx| {
16657                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16658                            editor.fold_buffer(buffer_id, cx);
16659                        }
16660                    })
16661                    .ok();
16662            });
16663        }
16664    }
16665
16666    pub fn fold_function_bodies(
16667        &mut self,
16668        _: &actions::FoldFunctionBodies,
16669        window: &mut Window,
16670        cx: &mut Context<Self>,
16671    ) {
16672        let snapshot = self.buffer.read(cx).snapshot(cx);
16673
16674        let ranges = snapshot
16675            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16676            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16677            .collect::<Vec<_>>();
16678
16679        let creases = ranges
16680            .into_iter()
16681            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16682            .collect();
16683
16684        self.fold_creases(creases, true, window, cx);
16685    }
16686
16687    pub fn fold_recursive(
16688        &mut self,
16689        _: &actions::FoldRecursive,
16690        window: &mut Window,
16691        cx: &mut Context<Self>,
16692    ) {
16693        let mut to_fold = Vec::new();
16694        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16695        let selections = self.selections.all_adjusted(cx);
16696
16697        for selection in selections {
16698            let range = selection.range().sorted();
16699            let buffer_start_row = range.start.row;
16700
16701            if range.start.row != range.end.row {
16702                let mut found = false;
16703                for row in range.start.row..=range.end.row {
16704                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16705                        found = true;
16706                        to_fold.push(crease);
16707                    }
16708                }
16709                if found {
16710                    continue;
16711                }
16712            }
16713
16714            for row in (0..=range.start.row).rev() {
16715                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16716                    if crease.range().end.row >= buffer_start_row {
16717                        to_fold.push(crease);
16718                    } else {
16719                        break;
16720                    }
16721                }
16722            }
16723        }
16724
16725        self.fold_creases(to_fold, true, window, cx);
16726    }
16727
16728    pub fn fold_at(
16729        &mut self,
16730        buffer_row: MultiBufferRow,
16731        window: &mut Window,
16732        cx: &mut Context<Self>,
16733    ) {
16734        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16735
16736        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16737            let autoscroll = self
16738                .selections
16739                .all::<Point>(cx)
16740                .iter()
16741                .any(|selection| crease.range().overlaps(&selection.range()));
16742
16743            self.fold_creases(vec![crease], autoscroll, window, cx);
16744        }
16745    }
16746
16747    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16748        if self.is_singleton(cx) {
16749            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16750            let buffer = &display_map.buffer_snapshot;
16751            let selections = self.selections.all::<Point>(cx);
16752            let ranges = selections
16753                .iter()
16754                .map(|s| {
16755                    let range = s.display_range(&display_map).sorted();
16756                    let mut start = range.start.to_point(&display_map);
16757                    let mut end = range.end.to_point(&display_map);
16758                    start.column = 0;
16759                    end.column = buffer.line_len(MultiBufferRow(end.row));
16760                    start..end
16761                })
16762                .collect::<Vec<_>>();
16763
16764            self.unfold_ranges(&ranges, true, true, cx);
16765        } else {
16766            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16767            let buffer_ids = self
16768                .selections
16769                .disjoint_anchor_ranges()
16770                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16771                .collect::<HashSet<_>>();
16772            for buffer_id in buffer_ids {
16773                self.unfold_buffer(buffer_id, cx);
16774            }
16775        }
16776    }
16777
16778    pub fn unfold_recursive(
16779        &mut self,
16780        _: &UnfoldRecursive,
16781        _window: &mut Window,
16782        cx: &mut Context<Self>,
16783    ) {
16784        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16785        let selections = self.selections.all::<Point>(cx);
16786        let ranges = selections
16787            .iter()
16788            .map(|s| {
16789                let mut range = s.display_range(&display_map).sorted();
16790                *range.start.column_mut() = 0;
16791                *range.end.column_mut() = display_map.line_len(range.end.row());
16792                let start = range.start.to_point(&display_map);
16793                let end = range.end.to_point(&display_map);
16794                start..end
16795            })
16796            .collect::<Vec<_>>();
16797
16798        self.unfold_ranges(&ranges, true, true, cx);
16799    }
16800
16801    pub fn unfold_at(
16802        &mut self,
16803        buffer_row: MultiBufferRow,
16804        _window: &mut Window,
16805        cx: &mut Context<Self>,
16806    ) {
16807        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16808
16809        let intersection_range = Point::new(buffer_row.0, 0)
16810            ..Point::new(
16811                buffer_row.0,
16812                display_map.buffer_snapshot.line_len(buffer_row),
16813            );
16814
16815        let autoscroll = self
16816            .selections
16817            .all::<Point>(cx)
16818            .iter()
16819            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16820
16821        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16822    }
16823
16824    pub fn unfold_all(
16825        &mut self,
16826        _: &actions::UnfoldAll,
16827        _window: &mut Window,
16828        cx: &mut Context<Self>,
16829    ) {
16830        if self.buffer.read(cx).is_singleton() {
16831            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16832            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16833        } else {
16834            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16835                editor
16836                    .update(cx, |editor, cx| {
16837                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16838                            editor.unfold_buffer(buffer_id, cx);
16839                        }
16840                    })
16841                    .ok();
16842            });
16843        }
16844    }
16845
16846    pub fn fold_selected_ranges(
16847        &mut self,
16848        _: &FoldSelectedRanges,
16849        window: &mut Window,
16850        cx: &mut Context<Self>,
16851    ) {
16852        let selections = self.selections.all_adjusted(cx);
16853        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16854        let ranges = selections
16855            .into_iter()
16856            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16857            .collect::<Vec<_>>();
16858        self.fold_creases(ranges, true, window, cx);
16859    }
16860
16861    pub fn fold_ranges<T: ToOffset + Clone>(
16862        &mut self,
16863        ranges: Vec<Range<T>>,
16864        auto_scroll: bool,
16865        window: &mut Window,
16866        cx: &mut Context<Self>,
16867    ) {
16868        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16869        let ranges = ranges
16870            .into_iter()
16871            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16872            .collect::<Vec<_>>();
16873        self.fold_creases(ranges, auto_scroll, window, cx);
16874    }
16875
16876    pub fn fold_creases<T: ToOffset + Clone>(
16877        &mut self,
16878        creases: Vec<Crease<T>>,
16879        auto_scroll: bool,
16880        _window: &mut Window,
16881        cx: &mut Context<Self>,
16882    ) {
16883        if creases.is_empty() {
16884            return;
16885        }
16886
16887        let mut buffers_affected = HashSet::default();
16888        let multi_buffer = self.buffer().read(cx);
16889        for crease in &creases {
16890            if let Some((_, buffer, _)) =
16891                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16892            {
16893                buffers_affected.insert(buffer.read(cx).remote_id());
16894            };
16895        }
16896
16897        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16898
16899        if auto_scroll {
16900            self.request_autoscroll(Autoscroll::fit(), cx);
16901        }
16902
16903        cx.notify();
16904
16905        self.scrollbar_marker_state.dirty = true;
16906        self.folds_did_change(cx);
16907    }
16908
16909    /// Removes any folds whose ranges intersect any of the given ranges.
16910    pub fn unfold_ranges<T: ToOffset + Clone>(
16911        &mut self,
16912        ranges: &[Range<T>],
16913        inclusive: bool,
16914        auto_scroll: bool,
16915        cx: &mut Context<Self>,
16916    ) {
16917        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16918            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16919        });
16920        self.folds_did_change(cx);
16921    }
16922
16923    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16924        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16925            return;
16926        }
16927        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16928        self.display_map.update(cx, |display_map, cx| {
16929            display_map.fold_buffers([buffer_id], cx)
16930        });
16931        cx.emit(EditorEvent::BufferFoldToggled {
16932            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16933            folded: true,
16934        });
16935        cx.notify();
16936    }
16937
16938    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16939        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16940            return;
16941        }
16942        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16943        self.display_map.update(cx, |display_map, cx| {
16944            display_map.unfold_buffers([buffer_id], cx);
16945        });
16946        cx.emit(EditorEvent::BufferFoldToggled {
16947            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16948            folded: false,
16949        });
16950        cx.notify();
16951    }
16952
16953    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16954        self.display_map.read(cx).is_buffer_folded(buffer)
16955    }
16956
16957    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16958        self.display_map.read(cx).folded_buffers()
16959    }
16960
16961    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16962        self.display_map.update(cx, |display_map, cx| {
16963            display_map.disable_header_for_buffer(buffer_id, cx);
16964        });
16965        cx.notify();
16966    }
16967
16968    /// Removes any folds with the given ranges.
16969    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16970        &mut self,
16971        ranges: &[Range<T>],
16972        type_id: TypeId,
16973        auto_scroll: bool,
16974        cx: &mut Context<Self>,
16975    ) {
16976        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16977            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16978        });
16979        self.folds_did_change(cx);
16980    }
16981
16982    fn remove_folds_with<T: ToOffset + Clone>(
16983        &mut self,
16984        ranges: &[Range<T>],
16985        auto_scroll: bool,
16986        cx: &mut Context<Self>,
16987        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16988    ) {
16989        if ranges.is_empty() {
16990            return;
16991        }
16992
16993        let mut buffers_affected = HashSet::default();
16994        let multi_buffer = self.buffer().read(cx);
16995        for range in ranges {
16996            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16997                buffers_affected.insert(buffer.read(cx).remote_id());
16998            };
16999        }
17000
17001        self.display_map.update(cx, update);
17002
17003        if auto_scroll {
17004            self.request_autoscroll(Autoscroll::fit(), cx);
17005        }
17006
17007        cx.notify();
17008        self.scrollbar_marker_state.dirty = true;
17009        self.active_indent_guides_state.dirty = true;
17010    }
17011
17012    pub fn update_fold_widths(
17013        &mut self,
17014        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
17015        cx: &mut Context<Self>,
17016    ) -> bool {
17017        self.display_map
17018            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17019    }
17020
17021    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17022        self.display_map.read(cx).fold_placeholder.clone()
17023    }
17024
17025    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17026        self.buffer.update(cx, |buffer, cx| {
17027            buffer.set_all_diff_hunks_expanded(cx);
17028        });
17029    }
17030
17031    pub fn expand_all_diff_hunks(
17032        &mut self,
17033        _: &ExpandAllDiffHunks,
17034        _window: &mut Window,
17035        cx: &mut Context<Self>,
17036    ) {
17037        self.buffer.update(cx, |buffer, cx| {
17038            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17039        });
17040    }
17041
17042    pub fn toggle_selected_diff_hunks(
17043        &mut self,
17044        _: &ToggleSelectedDiffHunks,
17045        _window: &mut Window,
17046        cx: &mut Context<Self>,
17047    ) {
17048        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17049        self.toggle_diff_hunks_in_ranges(ranges, cx);
17050    }
17051
17052    pub fn diff_hunks_in_ranges<'a>(
17053        &'a self,
17054        ranges: &'a [Range<Anchor>],
17055        buffer: &'a MultiBufferSnapshot,
17056    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17057        ranges.iter().flat_map(move |range| {
17058            let end_excerpt_id = range.end.excerpt_id;
17059            let range = range.to_point(buffer);
17060            let mut peek_end = range.end;
17061            if range.end.row < buffer.max_row().0 {
17062                peek_end = Point::new(range.end.row + 1, 0);
17063            }
17064            buffer
17065                .diff_hunks_in_range(range.start..peek_end)
17066                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17067        })
17068    }
17069
17070    pub fn has_stageable_diff_hunks_in_ranges(
17071        &self,
17072        ranges: &[Range<Anchor>],
17073        snapshot: &MultiBufferSnapshot,
17074    ) -> bool {
17075        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17076        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17077    }
17078
17079    pub fn toggle_staged_selected_diff_hunks(
17080        &mut self,
17081        _: &::git::ToggleStaged,
17082        _: &mut Window,
17083        cx: &mut Context<Self>,
17084    ) {
17085        let snapshot = self.buffer.read(cx).snapshot(cx);
17086        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17087        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17088        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17089    }
17090
17091    pub fn set_render_diff_hunk_controls(
17092        &mut self,
17093        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17094        cx: &mut Context<Self>,
17095    ) {
17096        self.render_diff_hunk_controls = render_diff_hunk_controls;
17097        cx.notify();
17098    }
17099
17100    pub fn stage_and_next(
17101        &mut self,
17102        _: &::git::StageAndNext,
17103        window: &mut Window,
17104        cx: &mut Context<Self>,
17105    ) {
17106        self.do_stage_or_unstage_and_next(true, window, cx);
17107    }
17108
17109    pub fn unstage_and_next(
17110        &mut self,
17111        _: &::git::UnstageAndNext,
17112        window: &mut Window,
17113        cx: &mut Context<Self>,
17114    ) {
17115        self.do_stage_or_unstage_and_next(false, window, cx);
17116    }
17117
17118    pub fn stage_or_unstage_diff_hunks(
17119        &mut self,
17120        stage: bool,
17121        ranges: Vec<Range<Anchor>>,
17122        cx: &mut Context<Self>,
17123    ) {
17124        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17125        cx.spawn(async move |this, cx| {
17126            task.await?;
17127            this.update(cx, |this, cx| {
17128                let snapshot = this.buffer.read(cx).snapshot(cx);
17129                let chunk_by = this
17130                    .diff_hunks_in_ranges(&ranges, &snapshot)
17131                    .chunk_by(|hunk| hunk.buffer_id);
17132                for (buffer_id, hunks) in &chunk_by {
17133                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17134                }
17135            })
17136        })
17137        .detach_and_log_err(cx);
17138    }
17139
17140    fn save_buffers_for_ranges_if_needed(
17141        &mut self,
17142        ranges: &[Range<Anchor>],
17143        cx: &mut Context<Editor>,
17144    ) -> Task<Result<()>> {
17145        let multibuffer = self.buffer.read(cx);
17146        let snapshot = multibuffer.read(cx);
17147        let buffer_ids: HashSet<_> = ranges
17148            .iter()
17149            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17150            .collect();
17151        drop(snapshot);
17152
17153        let mut buffers = HashSet::default();
17154        for buffer_id in buffer_ids {
17155            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17156                let buffer = buffer_entity.read(cx);
17157                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17158                {
17159                    buffers.insert(buffer_entity);
17160                }
17161            }
17162        }
17163
17164        if let Some(project) = &self.project {
17165            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17166        } else {
17167            Task::ready(Ok(()))
17168        }
17169    }
17170
17171    fn do_stage_or_unstage_and_next(
17172        &mut self,
17173        stage: bool,
17174        window: &mut Window,
17175        cx: &mut Context<Self>,
17176    ) {
17177        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17178
17179        if ranges.iter().any(|range| range.start != range.end) {
17180            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17181            return;
17182        }
17183
17184        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17185        let snapshot = self.snapshot(window, cx);
17186        let position = self.selections.newest::<Point>(cx).head();
17187        let mut row = snapshot
17188            .buffer_snapshot
17189            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17190            .find(|hunk| hunk.row_range.start.0 > position.row)
17191            .map(|hunk| hunk.row_range.start);
17192
17193        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17194        // Outside of the project diff editor, wrap around to the beginning.
17195        if !all_diff_hunks_expanded {
17196            row = row.or_else(|| {
17197                snapshot
17198                    .buffer_snapshot
17199                    .diff_hunks_in_range(Point::zero()..position)
17200                    .find(|hunk| hunk.row_range.end.0 < position.row)
17201                    .map(|hunk| hunk.row_range.start)
17202            });
17203        }
17204
17205        if let Some(row) = row {
17206            let destination = Point::new(row.0, 0);
17207            let autoscroll = Autoscroll::center();
17208
17209            self.unfold_ranges(&[destination..destination], false, false, cx);
17210            self.change_selections(Some(autoscroll), window, cx, |s| {
17211                s.select_ranges([destination..destination]);
17212            });
17213        }
17214    }
17215
17216    fn do_stage_or_unstage(
17217        &self,
17218        stage: bool,
17219        buffer_id: BufferId,
17220        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17221        cx: &mut App,
17222    ) -> Option<()> {
17223        let project = self.project.as_ref()?;
17224        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17225        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17226        let buffer_snapshot = buffer.read(cx).snapshot();
17227        let file_exists = buffer_snapshot
17228            .file()
17229            .is_some_and(|file| file.disk_state().exists());
17230        diff.update(cx, |diff, cx| {
17231            diff.stage_or_unstage_hunks(
17232                stage,
17233                &hunks
17234                    .map(|hunk| buffer_diff::DiffHunk {
17235                        buffer_range: hunk.buffer_range,
17236                        diff_base_byte_range: hunk.diff_base_byte_range,
17237                        secondary_status: hunk.secondary_status,
17238                        range: Point::zero()..Point::zero(), // unused
17239                    })
17240                    .collect::<Vec<_>>(),
17241                &buffer_snapshot,
17242                file_exists,
17243                cx,
17244            )
17245        });
17246        None
17247    }
17248
17249    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17250        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17251        self.buffer
17252            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17253    }
17254
17255    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17256        self.buffer.update(cx, |buffer, cx| {
17257            let ranges = vec![Anchor::min()..Anchor::max()];
17258            if !buffer.all_diff_hunks_expanded()
17259                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17260            {
17261                buffer.collapse_diff_hunks(ranges, cx);
17262                true
17263            } else {
17264                false
17265            }
17266        })
17267    }
17268
17269    fn toggle_diff_hunks_in_ranges(
17270        &mut self,
17271        ranges: Vec<Range<Anchor>>,
17272        cx: &mut Context<Editor>,
17273    ) {
17274        self.buffer.update(cx, |buffer, cx| {
17275            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17276            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17277        })
17278    }
17279
17280    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17281        self.buffer.update(cx, |buffer, cx| {
17282            let snapshot = buffer.snapshot(cx);
17283            let excerpt_id = range.end.excerpt_id;
17284            let point_range = range.to_point(&snapshot);
17285            let expand = !buffer.single_hunk_is_expanded(range, cx);
17286            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17287        })
17288    }
17289
17290    pub(crate) fn apply_all_diff_hunks(
17291        &mut self,
17292        _: &ApplyAllDiffHunks,
17293        window: &mut Window,
17294        cx: &mut Context<Self>,
17295    ) {
17296        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17297
17298        let buffers = self.buffer.read(cx).all_buffers();
17299        for branch_buffer in buffers {
17300            branch_buffer.update(cx, |branch_buffer, cx| {
17301                branch_buffer.merge_into_base(Vec::new(), cx);
17302            });
17303        }
17304
17305        if let Some(project) = self.project.clone() {
17306            self.save(
17307                SaveOptions {
17308                    format: true,
17309                    autosave: false,
17310                },
17311                project,
17312                window,
17313                cx,
17314            )
17315            .detach_and_log_err(cx);
17316        }
17317    }
17318
17319    pub(crate) fn apply_selected_diff_hunks(
17320        &mut self,
17321        _: &ApplyDiffHunk,
17322        window: &mut Window,
17323        cx: &mut Context<Self>,
17324    ) {
17325        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17326        let snapshot = self.snapshot(window, cx);
17327        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17328        let mut ranges_by_buffer = HashMap::default();
17329        self.transact(window, cx, |editor, _window, cx| {
17330            for hunk in hunks {
17331                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17332                    ranges_by_buffer
17333                        .entry(buffer.clone())
17334                        .or_insert_with(Vec::new)
17335                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17336                }
17337            }
17338
17339            for (buffer, ranges) in ranges_by_buffer {
17340                buffer.update(cx, |buffer, cx| {
17341                    buffer.merge_into_base(ranges, cx);
17342                });
17343            }
17344        });
17345
17346        if let Some(project) = self.project.clone() {
17347            self.save(
17348                SaveOptions {
17349                    format: true,
17350                    autosave: false,
17351                },
17352                project,
17353                window,
17354                cx,
17355            )
17356            .detach_and_log_err(cx);
17357        }
17358    }
17359
17360    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17361        if hovered != self.gutter_hovered {
17362            self.gutter_hovered = hovered;
17363            cx.notify();
17364        }
17365    }
17366
17367    pub fn insert_blocks(
17368        &mut self,
17369        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17370        autoscroll: Option<Autoscroll>,
17371        cx: &mut Context<Self>,
17372    ) -> Vec<CustomBlockId> {
17373        let blocks = self
17374            .display_map
17375            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17376        if let Some(autoscroll) = autoscroll {
17377            self.request_autoscroll(autoscroll, cx);
17378        }
17379        cx.notify();
17380        blocks
17381    }
17382
17383    pub fn resize_blocks(
17384        &mut self,
17385        heights: HashMap<CustomBlockId, u32>,
17386        autoscroll: Option<Autoscroll>,
17387        cx: &mut Context<Self>,
17388    ) {
17389        self.display_map
17390            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17391        if let Some(autoscroll) = autoscroll {
17392            self.request_autoscroll(autoscroll, cx);
17393        }
17394        cx.notify();
17395    }
17396
17397    pub fn replace_blocks(
17398        &mut self,
17399        renderers: HashMap<CustomBlockId, RenderBlock>,
17400        autoscroll: Option<Autoscroll>,
17401        cx: &mut Context<Self>,
17402    ) {
17403        self.display_map
17404            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17405        if let Some(autoscroll) = autoscroll {
17406            self.request_autoscroll(autoscroll, cx);
17407        }
17408        cx.notify();
17409    }
17410
17411    pub fn remove_blocks(
17412        &mut self,
17413        block_ids: HashSet<CustomBlockId>,
17414        autoscroll: Option<Autoscroll>,
17415        cx: &mut Context<Self>,
17416    ) {
17417        self.display_map.update(cx, |display_map, cx| {
17418            display_map.remove_blocks(block_ids, cx)
17419        });
17420        if let Some(autoscroll) = autoscroll {
17421            self.request_autoscroll(autoscroll, cx);
17422        }
17423        cx.notify();
17424    }
17425
17426    pub fn row_for_block(
17427        &self,
17428        block_id: CustomBlockId,
17429        cx: &mut Context<Self>,
17430    ) -> Option<DisplayRow> {
17431        self.display_map
17432            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17433    }
17434
17435    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17436        self.focused_block = Some(focused_block);
17437    }
17438
17439    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17440        self.focused_block.take()
17441    }
17442
17443    pub fn insert_creases(
17444        &mut self,
17445        creases: impl IntoIterator<Item = Crease<Anchor>>,
17446        cx: &mut Context<Self>,
17447    ) -> Vec<CreaseId> {
17448        self.display_map
17449            .update(cx, |map, cx| map.insert_creases(creases, cx))
17450    }
17451
17452    pub fn remove_creases(
17453        &mut self,
17454        ids: impl IntoIterator<Item = CreaseId>,
17455        cx: &mut Context<Self>,
17456    ) -> Vec<(CreaseId, Range<Anchor>)> {
17457        self.display_map
17458            .update(cx, |map, cx| map.remove_creases(ids, cx))
17459    }
17460
17461    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17462        self.display_map
17463            .update(cx, |map, cx| map.snapshot(cx))
17464            .longest_row()
17465    }
17466
17467    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17468        self.display_map
17469            .update(cx, |map, cx| map.snapshot(cx))
17470            .max_point()
17471    }
17472
17473    pub fn text(&self, cx: &App) -> String {
17474        self.buffer.read(cx).read(cx).text()
17475    }
17476
17477    pub fn is_empty(&self, cx: &App) -> bool {
17478        self.buffer.read(cx).read(cx).is_empty()
17479    }
17480
17481    pub fn text_option(&self, cx: &App) -> Option<String> {
17482        let text = self.text(cx);
17483        let text = text.trim();
17484
17485        if text.is_empty() {
17486            return None;
17487        }
17488
17489        Some(text.to_string())
17490    }
17491
17492    pub fn set_text(
17493        &mut self,
17494        text: impl Into<Arc<str>>,
17495        window: &mut Window,
17496        cx: &mut Context<Self>,
17497    ) {
17498        self.transact(window, cx, |this, _, cx| {
17499            this.buffer
17500                .read(cx)
17501                .as_singleton()
17502                .expect("you can only call set_text on editors for singleton buffers")
17503                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17504        });
17505    }
17506
17507    pub fn display_text(&self, cx: &mut App) -> String {
17508        self.display_map
17509            .update(cx, |map, cx| map.snapshot(cx))
17510            .text()
17511    }
17512
17513    fn create_minimap(
17514        &self,
17515        minimap_settings: MinimapSettings,
17516        window: &mut Window,
17517        cx: &mut Context<Self>,
17518    ) -> Option<Entity<Self>> {
17519        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17520            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17521    }
17522
17523    fn initialize_new_minimap(
17524        &self,
17525        minimap_settings: MinimapSettings,
17526        window: &mut Window,
17527        cx: &mut Context<Self>,
17528    ) -> Entity<Self> {
17529        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17530
17531        let mut minimap = Editor::new_internal(
17532            EditorMode::Minimap {
17533                parent: cx.weak_entity(),
17534            },
17535            self.buffer.clone(),
17536            self.project.clone(),
17537            Some(self.display_map.clone()),
17538            window,
17539            cx,
17540        );
17541        minimap.scroll_manager.clone_state(&self.scroll_manager);
17542        minimap.set_text_style_refinement(TextStyleRefinement {
17543            font_size: Some(MINIMAP_FONT_SIZE),
17544            font_weight: Some(MINIMAP_FONT_WEIGHT),
17545            ..Default::default()
17546        });
17547        minimap.update_minimap_configuration(minimap_settings, cx);
17548        cx.new(|_| minimap)
17549    }
17550
17551    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17552        let current_line_highlight = minimap_settings
17553            .current_line_highlight
17554            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17555        self.set_current_line_highlight(Some(current_line_highlight));
17556    }
17557
17558    pub fn minimap(&self) -> Option<&Entity<Self>> {
17559        self.minimap
17560            .as_ref()
17561            .filter(|_| self.minimap_visibility.visible())
17562    }
17563
17564    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17565        let mut wrap_guides = smallvec![];
17566
17567        if self.show_wrap_guides == Some(false) {
17568            return wrap_guides;
17569        }
17570
17571        let settings = self.buffer.read(cx).language_settings(cx);
17572        if settings.show_wrap_guides {
17573            match self.soft_wrap_mode(cx) {
17574                SoftWrap::Column(soft_wrap) => {
17575                    wrap_guides.push((soft_wrap as usize, true));
17576                }
17577                SoftWrap::Bounded(soft_wrap) => {
17578                    wrap_guides.push((soft_wrap as usize, true));
17579                }
17580                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17581            }
17582            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17583        }
17584
17585        wrap_guides
17586    }
17587
17588    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17589        let settings = self.buffer.read(cx).language_settings(cx);
17590        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17591        match mode {
17592            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17593                SoftWrap::None
17594            }
17595            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17596            language_settings::SoftWrap::PreferredLineLength => {
17597                SoftWrap::Column(settings.preferred_line_length)
17598            }
17599            language_settings::SoftWrap::Bounded => {
17600                SoftWrap::Bounded(settings.preferred_line_length)
17601            }
17602        }
17603    }
17604
17605    pub fn set_soft_wrap_mode(
17606        &mut self,
17607        mode: language_settings::SoftWrap,
17608
17609        cx: &mut Context<Self>,
17610    ) {
17611        self.soft_wrap_mode_override = Some(mode);
17612        cx.notify();
17613    }
17614
17615    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17616        self.hard_wrap = hard_wrap;
17617        cx.notify();
17618    }
17619
17620    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17621        self.text_style_refinement = Some(style);
17622    }
17623
17624    /// called by the Element so we know what style we were most recently rendered with.
17625    pub(crate) fn set_style(
17626        &mut self,
17627        style: EditorStyle,
17628        window: &mut Window,
17629        cx: &mut Context<Self>,
17630    ) {
17631        // We intentionally do not inform the display map about the minimap style
17632        // so that wrapping is not recalculated and stays consistent for the editor
17633        // and its linked minimap.
17634        if !self.mode.is_minimap() {
17635            let rem_size = window.rem_size();
17636            self.display_map.update(cx, |map, cx| {
17637                map.set_font(
17638                    style.text.font(),
17639                    style.text.font_size.to_pixels(rem_size),
17640                    cx,
17641                )
17642            });
17643        }
17644        self.style = Some(style);
17645    }
17646
17647    pub fn style(&self) -> Option<&EditorStyle> {
17648        self.style.as_ref()
17649    }
17650
17651    // Called by the element. This method is not designed to be called outside of the editor
17652    // element's layout code because it does not notify when rewrapping is computed synchronously.
17653    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17654        self.display_map
17655            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17656    }
17657
17658    pub fn set_soft_wrap(&mut self) {
17659        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17660    }
17661
17662    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17663        if self.soft_wrap_mode_override.is_some() {
17664            self.soft_wrap_mode_override.take();
17665        } else {
17666            let soft_wrap = match self.soft_wrap_mode(cx) {
17667                SoftWrap::GitDiff => return,
17668                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17669                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17670                    language_settings::SoftWrap::None
17671                }
17672            };
17673            self.soft_wrap_mode_override = Some(soft_wrap);
17674        }
17675        cx.notify();
17676    }
17677
17678    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17679        let Some(workspace) = self.workspace() else {
17680            return;
17681        };
17682        let fs = workspace.read(cx).app_state().fs.clone();
17683        let current_show = TabBarSettings::get_global(cx).show;
17684        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17685            setting.show = Some(!current_show);
17686        });
17687    }
17688
17689    pub fn toggle_indent_guides(
17690        &mut self,
17691        _: &ToggleIndentGuides,
17692        _: &mut Window,
17693        cx: &mut Context<Self>,
17694    ) {
17695        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17696            self.buffer
17697                .read(cx)
17698                .language_settings(cx)
17699                .indent_guides
17700                .enabled
17701        });
17702        self.show_indent_guides = Some(!currently_enabled);
17703        cx.notify();
17704    }
17705
17706    fn should_show_indent_guides(&self) -> Option<bool> {
17707        self.show_indent_guides
17708    }
17709
17710    pub fn toggle_line_numbers(
17711        &mut self,
17712        _: &ToggleLineNumbers,
17713        _: &mut Window,
17714        cx: &mut Context<Self>,
17715    ) {
17716        let mut editor_settings = EditorSettings::get_global(cx).clone();
17717        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17718        EditorSettings::override_global(editor_settings, cx);
17719    }
17720
17721    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17722        if let Some(show_line_numbers) = self.show_line_numbers {
17723            return show_line_numbers;
17724        }
17725        EditorSettings::get_global(cx).gutter.line_numbers
17726    }
17727
17728    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17729        self.use_relative_line_numbers
17730            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17731    }
17732
17733    pub fn toggle_relative_line_numbers(
17734        &mut self,
17735        _: &ToggleRelativeLineNumbers,
17736        _: &mut Window,
17737        cx: &mut Context<Self>,
17738    ) {
17739        let is_relative = self.should_use_relative_line_numbers(cx);
17740        self.set_relative_line_number(Some(!is_relative), cx)
17741    }
17742
17743    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17744        self.use_relative_line_numbers = is_relative;
17745        cx.notify();
17746    }
17747
17748    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17749        self.show_gutter = show_gutter;
17750        cx.notify();
17751    }
17752
17753    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17754        self.show_scrollbars = ScrollbarAxes {
17755            horizontal: show,
17756            vertical: show,
17757        };
17758        cx.notify();
17759    }
17760
17761    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17762        self.show_scrollbars.vertical = show;
17763        cx.notify();
17764    }
17765
17766    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17767        self.show_scrollbars.horizontal = show;
17768        cx.notify();
17769    }
17770
17771    pub fn set_minimap_visibility(
17772        &mut self,
17773        minimap_visibility: MinimapVisibility,
17774        window: &mut Window,
17775        cx: &mut Context<Self>,
17776    ) {
17777        if self.minimap_visibility != minimap_visibility {
17778            if minimap_visibility.visible() && self.minimap.is_none() {
17779                let minimap_settings = EditorSettings::get_global(cx).minimap;
17780                self.minimap =
17781                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17782            }
17783            self.minimap_visibility = minimap_visibility;
17784            cx.notify();
17785        }
17786    }
17787
17788    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17789        self.set_show_scrollbars(false, cx);
17790        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17791    }
17792
17793    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17794        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17795    }
17796
17797    /// Normally the text in full mode and auto height editors is padded on the
17798    /// left side by roughly half a character width for improved hit testing.
17799    ///
17800    /// Use this method to disable this for cases where this is not wanted (e.g.
17801    /// if you want to align the editor text with some other text above or below)
17802    /// or if you want to add this padding to single-line editors.
17803    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17804        self.offset_content = offset_content;
17805        cx.notify();
17806    }
17807
17808    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17809        self.show_line_numbers = Some(show_line_numbers);
17810        cx.notify();
17811    }
17812
17813    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17814        self.disable_expand_excerpt_buttons = true;
17815        cx.notify();
17816    }
17817
17818    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17819        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17820        cx.notify();
17821    }
17822
17823    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17824        self.show_code_actions = Some(show_code_actions);
17825        cx.notify();
17826    }
17827
17828    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17829        self.show_runnables = Some(show_runnables);
17830        cx.notify();
17831    }
17832
17833    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17834        self.show_breakpoints = Some(show_breakpoints);
17835        cx.notify();
17836    }
17837
17838    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17839        if self.display_map.read(cx).masked != masked {
17840            self.display_map.update(cx, |map, _| map.masked = masked);
17841        }
17842        cx.notify()
17843    }
17844
17845    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17846        self.show_wrap_guides = Some(show_wrap_guides);
17847        cx.notify();
17848    }
17849
17850    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17851        self.show_indent_guides = Some(show_indent_guides);
17852        cx.notify();
17853    }
17854
17855    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17856        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17857            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17858                if let Some(dir) = file.abs_path(cx).parent() {
17859                    return Some(dir.to_owned());
17860                }
17861            }
17862
17863            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17864                return Some(project_path.path.to_path_buf());
17865            }
17866        }
17867
17868        None
17869    }
17870
17871    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17872        self.active_excerpt(cx)?
17873            .1
17874            .read(cx)
17875            .file()
17876            .and_then(|f| f.as_local())
17877    }
17878
17879    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17880        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17881            let buffer = buffer.read(cx);
17882            if let Some(project_path) = buffer.project_path(cx) {
17883                let project = self.project.as_ref()?.read(cx);
17884                project.absolute_path(&project_path, cx)
17885            } else {
17886                buffer
17887                    .file()
17888                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17889            }
17890        })
17891    }
17892
17893    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17894        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17895            let project_path = buffer.read(cx).project_path(cx)?;
17896            let project = self.project.as_ref()?.read(cx);
17897            let entry = project.entry_for_path(&project_path, cx)?;
17898            let path = entry.path.to_path_buf();
17899            Some(path)
17900        })
17901    }
17902
17903    pub fn reveal_in_finder(
17904        &mut self,
17905        _: &RevealInFileManager,
17906        _window: &mut Window,
17907        cx: &mut Context<Self>,
17908    ) {
17909        if let Some(target) = self.target_file(cx) {
17910            cx.reveal_path(&target.abs_path(cx));
17911        }
17912    }
17913
17914    pub fn copy_path(
17915        &mut self,
17916        _: &zed_actions::workspace::CopyPath,
17917        _window: &mut Window,
17918        cx: &mut Context<Self>,
17919    ) {
17920        if let Some(path) = self.target_file_abs_path(cx) {
17921            if let Some(path) = path.to_str() {
17922                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17923            }
17924        }
17925    }
17926
17927    pub fn copy_relative_path(
17928        &mut self,
17929        _: &zed_actions::workspace::CopyRelativePath,
17930        _window: &mut Window,
17931        cx: &mut Context<Self>,
17932    ) {
17933        if let Some(path) = self.target_file_path(cx) {
17934            if let Some(path) = path.to_str() {
17935                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17936            }
17937        }
17938    }
17939
17940    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17941        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17942            buffer.read(cx).project_path(cx)
17943        } else {
17944            None
17945        }
17946    }
17947
17948    // Returns true if the editor handled a go-to-line request
17949    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17950        maybe!({
17951            let breakpoint_store = self.breakpoint_store.as_ref()?;
17952
17953            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17954            else {
17955                self.clear_row_highlights::<ActiveDebugLine>();
17956                return None;
17957            };
17958
17959            let position = active_stack_frame.position;
17960            let buffer_id = position.buffer_id?;
17961            let snapshot = self
17962                .project
17963                .as_ref()?
17964                .read(cx)
17965                .buffer_for_id(buffer_id, cx)?
17966                .read(cx)
17967                .snapshot();
17968
17969            let mut handled = false;
17970            for (id, ExcerptRange { context, .. }) in
17971                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17972            {
17973                if context.start.cmp(&position, &snapshot).is_ge()
17974                    || context.end.cmp(&position, &snapshot).is_lt()
17975                {
17976                    continue;
17977                }
17978                let snapshot = self.buffer.read(cx).snapshot(cx);
17979                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17980
17981                handled = true;
17982                self.clear_row_highlights::<ActiveDebugLine>();
17983
17984                self.go_to_line::<ActiveDebugLine>(
17985                    multibuffer_anchor,
17986                    Some(cx.theme().colors().editor_debugger_active_line_background),
17987                    window,
17988                    cx,
17989                );
17990
17991                cx.notify();
17992            }
17993
17994            handled.then_some(())
17995        })
17996        .is_some()
17997    }
17998
17999    pub fn copy_file_name_without_extension(
18000        &mut self,
18001        _: &CopyFileNameWithoutExtension,
18002        _: &mut Window,
18003        cx: &mut Context<Self>,
18004    ) {
18005        if let Some(file) = self.target_file(cx) {
18006            if let Some(file_stem) = file.path().file_stem() {
18007                if let Some(name) = file_stem.to_str() {
18008                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18009                }
18010            }
18011        }
18012    }
18013
18014    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18015        if let Some(file) = self.target_file(cx) {
18016            if let Some(file_name) = file.path().file_name() {
18017                if let Some(name) = file_name.to_str() {
18018                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18019                }
18020            }
18021        }
18022    }
18023
18024    pub fn toggle_git_blame(
18025        &mut self,
18026        _: &::git::Blame,
18027        window: &mut Window,
18028        cx: &mut Context<Self>,
18029    ) {
18030        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18031
18032        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18033            self.start_git_blame(true, window, cx);
18034        }
18035
18036        cx.notify();
18037    }
18038
18039    pub fn toggle_git_blame_inline(
18040        &mut self,
18041        _: &ToggleGitBlameInline,
18042        window: &mut Window,
18043        cx: &mut Context<Self>,
18044    ) {
18045        self.toggle_git_blame_inline_internal(true, window, cx);
18046        cx.notify();
18047    }
18048
18049    pub fn open_git_blame_commit(
18050        &mut self,
18051        _: &OpenGitBlameCommit,
18052        window: &mut Window,
18053        cx: &mut Context<Self>,
18054    ) {
18055        self.open_git_blame_commit_internal(window, cx);
18056    }
18057
18058    fn open_git_blame_commit_internal(
18059        &mut self,
18060        window: &mut Window,
18061        cx: &mut Context<Self>,
18062    ) -> Option<()> {
18063        let blame = self.blame.as_ref()?;
18064        let snapshot = self.snapshot(window, cx);
18065        let cursor = self.selections.newest::<Point>(cx).head();
18066        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18067        let blame_entry = blame
18068            .update(cx, |blame, cx| {
18069                blame
18070                    .blame_for_rows(
18071                        &[RowInfo {
18072                            buffer_id: Some(buffer.remote_id()),
18073                            buffer_row: Some(point.row),
18074                            ..Default::default()
18075                        }],
18076                        cx,
18077                    )
18078                    .next()
18079            })
18080            .flatten()?;
18081        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18082        let repo = blame.read(cx).repository(cx)?;
18083        let workspace = self.workspace()?.downgrade();
18084        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18085        None
18086    }
18087
18088    pub fn git_blame_inline_enabled(&self) -> bool {
18089        self.git_blame_inline_enabled
18090    }
18091
18092    pub fn toggle_selection_menu(
18093        &mut self,
18094        _: &ToggleSelectionMenu,
18095        _: &mut Window,
18096        cx: &mut Context<Self>,
18097    ) {
18098        self.show_selection_menu = self
18099            .show_selection_menu
18100            .map(|show_selections_menu| !show_selections_menu)
18101            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18102
18103        cx.notify();
18104    }
18105
18106    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18107        self.show_selection_menu
18108            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18109    }
18110
18111    fn start_git_blame(
18112        &mut self,
18113        user_triggered: bool,
18114        window: &mut Window,
18115        cx: &mut Context<Self>,
18116    ) {
18117        if let Some(project) = self.project.as_ref() {
18118            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18119                return;
18120            };
18121
18122            if buffer.read(cx).file().is_none() {
18123                return;
18124            }
18125
18126            let focused = self.focus_handle(cx).contains_focused(window, cx);
18127
18128            let project = project.clone();
18129            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18130            self.blame_subscription =
18131                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18132            self.blame = Some(blame);
18133        }
18134    }
18135
18136    fn toggle_git_blame_inline_internal(
18137        &mut self,
18138        user_triggered: bool,
18139        window: &mut Window,
18140        cx: &mut Context<Self>,
18141    ) {
18142        if self.git_blame_inline_enabled {
18143            self.git_blame_inline_enabled = false;
18144            self.show_git_blame_inline = false;
18145            self.show_git_blame_inline_delay_task.take();
18146        } else {
18147            self.git_blame_inline_enabled = true;
18148            self.start_git_blame_inline(user_triggered, window, cx);
18149        }
18150
18151        cx.notify();
18152    }
18153
18154    fn start_git_blame_inline(
18155        &mut self,
18156        user_triggered: bool,
18157        window: &mut Window,
18158        cx: &mut Context<Self>,
18159    ) {
18160        self.start_git_blame(user_triggered, window, cx);
18161
18162        if ProjectSettings::get_global(cx)
18163            .git
18164            .inline_blame_delay()
18165            .is_some()
18166        {
18167            self.start_inline_blame_timer(window, cx);
18168        } else {
18169            self.show_git_blame_inline = true
18170        }
18171    }
18172
18173    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18174        self.blame.as_ref()
18175    }
18176
18177    pub fn show_git_blame_gutter(&self) -> bool {
18178        self.show_git_blame_gutter
18179    }
18180
18181    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18182        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18183    }
18184
18185    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18186        self.show_git_blame_inline
18187            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18188            && !self.newest_selection_head_on_empty_line(cx)
18189            && self.has_blame_entries(cx)
18190    }
18191
18192    fn has_blame_entries(&self, cx: &App) -> bool {
18193        self.blame()
18194            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18195    }
18196
18197    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18198        let cursor_anchor = self.selections.newest_anchor().head();
18199
18200        let snapshot = self.buffer.read(cx).snapshot(cx);
18201        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18202
18203        snapshot.line_len(buffer_row) == 0
18204    }
18205
18206    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18207        let buffer_and_selection = maybe!({
18208            let selection = self.selections.newest::<Point>(cx);
18209            let selection_range = selection.range();
18210
18211            let multi_buffer = self.buffer().read(cx);
18212            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18213            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18214
18215            let (buffer, range, _) = if selection.reversed {
18216                buffer_ranges.first()
18217            } else {
18218                buffer_ranges.last()
18219            }?;
18220
18221            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18222                ..text::ToPoint::to_point(&range.end, &buffer).row;
18223            Some((
18224                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18225                selection,
18226            ))
18227        });
18228
18229        let Some((buffer, selection)) = buffer_and_selection else {
18230            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18231        };
18232
18233        let Some(project) = self.project.as_ref() else {
18234            return Task::ready(Err(anyhow!("editor does not have project")));
18235        };
18236
18237        project.update(cx, |project, cx| {
18238            project.get_permalink_to_line(&buffer, selection, cx)
18239        })
18240    }
18241
18242    pub fn copy_permalink_to_line(
18243        &mut self,
18244        _: &CopyPermalinkToLine,
18245        window: &mut Window,
18246        cx: &mut Context<Self>,
18247    ) {
18248        let permalink_task = self.get_permalink_to_line(cx);
18249        let workspace = self.workspace();
18250
18251        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18252            Ok(permalink) => {
18253                cx.update(|_, cx| {
18254                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18255                })
18256                .ok();
18257            }
18258            Err(err) => {
18259                let message = format!("Failed to copy permalink: {err}");
18260
18261                anyhow::Result::<()>::Err(err).log_err();
18262
18263                if let Some(workspace) = workspace {
18264                    workspace
18265                        .update_in(cx, |workspace, _, cx| {
18266                            struct CopyPermalinkToLine;
18267
18268                            workspace.show_toast(
18269                                Toast::new(
18270                                    NotificationId::unique::<CopyPermalinkToLine>(),
18271                                    message,
18272                                ),
18273                                cx,
18274                            )
18275                        })
18276                        .ok();
18277                }
18278            }
18279        })
18280        .detach();
18281    }
18282
18283    pub fn copy_file_location(
18284        &mut self,
18285        _: &CopyFileLocation,
18286        _: &mut Window,
18287        cx: &mut Context<Self>,
18288    ) {
18289        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18290        if let Some(file) = self.target_file(cx) {
18291            if let Some(path) = file.path().to_str() {
18292                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18293            }
18294        }
18295    }
18296
18297    pub fn open_permalink_to_line(
18298        &mut self,
18299        _: &OpenPermalinkToLine,
18300        window: &mut Window,
18301        cx: &mut Context<Self>,
18302    ) {
18303        let permalink_task = self.get_permalink_to_line(cx);
18304        let workspace = self.workspace();
18305
18306        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18307            Ok(permalink) => {
18308                cx.update(|_, cx| {
18309                    cx.open_url(permalink.as_ref());
18310                })
18311                .ok();
18312            }
18313            Err(err) => {
18314                let message = format!("Failed to open permalink: {err}");
18315
18316                anyhow::Result::<()>::Err(err).log_err();
18317
18318                if let Some(workspace) = workspace {
18319                    workspace
18320                        .update(cx, |workspace, cx| {
18321                            struct OpenPermalinkToLine;
18322
18323                            workspace.show_toast(
18324                                Toast::new(
18325                                    NotificationId::unique::<OpenPermalinkToLine>(),
18326                                    message,
18327                                ),
18328                                cx,
18329                            )
18330                        })
18331                        .ok();
18332                }
18333            }
18334        })
18335        .detach();
18336    }
18337
18338    pub fn insert_uuid_v4(
18339        &mut self,
18340        _: &InsertUuidV4,
18341        window: &mut Window,
18342        cx: &mut Context<Self>,
18343    ) {
18344        self.insert_uuid(UuidVersion::V4, window, cx);
18345    }
18346
18347    pub fn insert_uuid_v7(
18348        &mut self,
18349        _: &InsertUuidV7,
18350        window: &mut Window,
18351        cx: &mut Context<Self>,
18352    ) {
18353        self.insert_uuid(UuidVersion::V7, window, cx);
18354    }
18355
18356    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18357        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18358        self.transact(window, cx, |this, window, cx| {
18359            let edits = this
18360                .selections
18361                .all::<Point>(cx)
18362                .into_iter()
18363                .map(|selection| {
18364                    let uuid = match version {
18365                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18366                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18367                    };
18368
18369                    (selection.range(), uuid.to_string())
18370                });
18371            this.edit(edits, cx);
18372            this.refresh_inline_completion(true, false, window, cx);
18373        });
18374    }
18375
18376    pub fn open_selections_in_multibuffer(
18377        &mut self,
18378        _: &OpenSelectionsInMultibuffer,
18379        window: &mut Window,
18380        cx: &mut Context<Self>,
18381    ) {
18382        let multibuffer = self.buffer.read(cx);
18383
18384        let Some(buffer) = multibuffer.as_singleton() else {
18385            return;
18386        };
18387
18388        let Some(workspace) = self.workspace() else {
18389            return;
18390        };
18391
18392        let title = multibuffer.title(cx).to_string();
18393
18394        let locations = self
18395            .selections
18396            .all_anchors(cx)
18397            .into_iter()
18398            .map(|selection| Location {
18399                buffer: buffer.clone(),
18400                range: selection.start.text_anchor..selection.end.text_anchor,
18401            })
18402            .collect::<Vec<_>>();
18403
18404        cx.spawn_in(window, async move |_, cx| {
18405            workspace.update_in(cx, |workspace, window, cx| {
18406                Self::open_locations_in_multibuffer(
18407                    workspace,
18408                    locations,
18409                    format!("Selections for '{title}'"),
18410                    false,
18411                    MultibufferSelectionMode::All,
18412                    window,
18413                    cx,
18414                );
18415            })
18416        })
18417        .detach();
18418    }
18419
18420    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18421    /// last highlight added will be used.
18422    ///
18423    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18424    pub fn highlight_rows<T: 'static>(
18425        &mut self,
18426        range: Range<Anchor>,
18427        color: Hsla,
18428        options: RowHighlightOptions,
18429        cx: &mut Context<Self>,
18430    ) {
18431        let snapshot = self.buffer().read(cx).snapshot(cx);
18432        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18433        let ix = row_highlights.binary_search_by(|highlight| {
18434            Ordering::Equal
18435                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18436                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18437        });
18438
18439        if let Err(mut ix) = ix {
18440            let index = post_inc(&mut self.highlight_order);
18441
18442            // If this range intersects with the preceding highlight, then merge it with
18443            // the preceding highlight. Otherwise insert a new highlight.
18444            let mut merged = false;
18445            if ix > 0 {
18446                let prev_highlight = &mut row_highlights[ix - 1];
18447                if prev_highlight
18448                    .range
18449                    .end
18450                    .cmp(&range.start, &snapshot)
18451                    .is_ge()
18452                {
18453                    ix -= 1;
18454                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18455                        prev_highlight.range.end = range.end;
18456                    }
18457                    merged = true;
18458                    prev_highlight.index = index;
18459                    prev_highlight.color = color;
18460                    prev_highlight.options = options;
18461                }
18462            }
18463
18464            if !merged {
18465                row_highlights.insert(
18466                    ix,
18467                    RowHighlight {
18468                        range: range.clone(),
18469                        index,
18470                        color,
18471                        options,
18472                        type_id: TypeId::of::<T>(),
18473                    },
18474                );
18475            }
18476
18477            // If any of the following highlights intersect with this one, merge them.
18478            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18479                let highlight = &row_highlights[ix];
18480                if next_highlight
18481                    .range
18482                    .start
18483                    .cmp(&highlight.range.end, &snapshot)
18484                    .is_le()
18485                {
18486                    if next_highlight
18487                        .range
18488                        .end
18489                        .cmp(&highlight.range.end, &snapshot)
18490                        .is_gt()
18491                    {
18492                        row_highlights[ix].range.end = next_highlight.range.end;
18493                    }
18494                    row_highlights.remove(ix + 1);
18495                } else {
18496                    break;
18497                }
18498            }
18499        }
18500    }
18501
18502    /// Remove any highlighted row ranges of the given type that intersect the
18503    /// given ranges.
18504    pub fn remove_highlighted_rows<T: 'static>(
18505        &mut self,
18506        ranges_to_remove: Vec<Range<Anchor>>,
18507        cx: &mut Context<Self>,
18508    ) {
18509        let snapshot = self.buffer().read(cx).snapshot(cx);
18510        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18511        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18512        row_highlights.retain(|highlight| {
18513            while let Some(range_to_remove) = ranges_to_remove.peek() {
18514                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18515                    Ordering::Less | Ordering::Equal => {
18516                        ranges_to_remove.next();
18517                    }
18518                    Ordering::Greater => {
18519                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18520                            Ordering::Less | Ordering::Equal => {
18521                                return false;
18522                            }
18523                            Ordering::Greater => break,
18524                        }
18525                    }
18526                }
18527            }
18528
18529            true
18530        })
18531    }
18532
18533    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18534    pub fn clear_row_highlights<T: 'static>(&mut self) {
18535        self.highlighted_rows.remove(&TypeId::of::<T>());
18536    }
18537
18538    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18539    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18540        self.highlighted_rows
18541            .get(&TypeId::of::<T>())
18542            .map_or(&[] as &[_], |vec| vec.as_slice())
18543            .iter()
18544            .map(|highlight| (highlight.range.clone(), highlight.color))
18545    }
18546
18547    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18548    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18549    /// Allows to ignore certain kinds of highlights.
18550    pub fn highlighted_display_rows(
18551        &self,
18552        window: &mut Window,
18553        cx: &mut App,
18554    ) -> BTreeMap<DisplayRow, LineHighlight> {
18555        let snapshot = self.snapshot(window, cx);
18556        let mut used_highlight_orders = HashMap::default();
18557        self.highlighted_rows
18558            .iter()
18559            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18560            .fold(
18561                BTreeMap::<DisplayRow, LineHighlight>::new(),
18562                |mut unique_rows, highlight| {
18563                    let start = highlight.range.start.to_display_point(&snapshot);
18564                    let end = highlight.range.end.to_display_point(&snapshot);
18565                    let start_row = start.row().0;
18566                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18567                        && end.column() == 0
18568                    {
18569                        end.row().0.saturating_sub(1)
18570                    } else {
18571                        end.row().0
18572                    };
18573                    for row in start_row..=end_row {
18574                        let used_index =
18575                            used_highlight_orders.entry(row).or_insert(highlight.index);
18576                        if highlight.index >= *used_index {
18577                            *used_index = highlight.index;
18578                            unique_rows.insert(
18579                                DisplayRow(row),
18580                                LineHighlight {
18581                                    include_gutter: highlight.options.include_gutter,
18582                                    border: None,
18583                                    background: highlight.color.into(),
18584                                    type_id: Some(highlight.type_id),
18585                                },
18586                            );
18587                        }
18588                    }
18589                    unique_rows
18590                },
18591            )
18592    }
18593
18594    pub fn highlighted_display_row_for_autoscroll(
18595        &self,
18596        snapshot: &DisplaySnapshot,
18597    ) -> Option<DisplayRow> {
18598        self.highlighted_rows
18599            .values()
18600            .flat_map(|highlighted_rows| highlighted_rows.iter())
18601            .filter_map(|highlight| {
18602                if highlight.options.autoscroll {
18603                    Some(highlight.range.start.to_display_point(snapshot).row())
18604                } else {
18605                    None
18606                }
18607            })
18608            .min()
18609    }
18610
18611    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18612        self.highlight_background::<SearchWithinRange>(
18613            ranges,
18614            |colors| colors.colors().editor_document_highlight_read_background,
18615            cx,
18616        )
18617    }
18618
18619    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18620        self.breadcrumb_header = Some(new_header);
18621    }
18622
18623    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18624        self.clear_background_highlights::<SearchWithinRange>(cx);
18625    }
18626
18627    pub fn highlight_background<T: 'static>(
18628        &mut self,
18629        ranges: &[Range<Anchor>],
18630        color_fetcher: fn(&Theme) -> Hsla,
18631        cx: &mut Context<Self>,
18632    ) {
18633        self.background_highlights.insert(
18634            HighlightKey::Type(TypeId::of::<T>()),
18635            (color_fetcher, Arc::from(ranges)),
18636        );
18637        self.scrollbar_marker_state.dirty = true;
18638        cx.notify();
18639    }
18640
18641    pub fn highlight_background_key<T: 'static>(
18642        &mut self,
18643        key: usize,
18644        ranges: &[Range<Anchor>],
18645        color_fetcher: fn(&Theme) -> Hsla,
18646        cx: &mut Context<Self>,
18647    ) {
18648        self.background_highlights.insert(
18649            HighlightKey::TypePlus(TypeId::of::<T>(), key),
18650            (color_fetcher, Arc::from(ranges)),
18651        );
18652        self.scrollbar_marker_state.dirty = true;
18653        cx.notify();
18654    }
18655
18656    pub fn clear_background_highlights<T: 'static>(
18657        &mut self,
18658        cx: &mut Context<Self>,
18659    ) -> Option<BackgroundHighlight> {
18660        let text_highlights = self
18661            .background_highlights
18662            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
18663        if !text_highlights.1.is_empty() {
18664            self.scrollbar_marker_state.dirty = true;
18665            cx.notify();
18666        }
18667        Some(text_highlights)
18668    }
18669
18670    pub fn highlight_gutter<T: 'static>(
18671        &mut self,
18672        ranges: impl Into<Vec<Range<Anchor>>>,
18673        color_fetcher: fn(&App) -> Hsla,
18674        cx: &mut Context<Self>,
18675    ) {
18676        self.gutter_highlights
18677            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18678        cx.notify();
18679    }
18680
18681    pub fn clear_gutter_highlights<T: 'static>(
18682        &mut self,
18683        cx: &mut Context<Self>,
18684    ) -> Option<GutterHighlight> {
18685        cx.notify();
18686        self.gutter_highlights.remove(&TypeId::of::<T>())
18687    }
18688
18689    pub fn insert_gutter_highlight<T: 'static>(
18690        &mut self,
18691        range: Range<Anchor>,
18692        color_fetcher: fn(&App) -> Hsla,
18693        cx: &mut Context<Self>,
18694    ) {
18695        let snapshot = self.buffer().read(cx).snapshot(cx);
18696        let mut highlights = self
18697            .gutter_highlights
18698            .remove(&TypeId::of::<T>())
18699            .map(|(_, highlights)| highlights)
18700            .unwrap_or_default();
18701        let ix = highlights.binary_search_by(|highlight| {
18702            Ordering::Equal
18703                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18704                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18705        });
18706        if let Err(ix) = ix {
18707            highlights.insert(ix, range);
18708        }
18709        self.gutter_highlights
18710            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18711    }
18712
18713    pub fn remove_gutter_highlights<T: 'static>(
18714        &mut self,
18715        ranges_to_remove: Vec<Range<Anchor>>,
18716        cx: &mut Context<Self>,
18717    ) {
18718        let snapshot = self.buffer().read(cx).snapshot(cx);
18719        let Some((color_fetcher, mut gutter_highlights)) =
18720            self.gutter_highlights.remove(&TypeId::of::<T>())
18721        else {
18722            return;
18723        };
18724        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18725        gutter_highlights.retain(|highlight| {
18726            while let Some(range_to_remove) = ranges_to_remove.peek() {
18727                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18728                    Ordering::Less | Ordering::Equal => {
18729                        ranges_to_remove.next();
18730                    }
18731                    Ordering::Greater => {
18732                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18733                            Ordering::Less | Ordering::Equal => {
18734                                return false;
18735                            }
18736                            Ordering::Greater => break,
18737                        }
18738                    }
18739                }
18740            }
18741
18742            true
18743        });
18744        self.gutter_highlights
18745            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18746    }
18747
18748    #[cfg(feature = "test-support")]
18749    pub fn all_text_highlights(
18750        &self,
18751        window: &mut Window,
18752        cx: &mut Context<Self>,
18753    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
18754        let snapshot = self.snapshot(window, cx);
18755        self.display_map.update(cx, |display_map, _| {
18756            display_map
18757                .all_text_highlights()
18758                .map(|highlight| {
18759                    let (style, ranges) = highlight.as_ref();
18760                    (
18761                        *style,
18762                        ranges
18763                            .iter()
18764                            .map(|range| range.clone().to_display_points(&snapshot))
18765                            .collect(),
18766                    )
18767                })
18768                .collect()
18769        })
18770    }
18771
18772    #[cfg(feature = "test-support")]
18773    pub fn all_text_background_highlights(
18774        &self,
18775        window: &mut Window,
18776        cx: &mut Context<Self>,
18777    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18778        let snapshot = self.snapshot(window, cx);
18779        let buffer = &snapshot.buffer_snapshot;
18780        let start = buffer.anchor_before(0);
18781        let end = buffer.anchor_after(buffer.len());
18782        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
18783    }
18784
18785    #[cfg(feature = "test-support")]
18786    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18787        let snapshot = self.buffer().read(cx).snapshot(cx);
18788
18789        let highlights = self
18790            .background_highlights
18791            .get(&HighlightKey::Type(TypeId::of::<
18792                items::BufferSearchHighlights,
18793            >()));
18794
18795        if let Some((_color, ranges)) = highlights {
18796            ranges
18797                .iter()
18798                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18799                .collect_vec()
18800        } else {
18801            vec![]
18802        }
18803    }
18804
18805    fn document_highlights_for_position<'a>(
18806        &'a self,
18807        position: Anchor,
18808        buffer: &'a MultiBufferSnapshot,
18809    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18810        let read_highlights = self
18811            .background_highlights
18812            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
18813            .map(|h| &h.1);
18814        let write_highlights = self
18815            .background_highlights
18816            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
18817            .map(|h| &h.1);
18818        let left_position = position.bias_left(buffer);
18819        let right_position = position.bias_right(buffer);
18820        read_highlights
18821            .into_iter()
18822            .chain(write_highlights)
18823            .flat_map(move |ranges| {
18824                let start_ix = match ranges.binary_search_by(|probe| {
18825                    let cmp = probe.end.cmp(&left_position, buffer);
18826                    if cmp.is_ge() {
18827                        Ordering::Greater
18828                    } else {
18829                        Ordering::Less
18830                    }
18831                }) {
18832                    Ok(i) | Err(i) => i,
18833                };
18834
18835                ranges[start_ix..]
18836                    .iter()
18837                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18838            })
18839    }
18840
18841    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18842        self.background_highlights
18843            .get(&HighlightKey::Type(TypeId::of::<T>()))
18844            .map_or(false, |(_, highlights)| !highlights.is_empty())
18845    }
18846
18847    pub fn background_highlights_in_range(
18848        &self,
18849        search_range: Range<Anchor>,
18850        display_snapshot: &DisplaySnapshot,
18851        theme: &Theme,
18852    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18853        let mut results = Vec::new();
18854        for (color_fetcher, ranges) in self.background_highlights.values() {
18855            let color = color_fetcher(theme);
18856            let start_ix = match ranges.binary_search_by(|probe| {
18857                let cmp = probe
18858                    .end
18859                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18860                if cmp.is_gt() {
18861                    Ordering::Greater
18862                } else {
18863                    Ordering::Less
18864                }
18865            }) {
18866                Ok(i) | Err(i) => i,
18867            };
18868            for range in &ranges[start_ix..] {
18869                if range
18870                    .start
18871                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18872                    .is_ge()
18873                {
18874                    break;
18875                }
18876
18877                let start = range.start.to_display_point(display_snapshot);
18878                let end = range.end.to_display_point(display_snapshot);
18879                results.push((start..end, color))
18880            }
18881        }
18882        results
18883    }
18884
18885    pub fn background_highlight_row_ranges<T: 'static>(
18886        &self,
18887        search_range: Range<Anchor>,
18888        display_snapshot: &DisplaySnapshot,
18889        count: usize,
18890    ) -> Vec<RangeInclusive<DisplayPoint>> {
18891        let mut results = Vec::new();
18892        let Some((_, ranges)) = self
18893            .background_highlights
18894            .get(&HighlightKey::Type(TypeId::of::<T>()))
18895        else {
18896            return vec![];
18897        };
18898
18899        let start_ix = match ranges.binary_search_by(|probe| {
18900            let cmp = probe
18901                .end
18902                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18903            if cmp.is_gt() {
18904                Ordering::Greater
18905            } else {
18906                Ordering::Less
18907            }
18908        }) {
18909            Ok(i) | Err(i) => i,
18910        };
18911        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18912            if let (Some(start_display), Some(end_display)) = (start, end) {
18913                results.push(
18914                    start_display.to_display_point(display_snapshot)
18915                        ..=end_display.to_display_point(display_snapshot),
18916                );
18917            }
18918        };
18919        let mut start_row: Option<Point> = None;
18920        let mut end_row: Option<Point> = None;
18921        if ranges.len() > count {
18922            return Vec::new();
18923        }
18924        for range in &ranges[start_ix..] {
18925            if range
18926                .start
18927                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18928                .is_ge()
18929            {
18930                break;
18931            }
18932            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18933            if let Some(current_row) = &end_row {
18934                if end.row == current_row.row {
18935                    continue;
18936                }
18937            }
18938            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18939            if start_row.is_none() {
18940                assert_eq!(end_row, None);
18941                start_row = Some(start);
18942                end_row = Some(end);
18943                continue;
18944            }
18945            if let Some(current_end) = end_row.as_mut() {
18946                if start.row > current_end.row + 1 {
18947                    push_region(start_row, end_row);
18948                    start_row = Some(start);
18949                    end_row = Some(end);
18950                } else {
18951                    // Merge two hunks.
18952                    *current_end = end;
18953                }
18954            } else {
18955                unreachable!();
18956            }
18957        }
18958        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18959        push_region(start_row, end_row);
18960        results
18961    }
18962
18963    pub fn gutter_highlights_in_range(
18964        &self,
18965        search_range: Range<Anchor>,
18966        display_snapshot: &DisplaySnapshot,
18967        cx: &App,
18968    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18969        let mut results = Vec::new();
18970        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18971            let color = color_fetcher(cx);
18972            let start_ix = match ranges.binary_search_by(|probe| {
18973                let cmp = probe
18974                    .end
18975                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18976                if cmp.is_gt() {
18977                    Ordering::Greater
18978                } else {
18979                    Ordering::Less
18980                }
18981            }) {
18982                Ok(i) | Err(i) => i,
18983            };
18984            for range in &ranges[start_ix..] {
18985                if range
18986                    .start
18987                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18988                    .is_ge()
18989                {
18990                    break;
18991                }
18992
18993                let start = range.start.to_display_point(display_snapshot);
18994                let end = range.end.to_display_point(display_snapshot);
18995                results.push((start..end, color))
18996            }
18997        }
18998        results
18999    }
19000
19001    /// Get the text ranges corresponding to the redaction query
19002    pub fn redacted_ranges(
19003        &self,
19004        search_range: Range<Anchor>,
19005        display_snapshot: &DisplaySnapshot,
19006        cx: &App,
19007    ) -> Vec<Range<DisplayPoint>> {
19008        display_snapshot
19009            .buffer_snapshot
19010            .redacted_ranges(search_range, |file| {
19011                if let Some(file) = file {
19012                    file.is_private()
19013                        && EditorSettings::get(
19014                            Some(SettingsLocation {
19015                                worktree_id: file.worktree_id(cx),
19016                                path: file.path().as_ref(),
19017                            }),
19018                            cx,
19019                        )
19020                        .redact_private_values
19021                } else {
19022                    false
19023                }
19024            })
19025            .map(|range| {
19026                range.start.to_display_point(display_snapshot)
19027                    ..range.end.to_display_point(display_snapshot)
19028            })
19029            .collect()
19030    }
19031
19032    pub fn highlight_text_key<T: 'static>(
19033        &mut self,
19034        key: usize,
19035        ranges: Vec<Range<Anchor>>,
19036        style: HighlightStyle,
19037        cx: &mut Context<Self>,
19038    ) {
19039        self.display_map.update(cx, |map, _| {
19040            map.highlight_text(
19041                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19042                ranges,
19043                style,
19044            );
19045        });
19046        cx.notify();
19047    }
19048
19049    pub fn highlight_text<T: 'static>(
19050        &mut self,
19051        ranges: Vec<Range<Anchor>>,
19052        style: HighlightStyle,
19053        cx: &mut Context<Self>,
19054    ) {
19055        self.display_map.update(cx, |map, _| {
19056            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19057        });
19058        cx.notify();
19059    }
19060
19061    pub(crate) fn highlight_inlays<T: 'static>(
19062        &mut self,
19063        highlights: Vec<InlayHighlight>,
19064        style: HighlightStyle,
19065        cx: &mut Context<Self>,
19066    ) {
19067        self.display_map.update(cx, |map, _| {
19068            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19069        });
19070        cx.notify();
19071    }
19072
19073    pub fn text_highlights<'a, T: 'static>(
19074        &'a self,
19075        cx: &'a App,
19076    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19077        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19078    }
19079
19080    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19081        let cleared = self
19082            .display_map
19083            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19084        if cleared {
19085            cx.notify();
19086        }
19087    }
19088
19089    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19090        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19091            && self.focus_handle.is_focused(window)
19092    }
19093
19094    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19095        self.show_cursor_when_unfocused = is_enabled;
19096        cx.notify();
19097    }
19098
19099    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19100        cx.notify();
19101    }
19102
19103    fn on_debug_session_event(
19104        &mut self,
19105        _session: Entity<Session>,
19106        event: &SessionEvent,
19107        cx: &mut Context<Self>,
19108    ) {
19109        match event {
19110            SessionEvent::InvalidateInlineValue => {
19111                self.refresh_inline_values(cx);
19112            }
19113            _ => {}
19114        }
19115    }
19116
19117    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19118        let Some(project) = self.project.clone() else {
19119            return;
19120        };
19121
19122        if !self.inline_value_cache.enabled {
19123            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19124            self.splice_inlays(&inlays, Vec::new(), cx);
19125            return;
19126        }
19127
19128        let current_execution_position = self
19129            .highlighted_rows
19130            .get(&TypeId::of::<ActiveDebugLine>())
19131            .and_then(|lines| lines.last().map(|line| line.range.start));
19132
19133        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19134            let inline_values = editor
19135                .update(cx, |editor, cx| {
19136                    let Some(current_execution_position) = current_execution_position else {
19137                        return Some(Task::ready(Ok(Vec::new())));
19138                    };
19139
19140                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19141                        let snapshot = buffer.snapshot(cx);
19142
19143                        let excerpt = snapshot.excerpt_containing(
19144                            current_execution_position..current_execution_position,
19145                        )?;
19146
19147                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19148                    })?;
19149
19150                    let range =
19151                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19152
19153                    project.inline_values(buffer, range, cx)
19154                })
19155                .ok()
19156                .flatten()?
19157                .await
19158                .context("refreshing debugger inlays")
19159                .log_err()?;
19160
19161            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19162
19163            for (buffer_id, inline_value) in inline_values
19164                .into_iter()
19165                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19166            {
19167                buffer_inline_values
19168                    .entry(buffer_id)
19169                    .or_default()
19170                    .push(inline_value);
19171            }
19172
19173            editor
19174                .update(cx, |editor, cx| {
19175                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19176                    let mut new_inlays = Vec::default();
19177
19178                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19179                        let buffer_id = buffer_snapshot.remote_id();
19180                        buffer_inline_values
19181                            .get(&buffer_id)
19182                            .into_iter()
19183                            .flatten()
19184                            .for_each(|hint| {
19185                                let inlay = Inlay::debugger(
19186                                    post_inc(&mut editor.next_inlay_id),
19187                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19188                                    hint.text(),
19189                                );
19190
19191                                new_inlays.push(inlay);
19192                            });
19193                    }
19194
19195                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19196                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19197
19198                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19199                })
19200                .ok()?;
19201            Some(())
19202        });
19203    }
19204
19205    fn on_buffer_event(
19206        &mut self,
19207        multibuffer: &Entity<MultiBuffer>,
19208        event: &multi_buffer::Event,
19209        window: &mut Window,
19210        cx: &mut Context<Self>,
19211    ) {
19212        match event {
19213            multi_buffer::Event::Edited {
19214                singleton_buffer_edited,
19215                edited_buffer,
19216            } => {
19217                self.scrollbar_marker_state.dirty = true;
19218                self.active_indent_guides_state.dirty = true;
19219                self.refresh_active_diagnostics(cx);
19220                self.refresh_code_actions(window, cx);
19221                self.refresh_selected_text_highlights(true, window, cx);
19222                refresh_matching_bracket_highlights(self, window, cx);
19223                if self.has_active_inline_completion() {
19224                    self.update_visible_inline_completion(window, cx);
19225                }
19226                if let Some(project) = self.project.as_ref() {
19227                    if let Some(edited_buffer) = edited_buffer {
19228                        project.update(cx, |project, cx| {
19229                            self.registered_buffers
19230                                .entry(edited_buffer.read(cx).remote_id())
19231                                .or_insert_with(|| {
19232                                    project
19233                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19234                                });
19235                        });
19236                    }
19237                }
19238                cx.emit(EditorEvent::BufferEdited);
19239                cx.emit(SearchEvent::MatchesInvalidated);
19240
19241                if let Some(buffer) = edited_buffer {
19242                    self.update_lsp_data(None, Some(buffer.read(cx).remote_id()), window, cx);
19243                }
19244
19245                if *singleton_buffer_edited {
19246                    if let Some(buffer) = edited_buffer {
19247                        if buffer.read(cx).file().is_none() {
19248                            cx.emit(EditorEvent::TitleChanged);
19249                        }
19250                    }
19251                    if let Some(project) = &self.project {
19252                        #[allow(clippy::mutable_key_type)]
19253                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19254                            multibuffer
19255                                .all_buffers()
19256                                .into_iter()
19257                                .filter_map(|buffer| {
19258                                    buffer.update(cx, |buffer, cx| {
19259                                        let language = buffer.language()?;
19260                                        let should_discard = project.update(cx, |project, cx| {
19261                                            project.is_local()
19262                                                && !project.has_language_servers_for(buffer, cx)
19263                                        });
19264                                        should_discard.not().then_some(language.clone())
19265                                    })
19266                                })
19267                                .collect::<HashSet<_>>()
19268                        });
19269                        if !languages_affected.is_empty() {
19270                            self.refresh_inlay_hints(
19271                                InlayHintRefreshReason::BufferEdited(languages_affected),
19272                                cx,
19273                            );
19274                        }
19275                    }
19276                }
19277
19278                let Some(project) = &self.project else { return };
19279                let (telemetry, is_via_ssh) = {
19280                    let project = project.read(cx);
19281                    let telemetry = project.client().telemetry().clone();
19282                    let is_via_ssh = project.is_via_ssh();
19283                    (telemetry, is_via_ssh)
19284                };
19285                refresh_linked_ranges(self, window, cx);
19286                telemetry.log_edit_event("editor", is_via_ssh);
19287            }
19288            multi_buffer::Event::ExcerptsAdded {
19289                buffer,
19290                predecessor,
19291                excerpts,
19292            } => {
19293                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19294                let buffer_id = buffer.read(cx).remote_id();
19295                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19296                    if let Some(project) = &self.project {
19297                        update_uncommitted_diff_for_buffer(
19298                            cx.entity(),
19299                            project,
19300                            [buffer.clone()],
19301                            self.buffer.clone(),
19302                            cx,
19303                        )
19304                        .detach();
19305                    }
19306                }
19307                self.update_lsp_data(None, Some(buffer_id), window, cx);
19308                cx.emit(EditorEvent::ExcerptsAdded {
19309                    buffer: buffer.clone(),
19310                    predecessor: *predecessor,
19311                    excerpts: excerpts.clone(),
19312                });
19313                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19314            }
19315            multi_buffer::Event::ExcerptsRemoved {
19316                ids,
19317                removed_buffer_ids,
19318            } => {
19319                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19320                let buffer = self.buffer.read(cx);
19321                self.registered_buffers
19322                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19323                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19324                cx.emit(EditorEvent::ExcerptsRemoved {
19325                    ids: ids.clone(),
19326                    removed_buffer_ids: removed_buffer_ids.clone(),
19327                });
19328            }
19329            multi_buffer::Event::ExcerptsEdited {
19330                excerpt_ids,
19331                buffer_ids,
19332            } => {
19333                self.display_map.update(cx, |map, cx| {
19334                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19335                });
19336                cx.emit(EditorEvent::ExcerptsEdited {
19337                    ids: excerpt_ids.clone(),
19338                });
19339            }
19340            multi_buffer::Event::ExcerptsExpanded { ids } => {
19341                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19342                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19343            }
19344            multi_buffer::Event::Reparsed(buffer_id) => {
19345                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19346                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19347
19348                cx.emit(EditorEvent::Reparsed(*buffer_id));
19349            }
19350            multi_buffer::Event::DiffHunksToggled => {
19351                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19352            }
19353            multi_buffer::Event::LanguageChanged(buffer_id) => {
19354                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19355                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19356                cx.emit(EditorEvent::Reparsed(*buffer_id));
19357                cx.notify();
19358            }
19359            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19360            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19361            multi_buffer::Event::FileHandleChanged
19362            | multi_buffer::Event::Reloaded
19363            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19364            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19365            multi_buffer::Event::DiagnosticsUpdated => {
19366                self.update_diagnostics_state(window, cx);
19367            }
19368            _ => {}
19369        };
19370    }
19371
19372    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19373        self.refresh_active_diagnostics(cx);
19374        self.refresh_inline_diagnostics(true, window, cx);
19375        self.scrollbar_marker_state.dirty = true;
19376        cx.notify();
19377    }
19378
19379    pub fn start_temporary_diff_override(&mut self) {
19380        self.load_diff_task.take();
19381        self.temporary_diff_override = true;
19382    }
19383
19384    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19385        self.temporary_diff_override = false;
19386        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19387        self.buffer.update(cx, |buffer, cx| {
19388            buffer.set_all_diff_hunks_collapsed(cx);
19389        });
19390
19391        if let Some(project) = self.project.clone() {
19392            self.load_diff_task = Some(
19393                update_uncommitted_diff_for_buffer(
19394                    cx.entity(),
19395                    &project,
19396                    self.buffer.read(cx).all_buffers(),
19397                    self.buffer.clone(),
19398                    cx,
19399                )
19400                .shared(),
19401            );
19402        }
19403    }
19404
19405    fn on_display_map_changed(
19406        &mut self,
19407        _: Entity<DisplayMap>,
19408        _: &mut Window,
19409        cx: &mut Context<Self>,
19410    ) {
19411        cx.notify();
19412    }
19413
19414    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19415        let new_severity = if self.diagnostics_enabled() {
19416            EditorSettings::get_global(cx)
19417                .diagnostics_max_severity
19418                .unwrap_or(DiagnosticSeverity::Hint)
19419        } else {
19420            DiagnosticSeverity::Off
19421        };
19422        self.set_max_diagnostics_severity(new_severity, cx);
19423        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19424        self.update_edit_prediction_settings(cx);
19425        self.refresh_inline_completion(true, false, window, cx);
19426        self.refresh_inlay_hints(
19427            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19428                self.selections.newest_anchor().head(),
19429                &self.buffer.read(cx).snapshot(cx),
19430                cx,
19431            )),
19432            cx,
19433        );
19434
19435        let old_cursor_shape = self.cursor_shape;
19436
19437        {
19438            let editor_settings = EditorSettings::get_global(cx);
19439            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19440            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19441            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19442            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19443            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19444        }
19445
19446        if old_cursor_shape != self.cursor_shape {
19447            cx.emit(EditorEvent::CursorShapeChanged);
19448        }
19449
19450        let project_settings = ProjectSettings::get_global(cx);
19451        self.serialize_dirty_buffers =
19452            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19453
19454        if self.mode.is_full() {
19455            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19456            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19457            if self.show_inline_diagnostics != show_inline_diagnostics {
19458                self.show_inline_diagnostics = show_inline_diagnostics;
19459                self.refresh_inline_diagnostics(false, window, cx);
19460            }
19461
19462            if self.git_blame_inline_enabled != inline_blame_enabled {
19463                self.toggle_git_blame_inline_internal(false, window, cx);
19464            }
19465
19466            let minimap_settings = EditorSettings::get_global(cx).minimap;
19467            if self.minimap_visibility != MinimapVisibility::Disabled {
19468                if self.minimap_visibility.settings_visibility()
19469                    != minimap_settings.minimap_enabled()
19470                {
19471                    self.set_minimap_visibility(
19472                        MinimapVisibility::for_mode(self.mode(), cx),
19473                        window,
19474                        cx,
19475                    );
19476                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19477                    minimap_entity.update(cx, |minimap_editor, cx| {
19478                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19479                    })
19480                }
19481            }
19482        }
19483
19484        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19485            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19486        }) {
19487            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19488                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19489            }
19490            self.refresh_colors(None, None, window, cx);
19491        }
19492
19493        cx.notify();
19494    }
19495
19496    pub fn set_searchable(&mut self, searchable: bool) {
19497        self.searchable = searchable;
19498    }
19499
19500    pub fn searchable(&self) -> bool {
19501        self.searchable
19502    }
19503
19504    fn open_proposed_changes_editor(
19505        &mut self,
19506        _: &OpenProposedChangesEditor,
19507        window: &mut Window,
19508        cx: &mut Context<Self>,
19509    ) {
19510        let Some(workspace) = self.workspace() else {
19511            cx.propagate();
19512            return;
19513        };
19514
19515        let selections = self.selections.all::<usize>(cx);
19516        let multi_buffer = self.buffer.read(cx);
19517        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19518        let mut new_selections_by_buffer = HashMap::default();
19519        for selection in selections {
19520            for (buffer, range, _) in
19521                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19522            {
19523                let mut range = range.to_point(buffer);
19524                range.start.column = 0;
19525                range.end.column = buffer.line_len(range.end.row);
19526                new_selections_by_buffer
19527                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19528                    .or_insert(Vec::new())
19529                    .push(range)
19530            }
19531        }
19532
19533        let proposed_changes_buffers = new_selections_by_buffer
19534            .into_iter()
19535            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19536            .collect::<Vec<_>>();
19537        let proposed_changes_editor = cx.new(|cx| {
19538            ProposedChangesEditor::new(
19539                "Proposed changes",
19540                proposed_changes_buffers,
19541                self.project.clone(),
19542                window,
19543                cx,
19544            )
19545        });
19546
19547        window.defer(cx, move |window, cx| {
19548            workspace.update(cx, |workspace, cx| {
19549                workspace.active_pane().update(cx, |pane, cx| {
19550                    pane.add_item(
19551                        Box::new(proposed_changes_editor),
19552                        true,
19553                        true,
19554                        None,
19555                        window,
19556                        cx,
19557                    );
19558                });
19559            });
19560        });
19561    }
19562
19563    pub fn open_excerpts_in_split(
19564        &mut self,
19565        _: &OpenExcerptsSplit,
19566        window: &mut Window,
19567        cx: &mut Context<Self>,
19568    ) {
19569        self.open_excerpts_common(None, true, window, cx)
19570    }
19571
19572    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19573        self.open_excerpts_common(None, false, window, cx)
19574    }
19575
19576    fn open_excerpts_common(
19577        &mut self,
19578        jump_data: Option<JumpData>,
19579        split: bool,
19580        window: &mut Window,
19581        cx: &mut Context<Self>,
19582    ) {
19583        let Some(workspace) = self.workspace() else {
19584            cx.propagate();
19585            return;
19586        };
19587
19588        if self.buffer.read(cx).is_singleton() {
19589            cx.propagate();
19590            return;
19591        }
19592
19593        let mut new_selections_by_buffer = HashMap::default();
19594        match &jump_data {
19595            Some(JumpData::MultiBufferPoint {
19596                excerpt_id,
19597                position,
19598                anchor,
19599                line_offset_from_top,
19600            }) => {
19601                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19602                if let Some(buffer) = multi_buffer_snapshot
19603                    .buffer_id_for_excerpt(*excerpt_id)
19604                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19605                {
19606                    let buffer_snapshot = buffer.read(cx).snapshot();
19607                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19608                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19609                    } else {
19610                        buffer_snapshot.clip_point(*position, Bias::Left)
19611                    };
19612                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19613                    new_selections_by_buffer.insert(
19614                        buffer,
19615                        (
19616                            vec![jump_to_offset..jump_to_offset],
19617                            Some(*line_offset_from_top),
19618                        ),
19619                    );
19620                }
19621            }
19622            Some(JumpData::MultiBufferRow {
19623                row,
19624                line_offset_from_top,
19625            }) => {
19626                let point = MultiBufferPoint::new(row.0, 0);
19627                if let Some((buffer, buffer_point, _)) =
19628                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19629                {
19630                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19631                    new_selections_by_buffer
19632                        .entry(buffer)
19633                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19634                        .0
19635                        .push(buffer_offset..buffer_offset)
19636                }
19637            }
19638            None => {
19639                let selections = self.selections.all::<usize>(cx);
19640                let multi_buffer = self.buffer.read(cx);
19641                for selection in selections {
19642                    for (snapshot, range, _, anchor) in multi_buffer
19643                        .snapshot(cx)
19644                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19645                    {
19646                        if let Some(anchor) = anchor {
19647                            // selection is in a deleted hunk
19648                            let Some(buffer_id) = anchor.buffer_id else {
19649                                continue;
19650                            };
19651                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19652                                continue;
19653                            };
19654                            let offset = text::ToOffset::to_offset(
19655                                &anchor.text_anchor,
19656                                &buffer_handle.read(cx).snapshot(),
19657                            );
19658                            let range = offset..offset;
19659                            new_selections_by_buffer
19660                                .entry(buffer_handle)
19661                                .or_insert((Vec::new(), None))
19662                                .0
19663                                .push(range)
19664                        } else {
19665                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19666                            else {
19667                                continue;
19668                            };
19669                            new_selections_by_buffer
19670                                .entry(buffer_handle)
19671                                .or_insert((Vec::new(), None))
19672                                .0
19673                                .push(range)
19674                        }
19675                    }
19676                }
19677            }
19678        }
19679
19680        new_selections_by_buffer
19681            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19682
19683        if new_selections_by_buffer.is_empty() {
19684            return;
19685        }
19686
19687        // We defer the pane interaction because we ourselves are a workspace item
19688        // and activating a new item causes the pane to call a method on us reentrantly,
19689        // which panics if we're on the stack.
19690        window.defer(cx, move |window, cx| {
19691            workspace.update(cx, |workspace, cx| {
19692                let pane = if split {
19693                    workspace.adjacent_pane(window, cx)
19694                } else {
19695                    workspace.active_pane().clone()
19696                };
19697
19698                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19699                    let editor = buffer
19700                        .read(cx)
19701                        .file()
19702                        .is_none()
19703                        .then(|| {
19704                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19705                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19706                            // Instead, we try to activate the existing editor in the pane first.
19707                            let (editor, pane_item_index) =
19708                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19709                                    let editor = item.downcast::<Editor>()?;
19710                                    let singleton_buffer =
19711                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19712                                    if singleton_buffer == buffer {
19713                                        Some((editor, i))
19714                                    } else {
19715                                        None
19716                                    }
19717                                })?;
19718                            pane.update(cx, |pane, cx| {
19719                                pane.activate_item(pane_item_index, true, true, window, cx)
19720                            });
19721                            Some(editor)
19722                        })
19723                        .flatten()
19724                        .unwrap_or_else(|| {
19725                            workspace.open_project_item::<Self>(
19726                                pane.clone(),
19727                                buffer,
19728                                true,
19729                                true,
19730                                window,
19731                                cx,
19732                            )
19733                        });
19734
19735                    editor.update(cx, |editor, cx| {
19736                        let autoscroll = match scroll_offset {
19737                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19738                            None => Autoscroll::newest(),
19739                        };
19740                        let nav_history = editor.nav_history.take();
19741                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19742                            s.select_ranges(ranges);
19743                        });
19744                        editor.nav_history = nav_history;
19745                    });
19746                }
19747            })
19748        });
19749    }
19750
19751    // For now, don't allow opening excerpts in buffers that aren't backed by
19752    // regular project files.
19753    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19754        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19755    }
19756
19757    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19758        let snapshot = self.buffer.read(cx).read(cx);
19759        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19760        Some(
19761            ranges
19762                .iter()
19763                .map(move |range| {
19764                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19765                })
19766                .collect(),
19767        )
19768    }
19769
19770    fn selection_replacement_ranges(
19771        &self,
19772        range: Range<OffsetUtf16>,
19773        cx: &mut App,
19774    ) -> Vec<Range<OffsetUtf16>> {
19775        let selections = self.selections.all::<OffsetUtf16>(cx);
19776        let newest_selection = selections
19777            .iter()
19778            .max_by_key(|selection| selection.id)
19779            .unwrap();
19780        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19781        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19782        let snapshot = self.buffer.read(cx).read(cx);
19783        selections
19784            .into_iter()
19785            .map(|mut selection| {
19786                selection.start.0 =
19787                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19788                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19789                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19790                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19791            })
19792            .collect()
19793    }
19794
19795    fn report_editor_event(
19796        &self,
19797        event_type: &'static str,
19798        file_extension: Option<String>,
19799        cx: &App,
19800    ) {
19801        if cfg!(any(test, feature = "test-support")) {
19802            return;
19803        }
19804
19805        let Some(project) = &self.project else { return };
19806
19807        // If None, we are in a file without an extension
19808        let file = self
19809            .buffer
19810            .read(cx)
19811            .as_singleton()
19812            .and_then(|b| b.read(cx).file());
19813        let file_extension = file_extension.or(file
19814            .as_ref()
19815            .and_then(|file| Path::new(file.file_name(cx)).extension())
19816            .and_then(|e| e.to_str())
19817            .map(|a| a.to_string()));
19818
19819        let vim_mode = vim_enabled(cx);
19820
19821        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19822        let copilot_enabled = edit_predictions_provider
19823            == language::language_settings::EditPredictionProvider::Copilot;
19824        let copilot_enabled_for_language = self
19825            .buffer
19826            .read(cx)
19827            .language_settings(cx)
19828            .show_edit_predictions;
19829
19830        let project = project.read(cx);
19831        telemetry::event!(
19832            event_type,
19833            file_extension,
19834            vim_mode,
19835            copilot_enabled,
19836            copilot_enabled_for_language,
19837            edit_predictions_provider,
19838            is_via_ssh = project.is_via_ssh(),
19839        );
19840    }
19841
19842    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19843    /// with each line being an array of {text, highlight} objects.
19844    fn copy_highlight_json(
19845        &mut self,
19846        _: &CopyHighlightJson,
19847        window: &mut Window,
19848        cx: &mut Context<Self>,
19849    ) {
19850        #[derive(Serialize)]
19851        struct Chunk<'a> {
19852            text: String,
19853            highlight: Option<&'a str>,
19854        }
19855
19856        let snapshot = self.buffer.read(cx).snapshot(cx);
19857        let range = self
19858            .selected_text_range(false, window, cx)
19859            .and_then(|selection| {
19860                if selection.range.is_empty() {
19861                    None
19862                } else {
19863                    Some(selection.range)
19864                }
19865            })
19866            .unwrap_or_else(|| 0..snapshot.len());
19867
19868        let chunks = snapshot.chunks(range, true);
19869        let mut lines = Vec::new();
19870        let mut line: VecDeque<Chunk> = VecDeque::new();
19871
19872        let Some(style) = self.style.as_ref() else {
19873            return;
19874        };
19875
19876        for chunk in chunks {
19877            let highlight = chunk
19878                .syntax_highlight_id
19879                .and_then(|id| id.name(&style.syntax));
19880            let mut chunk_lines = chunk.text.split('\n').peekable();
19881            while let Some(text) = chunk_lines.next() {
19882                let mut merged_with_last_token = false;
19883                if let Some(last_token) = line.back_mut() {
19884                    if last_token.highlight == highlight {
19885                        last_token.text.push_str(text);
19886                        merged_with_last_token = true;
19887                    }
19888                }
19889
19890                if !merged_with_last_token {
19891                    line.push_back(Chunk {
19892                        text: text.into(),
19893                        highlight,
19894                    });
19895                }
19896
19897                if chunk_lines.peek().is_some() {
19898                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19899                        line.pop_front();
19900                    }
19901                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19902                        line.pop_back();
19903                    }
19904
19905                    lines.push(mem::take(&mut line));
19906                }
19907            }
19908        }
19909
19910        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19911            return;
19912        };
19913        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19914    }
19915
19916    pub fn open_context_menu(
19917        &mut self,
19918        _: &OpenContextMenu,
19919        window: &mut Window,
19920        cx: &mut Context<Self>,
19921    ) {
19922        self.request_autoscroll(Autoscroll::newest(), cx);
19923        let position = self.selections.newest_display(cx).start;
19924        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19925    }
19926
19927    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19928        &self.inlay_hint_cache
19929    }
19930
19931    pub fn replay_insert_event(
19932        &mut self,
19933        text: &str,
19934        relative_utf16_range: Option<Range<isize>>,
19935        window: &mut Window,
19936        cx: &mut Context<Self>,
19937    ) {
19938        if !self.input_enabled {
19939            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19940            return;
19941        }
19942        if let Some(relative_utf16_range) = relative_utf16_range {
19943            let selections = self.selections.all::<OffsetUtf16>(cx);
19944            self.change_selections(None, window, cx, |s| {
19945                let new_ranges = selections.into_iter().map(|range| {
19946                    let start = OffsetUtf16(
19947                        range
19948                            .head()
19949                            .0
19950                            .saturating_add_signed(relative_utf16_range.start),
19951                    );
19952                    let end = OffsetUtf16(
19953                        range
19954                            .head()
19955                            .0
19956                            .saturating_add_signed(relative_utf16_range.end),
19957                    );
19958                    start..end
19959                });
19960                s.select_ranges(new_ranges);
19961            });
19962        }
19963
19964        self.handle_input(text, window, cx);
19965    }
19966
19967    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19968        let Some(provider) = self.semantics_provider.as_ref() else {
19969            return false;
19970        };
19971
19972        let mut supports = false;
19973        self.buffer().update(cx, |this, cx| {
19974            this.for_each_buffer(|buffer| {
19975                supports |= provider.supports_inlay_hints(buffer, cx);
19976            });
19977        });
19978
19979        supports
19980    }
19981
19982    pub fn is_focused(&self, window: &Window) -> bool {
19983        self.focus_handle.is_focused(window)
19984    }
19985
19986    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19987        cx.emit(EditorEvent::Focused);
19988
19989        if let Some(descendant) = self
19990            .last_focused_descendant
19991            .take()
19992            .and_then(|descendant| descendant.upgrade())
19993        {
19994            window.focus(&descendant);
19995        } else {
19996            if let Some(blame) = self.blame.as_ref() {
19997                blame.update(cx, GitBlame::focus)
19998            }
19999
20000            self.blink_manager.update(cx, BlinkManager::enable);
20001            self.show_cursor_names(window, cx);
20002            self.buffer.update(cx, |buffer, cx| {
20003                buffer.finalize_last_transaction(cx);
20004                if self.leader_id.is_none() {
20005                    buffer.set_active_selections(
20006                        &self.selections.disjoint_anchors(),
20007                        self.selections.line_mode,
20008                        self.cursor_shape,
20009                        cx,
20010                    );
20011                }
20012            });
20013        }
20014    }
20015
20016    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20017        cx.emit(EditorEvent::FocusedIn)
20018    }
20019
20020    fn handle_focus_out(
20021        &mut self,
20022        event: FocusOutEvent,
20023        _window: &mut Window,
20024        cx: &mut Context<Self>,
20025    ) {
20026        if event.blurred != self.focus_handle {
20027            self.last_focused_descendant = Some(event.blurred);
20028        }
20029        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20030    }
20031
20032    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20033        self.blink_manager.update(cx, BlinkManager::disable);
20034        self.buffer
20035            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20036
20037        if let Some(blame) = self.blame.as_ref() {
20038            blame.update(cx, GitBlame::blur)
20039        }
20040        if !self.hover_state.focused(window, cx) {
20041            hide_hover(self, cx);
20042        }
20043        if !self
20044            .context_menu
20045            .borrow()
20046            .as_ref()
20047            .is_some_and(|context_menu| context_menu.focused(window, cx))
20048        {
20049            self.hide_context_menu(window, cx);
20050        }
20051        self.discard_inline_completion(false, cx);
20052        cx.emit(EditorEvent::Blurred);
20053        cx.notify();
20054    }
20055
20056    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20057        let mut pending: String = window
20058            .pending_input_keystrokes()
20059            .into_iter()
20060            .flatten()
20061            .filter_map(|keystroke| {
20062                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20063                    keystroke.key_char.clone()
20064                } else {
20065                    None
20066                }
20067            })
20068            .collect();
20069
20070        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20071            pending = "".to_string();
20072        }
20073
20074        let existing_pending = self
20075            .text_highlights::<PendingInput>(cx)
20076            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20077        if existing_pending.is_none() && pending.is_empty() {
20078            return;
20079        }
20080        let transaction =
20081            self.transact(window, cx, |this, window, cx| {
20082                let selections = this.selections.all::<usize>(cx);
20083                let edits = selections
20084                    .iter()
20085                    .map(|selection| (selection.end..selection.end, pending.clone()));
20086                this.edit(edits, cx);
20087                this.change_selections(None, window, cx, |s| {
20088                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20089                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20090                    }));
20091                });
20092                if let Some(existing_ranges) = existing_pending {
20093                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20094                    this.edit(edits, cx);
20095                }
20096            });
20097
20098        let snapshot = self.snapshot(window, cx);
20099        let ranges = self
20100            .selections
20101            .all::<usize>(cx)
20102            .into_iter()
20103            .map(|selection| {
20104                snapshot.buffer_snapshot.anchor_after(selection.end)
20105                    ..snapshot
20106                        .buffer_snapshot
20107                        .anchor_before(selection.end + pending.len())
20108            })
20109            .collect();
20110
20111        if pending.is_empty() {
20112            self.clear_highlights::<PendingInput>(cx);
20113        } else {
20114            self.highlight_text::<PendingInput>(
20115                ranges,
20116                HighlightStyle {
20117                    underline: Some(UnderlineStyle {
20118                        thickness: px(1.),
20119                        color: None,
20120                        wavy: false,
20121                    }),
20122                    ..Default::default()
20123                },
20124                cx,
20125            );
20126        }
20127
20128        self.ime_transaction = self.ime_transaction.or(transaction);
20129        if let Some(transaction) = self.ime_transaction {
20130            self.buffer.update(cx, |buffer, cx| {
20131                buffer.group_until_transaction(transaction, cx);
20132            });
20133        }
20134
20135        if self.text_highlights::<PendingInput>(cx).is_none() {
20136            self.ime_transaction.take();
20137        }
20138    }
20139
20140    pub fn register_action_renderer(
20141        &mut self,
20142        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20143    ) -> Subscription {
20144        let id = self.next_editor_action_id.post_inc();
20145        self.editor_actions
20146            .borrow_mut()
20147            .insert(id, Box::new(listener));
20148
20149        let editor_actions = self.editor_actions.clone();
20150        Subscription::new(move || {
20151            editor_actions.borrow_mut().remove(&id);
20152        })
20153    }
20154
20155    pub fn register_action<A: Action>(
20156        &mut self,
20157        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20158    ) -> Subscription {
20159        let id = self.next_editor_action_id.post_inc();
20160        let listener = Arc::new(listener);
20161        self.editor_actions.borrow_mut().insert(
20162            id,
20163            Box::new(move |_, window, _| {
20164                let listener = listener.clone();
20165                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20166                    let action = action.downcast_ref().unwrap();
20167                    if phase == DispatchPhase::Bubble {
20168                        listener(action, window, cx)
20169                    }
20170                })
20171            }),
20172        );
20173
20174        let editor_actions = self.editor_actions.clone();
20175        Subscription::new(move || {
20176            editor_actions.borrow_mut().remove(&id);
20177        })
20178    }
20179
20180    pub fn file_header_size(&self) -> u32 {
20181        FILE_HEADER_HEIGHT
20182    }
20183
20184    pub fn restore(
20185        &mut self,
20186        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20187        window: &mut Window,
20188        cx: &mut Context<Self>,
20189    ) {
20190        let workspace = self.workspace();
20191        let project = self.project.as_ref();
20192        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20193            let mut tasks = Vec::new();
20194            for (buffer_id, changes) in revert_changes {
20195                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20196                    buffer.update(cx, |buffer, cx| {
20197                        buffer.edit(
20198                            changes
20199                                .into_iter()
20200                                .map(|(range, text)| (range, text.to_string())),
20201                            None,
20202                            cx,
20203                        );
20204                    });
20205
20206                    if let Some(project) =
20207                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20208                    {
20209                        project.update(cx, |project, cx| {
20210                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20211                        })
20212                    }
20213                }
20214            }
20215            tasks
20216        });
20217        cx.spawn_in(window, async move |_, cx| {
20218            for (buffer, task) in save_tasks {
20219                let result = task.await;
20220                if result.is_err() {
20221                    let Some(path) = buffer
20222                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20223                        .ok()
20224                    else {
20225                        continue;
20226                    };
20227                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20228                        let Some(task) = cx
20229                            .update_window_entity(&workspace, |workspace, window, cx| {
20230                                workspace
20231                                    .open_path_preview(path, None, false, false, false, window, cx)
20232                            })
20233                            .ok()
20234                        else {
20235                            continue;
20236                        };
20237                        task.await.log_err();
20238                    }
20239                }
20240            }
20241        })
20242        .detach();
20243        self.change_selections(None, window, cx, |selections| selections.refresh());
20244    }
20245
20246    pub fn to_pixel_point(
20247        &self,
20248        source: multi_buffer::Anchor,
20249        editor_snapshot: &EditorSnapshot,
20250        window: &mut Window,
20251    ) -> Option<gpui::Point<Pixels>> {
20252        let source_point = source.to_display_point(editor_snapshot);
20253        self.display_to_pixel_point(source_point, editor_snapshot, window)
20254    }
20255
20256    pub fn display_to_pixel_point(
20257        &self,
20258        source: DisplayPoint,
20259        editor_snapshot: &EditorSnapshot,
20260        window: &mut Window,
20261    ) -> Option<gpui::Point<Pixels>> {
20262        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20263        let text_layout_details = self.text_layout_details(window);
20264        let scroll_top = text_layout_details
20265            .scroll_anchor
20266            .scroll_position(editor_snapshot)
20267            .y;
20268
20269        if source.row().as_f32() < scroll_top.floor() {
20270            return None;
20271        }
20272        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20273        let source_y = line_height * (source.row().as_f32() - scroll_top);
20274        Some(gpui::Point::new(source_x, source_y))
20275    }
20276
20277    pub fn has_visible_completions_menu(&self) -> bool {
20278        !self.edit_prediction_preview_is_active()
20279            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20280                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20281            })
20282    }
20283
20284    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20285        if self.mode.is_minimap() {
20286            return;
20287        }
20288        self.addons
20289            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20290    }
20291
20292    pub fn unregister_addon<T: Addon>(&mut self) {
20293        self.addons.remove(&std::any::TypeId::of::<T>());
20294    }
20295
20296    pub fn addon<T: Addon>(&self) -> Option<&T> {
20297        let type_id = std::any::TypeId::of::<T>();
20298        self.addons
20299            .get(&type_id)
20300            .and_then(|item| item.to_any().downcast_ref::<T>())
20301    }
20302
20303    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20304        let type_id = std::any::TypeId::of::<T>();
20305        self.addons
20306            .get_mut(&type_id)
20307            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20308    }
20309
20310    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20311        let text_layout_details = self.text_layout_details(window);
20312        let style = &text_layout_details.editor_style;
20313        let font_id = window.text_system().resolve_font(&style.text.font());
20314        let font_size = style.text.font_size.to_pixels(window.rem_size());
20315        let line_height = style.text.line_height_in_pixels(window.rem_size());
20316        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20317
20318        gpui::Size::new(em_width, line_height)
20319    }
20320
20321    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20322        self.load_diff_task.clone()
20323    }
20324
20325    fn read_metadata_from_db(
20326        &mut self,
20327        item_id: u64,
20328        workspace_id: WorkspaceId,
20329        window: &mut Window,
20330        cx: &mut Context<Editor>,
20331    ) {
20332        if self.is_singleton(cx)
20333            && !self.mode.is_minimap()
20334            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20335        {
20336            let buffer_snapshot = OnceCell::new();
20337
20338            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20339                if !folds.is_empty() {
20340                    let snapshot =
20341                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20342                    self.fold_ranges(
20343                        folds
20344                            .into_iter()
20345                            .map(|(start, end)| {
20346                                snapshot.clip_offset(start, Bias::Left)
20347                                    ..snapshot.clip_offset(end, Bias::Right)
20348                            })
20349                            .collect(),
20350                        false,
20351                        window,
20352                        cx,
20353                    );
20354                }
20355            }
20356
20357            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20358                if !selections.is_empty() {
20359                    let snapshot =
20360                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20361                    // skip adding the initial selection to selection history
20362                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20363                    self.change_selections(None, window, cx, |s| {
20364                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20365                            snapshot.clip_offset(start, Bias::Left)
20366                                ..snapshot.clip_offset(end, Bias::Right)
20367                        }));
20368                    });
20369                    self.selection_history.mode = SelectionHistoryMode::Normal;
20370                }
20371            };
20372        }
20373
20374        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20375    }
20376
20377    fn update_lsp_data(
20378        &mut self,
20379        for_server_id: Option<LanguageServerId>,
20380        for_buffer: Option<BufferId>,
20381        window: &mut Window,
20382        cx: &mut Context<'_, Self>,
20383    ) {
20384        self.pull_diagnostics(for_buffer, window, cx);
20385        self.refresh_colors(for_server_id, for_buffer, window, cx);
20386    }
20387}
20388
20389fn vim_enabled(cx: &App) -> bool {
20390    cx.global::<SettingsStore>()
20391        .raw_user_settings()
20392        .get("vim_mode")
20393        == Some(&serde_json::Value::Bool(true))
20394}
20395
20396fn process_completion_for_edit(
20397    completion: &Completion,
20398    intent: CompletionIntent,
20399    buffer: &Entity<Buffer>,
20400    cursor_position: &text::Anchor,
20401    cx: &mut Context<Editor>,
20402) -> CompletionEdit {
20403    let buffer = buffer.read(cx);
20404    let buffer_snapshot = buffer.snapshot();
20405    let (snippet, new_text) = if completion.is_snippet() {
20406        // Workaround for typescript language server issues so that methods don't expand within
20407        // strings and functions with type expressions. The previous point is used because the query
20408        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20409        let mut snippet_source = completion.new_text.clone();
20410        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20411        previous_point.column = previous_point.column.saturating_sub(1);
20412        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20413            if scope.prefers_label_for_snippet_in_completion() {
20414                if let Some(label) = completion.label() {
20415                    if matches!(
20416                        completion.kind(),
20417                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20418                    ) {
20419                        snippet_source = label;
20420                    }
20421                }
20422            }
20423        }
20424        match Snippet::parse(&snippet_source).log_err() {
20425            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20426            None => (None, completion.new_text.clone()),
20427        }
20428    } else {
20429        (None, completion.new_text.clone())
20430    };
20431
20432    let mut range_to_replace = {
20433        let replace_range = &completion.replace_range;
20434        if let CompletionSource::Lsp {
20435            insert_range: Some(insert_range),
20436            ..
20437        } = &completion.source
20438        {
20439            debug_assert_eq!(
20440                insert_range.start, replace_range.start,
20441                "insert_range and replace_range should start at the same position"
20442            );
20443            debug_assert!(
20444                insert_range
20445                    .start
20446                    .cmp(&cursor_position, &buffer_snapshot)
20447                    .is_le(),
20448                "insert_range should start before or at cursor position"
20449            );
20450            debug_assert!(
20451                replace_range
20452                    .start
20453                    .cmp(&cursor_position, &buffer_snapshot)
20454                    .is_le(),
20455                "replace_range should start before or at cursor position"
20456            );
20457            debug_assert!(
20458                insert_range
20459                    .end
20460                    .cmp(&cursor_position, &buffer_snapshot)
20461                    .is_le(),
20462                "insert_range should end before or at cursor position"
20463            );
20464
20465            let should_replace = match intent {
20466                CompletionIntent::CompleteWithInsert => false,
20467                CompletionIntent::CompleteWithReplace => true,
20468                CompletionIntent::Complete | CompletionIntent::Compose => {
20469                    let insert_mode =
20470                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20471                            .completions
20472                            .lsp_insert_mode;
20473                    match insert_mode {
20474                        LspInsertMode::Insert => false,
20475                        LspInsertMode::Replace => true,
20476                        LspInsertMode::ReplaceSubsequence => {
20477                            let mut text_to_replace = buffer.chars_for_range(
20478                                buffer.anchor_before(replace_range.start)
20479                                    ..buffer.anchor_after(replace_range.end),
20480                            );
20481                            let mut current_needle = text_to_replace.next();
20482                            for haystack_ch in completion.label.text.chars() {
20483                                if let Some(needle_ch) = current_needle {
20484                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20485                                        current_needle = text_to_replace.next();
20486                                    }
20487                                }
20488                            }
20489                            current_needle.is_none()
20490                        }
20491                        LspInsertMode::ReplaceSuffix => {
20492                            if replace_range
20493                                .end
20494                                .cmp(&cursor_position, &buffer_snapshot)
20495                                .is_gt()
20496                            {
20497                                let range_after_cursor = *cursor_position..replace_range.end;
20498                                let text_after_cursor = buffer
20499                                    .text_for_range(
20500                                        buffer.anchor_before(range_after_cursor.start)
20501                                            ..buffer.anchor_after(range_after_cursor.end),
20502                                    )
20503                                    .collect::<String>()
20504                                    .to_ascii_lowercase();
20505                                completion
20506                                    .label
20507                                    .text
20508                                    .to_ascii_lowercase()
20509                                    .ends_with(&text_after_cursor)
20510                            } else {
20511                                true
20512                            }
20513                        }
20514                    }
20515                }
20516            };
20517
20518            if should_replace {
20519                replace_range.clone()
20520            } else {
20521                insert_range.clone()
20522            }
20523        } else {
20524            replace_range.clone()
20525        }
20526    };
20527
20528    if range_to_replace
20529        .end
20530        .cmp(&cursor_position, &buffer_snapshot)
20531        .is_lt()
20532    {
20533        range_to_replace.end = *cursor_position;
20534    }
20535
20536    CompletionEdit {
20537        new_text,
20538        replace_range: range_to_replace.to_offset(&buffer),
20539        snippet,
20540    }
20541}
20542
20543struct CompletionEdit {
20544    new_text: String,
20545    replace_range: Range<usize>,
20546    snippet: Option<Snippet>,
20547}
20548
20549fn insert_extra_newline_brackets(
20550    buffer: &MultiBufferSnapshot,
20551    range: Range<usize>,
20552    language: &language::LanguageScope,
20553) -> bool {
20554    let leading_whitespace_len = buffer
20555        .reversed_chars_at(range.start)
20556        .take_while(|c| c.is_whitespace() && *c != '\n')
20557        .map(|c| c.len_utf8())
20558        .sum::<usize>();
20559    let trailing_whitespace_len = buffer
20560        .chars_at(range.end)
20561        .take_while(|c| c.is_whitespace() && *c != '\n')
20562        .map(|c| c.len_utf8())
20563        .sum::<usize>();
20564    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20565
20566    language.brackets().any(|(pair, enabled)| {
20567        let pair_start = pair.start.trim_end();
20568        let pair_end = pair.end.trim_start();
20569
20570        enabled
20571            && pair.newline
20572            && buffer.contains_str_at(range.end, pair_end)
20573            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20574    })
20575}
20576
20577fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20578    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20579        [(buffer, range, _)] => (*buffer, range.clone()),
20580        _ => return false,
20581    };
20582    let pair = {
20583        let mut result: Option<BracketMatch> = None;
20584
20585        for pair in buffer
20586            .all_bracket_ranges(range.clone())
20587            .filter(move |pair| {
20588                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20589            })
20590        {
20591            let len = pair.close_range.end - pair.open_range.start;
20592
20593            if let Some(existing) = &result {
20594                let existing_len = existing.close_range.end - existing.open_range.start;
20595                if len > existing_len {
20596                    continue;
20597                }
20598            }
20599
20600            result = Some(pair);
20601        }
20602
20603        result
20604    };
20605    let Some(pair) = pair else {
20606        return false;
20607    };
20608    pair.newline_only
20609        && buffer
20610            .chars_for_range(pair.open_range.end..range.start)
20611            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20612            .all(|c| c.is_whitespace() && c != '\n')
20613}
20614
20615fn update_uncommitted_diff_for_buffer(
20616    editor: Entity<Editor>,
20617    project: &Entity<Project>,
20618    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20619    buffer: Entity<MultiBuffer>,
20620    cx: &mut App,
20621) -> Task<()> {
20622    let mut tasks = Vec::new();
20623    project.update(cx, |project, cx| {
20624        for buffer in buffers {
20625            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20626                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20627            }
20628        }
20629    });
20630    cx.spawn(async move |cx| {
20631        let diffs = future::join_all(tasks).await;
20632        if editor
20633            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20634            .unwrap_or(false)
20635        {
20636            return;
20637        }
20638
20639        buffer
20640            .update(cx, |buffer, cx| {
20641                for diff in diffs.into_iter().flatten() {
20642                    buffer.add_diff(diff, cx);
20643                }
20644            })
20645            .ok();
20646    })
20647}
20648
20649fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20650    let tab_size = tab_size.get() as usize;
20651    let mut width = offset;
20652
20653    for ch in text.chars() {
20654        width += if ch == '\t' {
20655            tab_size - (width % tab_size)
20656        } else {
20657            1
20658        };
20659    }
20660
20661    width - offset
20662}
20663
20664#[cfg(test)]
20665mod tests {
20666    use super::*;
20667
20668    #[test]
20669    fn test_string_size_with_expanded_tabs() {
20670        let nz = |val| NonZeroU32::new(val).unwrap();
20671        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20672        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20673        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20674        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20675        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20676        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20677        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20678        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20679    }
20680}
20681
20682/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20683struct WordBreakingTokenizer<'a> {
20684    input: &'a str,
20685}
20686
20687impl<'a> WordBreakingTokenizer<'a> {
20688    fn new(input: &'a str) -> Self {
20689        Self { input }
20690    }
20691}
20692
20693fn is_char_ideographic(ch: char) -> bool {
20694    use unicode_script::Script::*;
20695    use unicode_script::UnicodeScript;
20696    matches!(ch.script(), Han | Tangut | Yi)
20697}
20698
20699fn is_grapheme_ideographic(text: &str) -> bool {
20700    text.chars().any(is_char_ideographic)
20701}
20702
20703fn is_grapheme_whitespace(text: &str) -> bool {
20704    text.chars().any(|x| x.is_whitespace())
20705}
20706
20707fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20708    text.chars().next().map_or(false, |ch| {
20709        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20710    })
20711}
20712
20713#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20714enum WordBreakToken<'a> {
20715    Word { token: &'a str, grapheme_len: usize },
20716    InlineWhitespace { token: &'a str, grapheme_len: usize },
20717    Newline,
20718}
20719
20720impl<'a> Iterator for WordBreakingTokenizer<'a> {
20721    /// Yields a span, the count of graphemes in the token, and whether it was
20722    /// whitespace. Note that it also breaks at word boundaries.
20723    type Item = WordBreakToken<'a>;
20724
20725    fn next(&mut self) -> Option<Self::Item> {
20726        use unicode_segmentation::UnicodeSegmentation;
20727        if self.input.is_empty() {
20728            return None;
20729        }
20730
20731        let mut iter = self.input.graphemes(true).peekable();
20732        let mut offset = 0;
20733        let mut grapheme_len = 0;
20734        if let Some(first_grapheme) = iter.next() {
20735            let is_newline = first_grapheme == "\n";
20736            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20737            offset += first_grapheme.len();
20738            grapheme_len += 1;
20739            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20740                if let Some(grapheme) = iter.peek().copied() {
20741                    if should_stay_with_preceding_ideograph(grapheme) {
20742                        offset += grapheme.len();
20743                        grapheme_len += 1;
20744                    }
20745                }
20746            } else {
20747                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20748                let mut next_word_bound = words.peek().copied();
20749                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20750                    next_word_bound = words.next();
20751                }
20752                while let Some(grapheme) = iter.peek().copied() {
20753                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20754                        break;
20755                    };
20756                    if is_grapheme_whitespace(grapheme) != is_whitespace
20757                        || (grapheme == "\n") != is_newline
20758                    {
20759                        break;
20760                    };
20761                    offset += grapheme.len();
20762                    grapheme_len += 1;
20763                    iter.next();
20764                }
20765            }
20766            let token = &self.input[..offset];
20767            self.input = &self.input[offset..];
20768            if token == "\n" {
20769                Some(WordBreakToken::Newline)
20770            } else if is_whitespace {
20771                Some(WordBreakToken::InlineWhitespace {
20772                    token,
20773                    grapheme_len,
20774                })
20775            } else {
20776                Some(WordBreakToken::Word {
20777                    token,
20778                    grapheme_len,
20779                })
20780            }
20781        } else {
20782            None
20783        }
20784    }
20785}
20786
20787#[test]
20788fn test_word_breaking_tokenizer() {
20789    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20790        ("", &[]),
20791        ("  ", &[whitespace("  ", 2)]),
20792        ("Ʒ", &[word("Ʒ", 1)]),
20793        ("Ǽ", &[word("Ǽ", 1)]),
20794        ("", &[word("", 1)]),
20795        ("⋑⋑", &[word("⋑⋑", 2)]),
20796        (
20797            "原理,进而",
20798            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20799        ),
20800        (
20801            "hello world",
20802            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20803        ),
20804        (
20805            "hello, world",
20806            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20807        ),
20808        (
20809            "  hello world",
20810            &[
20811                whitespace("  ", 2),
20812                word("hello", 5),
20813                whitespace(" ", 1),
20814                word("world", 5),
20815            ],
20816        ),
20817        (
20818            "这是什么 \n 钢笔",
20819            &[
20820                word("", 1),
20821                word("", 1),
20822                word("", 1),
20823                word("", 1),
20824                whitespace(" ", 1),
20825                newline(),
20826                whitespace(" ", 1),
20827                word("", 1),
20828                word("", 1),
20829            ],
20830        ),
20831        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20832    ];
20833
20834    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20835        WordBreakToken::Word {
20836            token,
20837            grapheme_len,
20838        }
20839    }
20840
20841    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20842        WordBreakToken::InlineWhitespace {
20843            token,
20844            grapheme_len,
20845        }
20846    }
20847
20848    fn newline() -> WordBreakToken<'static> {
20849        WordBreakToken::Newline
20850    }
20851
20852    for (input, result) in tests {
20853        assert_eq!(
20854            WordBreakingTokenizer::new(input)
20855                .collect::<Vec<_>>()
20856                .as_slice(),
20857            *result,
20858        );
20859    }
20860}
20861
20862fn wrap_with_prefix(
20863    line_prefix: String,
20864    unwrapped_text: String,
20865    wrap_column: usize,
20866    tab_size: NonZeroU32,
20867    preserve_existing_whitespace: bool,
20868) -> String {
20869    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20870    let mut wrapped_text = String::new();
20871    let mut current_line = line_prefix.clone();
20872
20873    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20874    let mut current_line_len = line_prefix_len;
20875    let mut in_whitespace = false;
20876    for token in tokenizer {
20877        let have_preceding_whitespace = in_whitespace;
20878        match token {
20879            WordBreakToken::Word {
20880                token,
20881                grapheme_len,
20882            } => {
20883                in_whitespace = false;
20884                if current_line_len + grapheme_len > wrap_column
20885                    && current_line_len != line_prefix_len
20886                {
20887                    wrapped_text.push_str(current_line.trim_end());
20888                    wrapped_text.push('\n');
20889                    current_line.truncate(line_prefix.len());
20890                    current_line_len = line_prefix_len;
20891                }
20892                current_line.push_str(token);
20893                current_line_len += grapheme_len;
20894            }
20895            WordBreakToken::InlineWhitespace {
20896                mut token,
20897                mut grapheme_len,
20898            } => {
20899                in_whitespace = true;
20900                if have_preceding_whitespace && !preserve_existing_whitespace {
20901                    continue;
20902                }
20903                if !preserve_existing_whitespace {
20904                    token = " ";
20905                    grapheme_len = 1;
20906                }
20907                if current_line_len + grapheme_len > wrap_column {
20908                    wrapped_text.push_str(current_line.trim_end());
20909                    wrapped_text.push('\n');
20910                    current_line.truncate(line_prefix.len());
20911                    current_line_len = line_prefix_len;
20912                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20913                    current_line.push_str(token);
20914                    current_line_len += grapheme_len;
20915                }
20916            }
20917            WordBreakToken::Newline => {
20918                in_whitespace = true;
20919                if preserve_existing_whitespace {
20920                    wrapped_text.push_str(current_line.trim_end());
20921                    wrapped_text.push('\n');
20922                    current_line.truncate(line_prefix.len());
20923                    current_line_len = line_prefix_len;
20924                } else if have_preceding_whitespace {
20925                    continue;
20926                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20927                {
20928                    wrapped_text.push_str(current_line.trim_end());
20929                    wrapped_text.push('\n');
20930                    current_line.truncate(line_prefix.len());
20931                    current_line_len = line_prefix_len;
20932                } else if current_line_len != line_prefix_len {
20933                    current_line.push(' ');
20934                    current_line_len += 1;
20935                }
20936            }
20937        }
20938    }
20939
20940    if !current_line.is_empty() {
20941        wrapped_text.push_str(&current_line);
20942    }
20943    wrapped_text
20944}
20945
20946#[test]
20947fn test_wrap_with_prefix() {
20948    assert_eq!(
20949        wrap_with_prefix(
20950            "# ".to_string(),
20951            "abcdefg".to_string(),
20952            4,
20953            NonZeroU32::new(4).unwrap(),
20954            false,
20955        ),
20956        "# abcdefg"
20957    );
20958    assert_eq!(
20959        wrap_with_prefix(
20960            "".to_string(),
20961            "\thello world".to_string(),
20962            8,
20963            NonZeroU32::new(4).unwrap(),
20964            false,
20965        ),
20966        "hello\nworld"
20967    );
20968    assert_eq!(
20969        wrap_with_prefix(
20970            "// ".to_string(),
20971            "xx \nyy zz aa bb cc".to_string(),
20972            12,
20973            NonZeroU32::new(4).unwrap(),
20974            false,
20975        ),
20976        "// xx yy zz\n// aa bb cc"
20977    );
20978    assert_eq!(
20979        wrap_with_prefix(
20980            String::new(),
20981            "这是什么 \n 钢笔".to_string(),
20982            3,
20983            NonZeroU32::new(4).unwrap(),
20984            false,
20985        ),
20986        "这是什\n么 钢\n"
20987    );
20988}
20989
20990pub trait CollaborationHub {
20991    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20992    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20993    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20994}
20995
20996impl CollaborationHub for Entity<Project> {
20997    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20998        self.read(cx).collaborators()
20999    }
21000
21001    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21002        self.read(cx).user_store().read(cx).participant_indices()
21003    }
21004
21005    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21006        let this = self.read(cx);
21007        let user_ids = this.collaborators().values().map(|c| c.user_id);
21008        this.user_store().read(cx).participant_names(user_ids, cx)
21009    }
21010}
21011
21012pub trait SemanticsProvider {
21013    fn hover(
21014        &self,
21015        buffer: &Entity<Buffer>,
21016        position: text::Anchor,
21017        cx: &mut App,
21018    ) -> Option<Task<Vec<project::Hover>>>;
21019
21020    fn inline_values(
21021        &self,
21022        buffer_handle: Entity<Buffer>,
21023        range: Range<text::Anchor>,
21024        cx: &mut App,
21025    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21026
21027    fn inlay_hints(
21028        &self,
21029        buffer_handle: Entity<Buffer>,
21030        range: Range<text::Anchor>,
21031        cx: &mut App,
21032    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21033
21034    fn resolve_inlay_hint(
21035        &self,
21036        hint: InlayHint,
21037        buffer_handle: Entity<Buffer>,
21038        server_id: LanguageServerId,
21039        cx: &mut App,
21040    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21041
21042    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21043
21044    fn document_highlights(
21045        &self,
21046        buffer: &Entity<Buffer>,
21047        position: text::Anchor,
21048        cx: &mut App,
21049    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21050
21051    fn definitions(
21052        &self,
21053        buffer: &Entity<Buffer>,
21054        position: text::Anchor,
21055        kind: GotoDefinitionKind,
21056        cx: &mut App,
21057    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21058
21059    fn range_for_rename(
21060        &self,
21061        buffer: &Entity<Buffer>,
21062        position: text::Anchor,
21063        cx: &mut App,
21064    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21065
21066    fn perform_rename(
21067        &self,
21068        buffer: &Entity<Buffer>,
21069        position: text::Anchor,
21070        new_name: String,
21071        cx: &mut App,
21072    ) -> Option<Task<Result<ProjectTransaction>>>;
21073}
21074
21075pub trait CompletionProvider {
21076    fn completions(
21077        &self,
21078        excerpt_id: ExcerptId,
21079        buffer: &Entity<Buffer>,
21080        buffer_position: text::Anchor,
21081        trigger: CompletionContext,
21082        window: &mut Window,
21083        cx: &mut Context<Editor>,
21084    ) -> Task<Result<Vec<CompletionResponse>>>;
21085
21086    fn resolve_completions(
21087        &self,
21088        _buffer: Entity<Buffer>,
21089        _completion_indices: Vec<usize>,
21090        _completions: Rc<RefCell<Box<[Completion]>>>,
21091        _cx: &mut Context<Editor>,
21092    ) -> Task<Result<bool>> {
21093        Task::ready(Ok(false))
21094    }
21095
21096    fn apply_additional_edits_for_completion(
21097        &self,
21098        _buffer: Entity<Buffer>,
21099        _completions: Rc<RefCell<Box<[Completion]>>>,
21100        _completion_index: usize,
21101        _push_to_history: bool,
21102        _cx: &mut Context<Editor>,
21103    ) -> Task<Result<Option<language::Transaction>>> {
21104        Task::ready(Ok(None))
21105    }
21106
21107    fn is_completion_trigger(
21108        &self,
21109        buffer: &Entity<Buffer>,
21110        position: language::Anchor,
21111        text: &str,
21112        trigger_in_words: bool,
21113        menu_is_open: bool,
21114        cx: &mut Context<Editor>,
21115    ) -> bool;
21116
21117    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21118
21119    fn sort_completions(&self) -> bool {
21120        true
21121    }
21122
21123    fn filter_completions(&self) -> bool {
21124        true
21125    }
21126}
21127
21128pub trait CodeActionProvider {
21129    fn id(&self) -> Arc<str>;
21130
21131    fn code_actions(
21132        &self,
21133        buffer: &Entity<Buffer>,
21134        range: Range<text::Anchor>,
21135        window: &mut Window,
21136        cx: &mut App,
21137    ) -> Task<Result<Vec<CodeAction>>>;
21138
21139    fn apply_code_action(
21140        &self,
21141        buffer_handle: Entity<Buffer>,
21142        action: CodeAction,
21143        excerpt_id: ExcerptId,
21144        push_to_history: bool,
21145        window: &mut Window,
21146        cx: &mut App,
21147    ) -> Task<Result<ProjectTransaction>>;
21148}
21149
21150impl CodeActionProvider for Entity<Project> {
21151    fn id(&self) -> Arc<str> {
21152        "project".into()
21153    }
21154
21155    fn code_actions(
21156        &self,
21157        buffer: &Entity<Buffer>,
21158        range: Range<text::Anchor>,
21159        _window: &mut Window,
21160        cx: &mut App,
21161    ) -> Task<Result<Vec<CodeAction>>> {
21162        self.update(cx, |project, cx| {
21163            let code_lens = project.code_lens(buffer, range.clone(), cx);
21164            let code_actions = project.code_actions(buffer, range, None, cx);
21165            cx.background_spawn(async move {
21166                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21167                Ok(code_lens
21168                    .context("code lens fetch")?
21169                    .into_iter()
21170                    .chain(code_actions.context("code action fetch")?)
21171                    .collect())
21172            })
21173        })
21174    }
21175
21176    fn apply_code_action(
21177        &self,
21178        buffer_handle: Entity<Buffer>,
21179        action: CodeAction,
21180        _excerpt_id: ExcerptId,
21181        push_to_history: bool,
21182        _window: &mut Window,
21183        cx: &mut App,
21184    ) -> Task<Result<ProjectTransaction>> {
21185        self.update(cx, |project, cx| {
21186            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21187        })
21188    }
21189}
21190
21191fn snippet_completions(
21192    project: &Project,
21193    buffer: &Entity<Buffer>,
21194    buffer_position: text::Anchor,
21195    cx: &mut App,
21196) -> Task<Result<CompletionResponse>> {
21197    let languages = buffer.read(cx).languages_at(buffer_position);
21198    let snippet_store = project.snippets().read(cx);
21199
21200    let scopes: Vec<_> = languages
21201        .iter()
21202        .filter_map(|language| {
21203            let language_name = language.lsp_id();
21204            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21205
21206            if snippets.is_empty() {
21207                None
21208            } else {
21209                Some((language.default_scope(), snippets))
21210            }
21211        })
21212        .collect();
21213
21214    if scopes.is_empty() {
21215        return Task::ready(Ok(CompletionResponse {
21216            completions: vec![],
21217            is_incomplete: false,
21218        }));
21219    }
21220
21221    let snapshot = buffer.read(cx).text_snapshot();
21222    let chars: String = snapshot
21223        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21224        .collect();
21225    let executor = cx.background_executor().clone();
21226
21227    cx.background_spawn(async move {
21228        let mut is_incomplete = false;
21229        let mut completions: Vec<Completion> = Vec::new();
21230        for (scope, snippets) in scopes.into_iter() {
21231            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21232            let mut last_word = chars
21233                .chars()
21234                .take_while(|c| classifier.is_word(*c))
21235                .collect::<String>();
21236            last_word = last_word.chars().rev().collect();
21237
21238            if last_word.is_empty() {
21239                return Ok(CompletionResponse {
21240                    completions: vec![],
21241                    is_incomplete: true,
21242                });
21243            }
21244
21245            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21246            let to_lsp = |point: &text::Anchor| {
21247                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21248                point_to_lsp(end)
21249            };
21250            let lsp_end = to_lsp(&buffer_position);
21251
21252            let candidates = snippets
21253                .iter()
21254                .enumerate()
21255                .flat_map(|(ix, snippet)| {
21256                    snippet
21257                        .prefix
21258                        .iter()
21259                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21260                })
21261                .collect::<Vec<StringMatchCandidate>>();
21262
21263            const MAX_RESULTS: usize = 100;
21264            let mut matches = fuzzy::match_strings(
21265                &candidates,
21266                &last_word,
21267                last_word.chars().any(|c| c.is_uppercase()),
21268                true,
21269                MAX_RESULTS,
21270                &Default::default(),
21271                executor.clone(),
21272            )
21273            .await;
21274
21275            if matches.len() >= MAX_RESULTS {
21276                is_incomplete = true;
21277            }
21278
21279            // Remove all candidates where the query's start does not match the start of any word in the candidate
21280            if let Some(query_start) = last_word.chars().next() {
21281                matches.retain(|string_match| {
21282                    split_words(&string_match.string).any(|word| {
21283                        // Check that the first codepoint of the word as lowercase matches the first
21284                        // codepoint of the query as lowercase
21285                        word.chars()
21286                            .flat_map(|codepoint| codepoint.to_lowercase())
21287                            .zip(query_start.to_lowercase())
21288                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21289                    })
21290                });
21291            }
21292
21293            let matched_strings = matches
21294                .into_iter()
21295                .map(|m| m.string)
21296                .collect::<HashSet<_>>();
21297
21298            completions.extend(snippets.iter().filter_map(|snippet| {
21299                let matching_prefix = snippet
21300                    .prefix
21301                    .iter()
21302                    .find(|prefix| matched_strings.contains(*prefix))?;
21303                let start = as_offset - last_word.len();
21304                let start = snapshot.anchor_before(start);
21305                let range = start..buffer_position;
21306                let lsp_start = to_lsp(&start);
21307                let lsp_range = lsp::Range {
21308                    start: lsp_start,
21309                    end: lsp_end,
21310                };
21311                Some(Completion {
21312                    replace_range: range,
21313                    new_text: snippet.body.clone(),
21314                    source: CompletionSource::Lsp {
21315                        insert_range: None,
21316                        server_id: LanguageServerId(usize::MAX),
21317                        resolved: true,
21318                        lsp_completion: Box::new(lsp::CompletionItem {
21319                            label: snippet.prefix.first().unwrap().clone(),
21320                            kind: Some(CompletionItemKind::SNIPPET),
21321                            label_details: snippet.description.as_ref().map(|description| {
21322                                lsp::CompletionItemLabelDetails {
21323                                    detail: Some(description.clone()),
21324                                    description: None,
21325                                }
21326                            }),
21327                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21328                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21329                                lsp::InsertReplaceEdit {
21330                                    new_text: snippet.body.clone(),
21331                                    insert: lsp_range,
21332                                    replace: lsp_range,
21333                                },
21334                            )),
21335                            filter_text: Some(snippet.body.clone()),
21336                            sort_text: Some(char::MAX.to_string()),
21337                            ..lsp::CompletionItem::default()
21338                        }),
21339                        lsp_defaults: None,
21340                    },
21341                    label: CodeLabel {
21342                        text: matching_prefix.clone(),
21343                        runs: Vec::new(),
21344                        filter_range: 0..matching_prefix.len(),
21345                    },
21346                    icon_path: None,
21347                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21348                        single_line: snippet.name.clone().into(),
21349                        plain_text: snippet
21350                            .description
21351                            .clone()
21352                            .map(|description| description.into()),
21353                    }),
21354                    insert_text_mode: None,
21355                    confirm: None,
21356                })
21357            }))
21358        }
21359
21360        Ok(CompletionResponse {
21361            completions,
21362            is_incomplete,
21363        })
21364    })
21365}
21366
21367impl CompletionProvider for Entity<Project> {
21368    fn completions(
21369        &self,
21370        _excerpt_id: ExcerptId,
21371        buffer: &Entity<Buffer>,
21372        buffer_position: text::Anchor,
21373        options: CompletionContext,
21374        _window: &mut Window,
21375        cx: &mut Context<Editor>,
21376    ) -> Task<Result<Vec<CompletionResponse>>> {
21377        self.update(cx, |project, cx| {
21378            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21379            let project_completions = project.completions(buffer, buffer_position, options, cx);
21380            cx.background_spawn(async move {
21381                let mut responses = project_completions.await?;
21382                let snippets = snippets.await?;
21383                if !snippets.completions.is_empty() {
21384                    responses.push(snippets);
21385                }
21386                Ok(responses)
21387            })
21388        })
21389    }
21390
21391    fn resolve_completions(
21392        &self,
21393        buffer: Entity<Buffer>,
21394        completion_indices: Vec<usize>,
21395        completions: Rc<RefCell<Box<[Completion]>>>,
21396        cx: &mut Context<Editor>,
21397    ) -> Task<Result<bool>> {
21398        self.update(cx, |project, cx| {
21399            project.lsp_store().update(cx, |lsp_store, cx| {
21400                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21401            })
21402        })
21403    }
21404
21405    fn apply_additional_edits_for_completion(
21406        &self,
21407        buffer: Entity<Buffer>,
21408        completions: Rc<RefCell<Box<[Completion]>>>,
21409        completion_index: usize,
21410        push_to_history: bool,
21411        cx: &mut Context<Editor>,
21412    ) -> Task<Result<Option<language::Transaction>>> {
21413        self.update(cx, |project, cx| {
21414            project.lsp_store().update(cx, |lsp_store, cx| {
21415                lsp_store.apply_additional_edits_for_completion(
21416                    buffer,
21417                    completions,
21418                    completion_index,
21419                    push_to_history,
21420                    cx,
21421                )
21422            })
21423        })
21424    }
21425
21426    fn is_completion_trigger(
21427        &self,
21428        buffer: &Entity<Buffer>,
21429        position: language::Anchor,
21430        text: &str,
21431        trigger_in_words: bool,
21432        menu_is_open: bool,
21433        cx: &mut Context<Editor>,
21434    ) -> bool {
21435        let mut chars = text.chars();
21436        let char = if let Some(char) = chars.next() {
21437            char
21438        } else {
21439            return false;
21440        };
21441        if chars.next().is_some() {
21442            return false;
21443        }
21444
21445        let buffer = buffer.read(cx);
21446        let snapshot = buffer.snapshot();
21447        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21448            return false;
21449        }
21450        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21451        if trigger_in_words && classifier.is_word(char) {
21452            return true;
21453        }
21454
21455        buffer.completion_triggers().contains(text)
21456    }
21457}
21458
21459impl SemanticsProvider for Entity<Project> {
21460    fn hover(
21461        &self,
21462        buffer: &Entity<Buffer>,
21463        position: text::Anchor,
21464        cx: &mut App,
21465    ) -> Option<Task<Vec<project::Hover>>> {
21466        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21467    }
21468
21469    fn document_highlights(
21470        &self,
21471        buffer: &Entity<Buffer>,
21472        position: text::Anchor,
21473        cx: &mut App,
21474    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21475        Some(self.update(cx, |project, cx| {
21476            project.document_highlights(buffer, position, cx)
21477        }))
21478    }
21479
21480    fn definitions(
21481        &self,
21482        buffer: &Entity<Buffer>,
21483        position: text::Anchor,
21484        kind: GotoDefinitionKind,
21485        cx: &mut App,
21486    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21487        Some(self.update(cx, |project, cx| match kind {
21488            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21489            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21490            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21491            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21492        }))
21493    }
21494
21495    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21496        // TODO: make this work for remote projects
21497        self.update(cx, |project, cx| {
21498            if project
21499                .active_debug_session(cx)
21500                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21501            {
21502                return true;
21503            }
21504
21505            buffer.update(cx, |buffer, cx| {
21506                project.any_language_server_supports_inlay_hints(buffer, cx)
21507            })
21508        })
21509    }
21510
21511    fn inline_values(
21512        &self,
21513        buffer_handle: Entity<Buffer>,
21514
21515        range: Range<text::Anchor>,
21516        cx: &mut App,
21517    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21518        self.update(cx, |project, cx| {
21519            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21520
21521            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21522        })
21523    }
21524
21525    fn inlay_hints(
21526        &self,
21527        buffer_handle: Entity<Buffer>,
21528        range: Range<text::Anchor>,
21529        cx: &mut App,
21530    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21531        Some(self.update(cx, |project, cx| {
21532            project.inlay_hints(buffer_handle, range, cx)
21533        }))
21534    }
21535
21536    fn resolve_inlay_hint(
21537        &self,
21538        hint: InlayHint,
21539        buffer_handle: Entity<Buffer>,
21540        server_id: LanguageServerId,
21541        cx: &mut App,
21542    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21543        Some(self.update(cx, |project, cx| {
21544            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21545        }))
21546    }
21547
21548    fn range_for_rename(
21549        &self,
21550        buffer: &Entity<Buffer>,
21551        position: text::Anchor,
21552        cx: &mut App,
21553    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21554        Some(self.update(cx, |project, cx| {
21555            let buffer = buffer.clone();
21556            let task = project.prepare_rename(buffer.clone(), position, cx);
21557            cx.spawn(async move |_, cx| {
21558                Ok(match task.await? {
21559                    PrepareRenameResponse::Success(range) => Some(range),
21560                    PrepareRenameResponse::InvalidPosition => None,
21561                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21562                        // Fallback on using TreeSitter info to determine identifier range
21563                        buffer.read_with(cx, |buffer, _| {
21564                            let snapshot = buffer.snapshot();
21565                            let (range, kind) = snapshot.surrounding_word(position);
21566                            if kind != Some(CharKind::Word) {
21567                                return None;
21568                            }
21569                            Some(
21570                                snapshot.anchor_before(range.start)
21571                                    ..snapshot.anchor_after(range.end),
21572                            )
21573                        })?
21574                    }
21575                })
21576            })
21577        }))
21578    }
21579
21580    fn perform_rename(
21581        &self,
21582        buffer: &Entity<Buffer>,
21583        position: text::Anchor,
21584        new_name: String,
21585        cx: &mut App,
21586    ) -> Option<Task<Result<ProjectTransaction>>> {
21587        Some(self.update(cx, |project, cx| {
21588            project.perform_rename(buffer.clone(), position, new_name, cx)
21589        }))
21590    }
21591}
21592
21593fn inlay_hint_settings(
21594    location: Anchor,
21595    snapshot: &MultiBufferSnapshot,
21596    cx: &mut Context<Editor>,
21597) -> InlayHintSettings {
21598    let file = snapshot.file_at(location);
21599    let language = snapshot.language_at(location).map(|l| l.name());
21600    language_settings(language, file, cx).inlay_hints
21601}
21602
21603fn consume_contiguous_rows(
21604    contiguous_row_selections: &mut Vec<Selection<Point>>,
21605    selection: &Selection<Point>,
21606    display_map: &DisplaySnapshot,
21607    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21608) -> (MultiBufferRow, MultiBufferRow) {
21609    contiguous_row_selections.push(selection.clone());
21610    let start_row = MultiBufferRow(selection.start.row);
21611    let mut end_row = ending_row(selection, display_map);
21612
21613    while let Some(next_selection) = selections.peek() {
21614        if next_selection.start.row <= end_row.0 {
21615            end_row = ending_row(next_selection, display_map);
21616            contiguous_row_selections.push(selections.next().unwrap().clone());
21617        } else {
21618            break;
21619        }
21620    }
21621    (start_row, end_row)
21622}
21623
21624fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21625    if next_selection.end.column > 0 || next_selection.is_empty() {
21626        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21627    } else {
21628        MultiBufferRow(next_selection.end.row)
21629    }
21630}
21631
21632impl EditorSnapshot {
21633    pub fn remote_selections_in_range<'a>(
21634        &'a self,
21635        range: &'a Range<Anchor>,
21636        collaboration_hub: &dyn CollaborationHub,
21637        cx: &'a App,
21638    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21639        let participant_names = collaboration_hub.user_names(cx);
21640        let participant_indices = collaboration_hub.user_participant_indices(cx);
21641        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21642        let collaborators_by_replica_id = collaborators_by_peer_id
21643            .values()
21644            .map(|collaborator| (collaborator.replica_id, collaborator))
21645            .collect::<HashMap<_, _>>();
21646        self.buffer_snapshot
21647            .selections_in_range(range, false)
21648            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21649                if replica_id == AGENT_REPLICA_ID {
21650                    Some(RemoteSelection {
21651                        replica_id,
21652                        selection,
21653                        cursor_shape,
21654                        line_mode,
21655                        collaborator_id: CollaboratorId::Agent,
21656                        user_name: Some("Agent".into()),
21657                        color: cx.theme().players().agent(),
21658                    })
21659                } else {
21660                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21661                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21662                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21663                    Some(RemoteSelection {
21664                        replica_id,
21665                        selection,
21666                        cursor_shape,
21667                        line_mode,
21668                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21669                        user_name,
21670                        color: if let Some(index) = participant_index {
21671                            cx.theme().players().color_for_participant(index.0)
21672                        } else {
21673                            cx.theme().players().absent()
21674                        },
21675                    })
21676                }
21677            })
21678    }
21679
21680    pub fn hunks_for_ranges(
21681        &self,
21682        ranges: impl IntoIterator<Item = Range<Point>>,
21683    ) -> Vec<MultiBufferDiffHunk> {
21684        let mut hunks = Vec::new();
21685        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21686            HashMap::default();
21687        for query_range in ranges {
21688            let query_rows =
21689                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21690            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21691                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21692            ) {
21693                // Include deleted hunks that are adjacent to the query range, because
21694                // otherwise they would be missed.
21695                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21696                if hunk.status().is_deleted() {
21697                    intersects_range |= hunk.row_range.start == query_rows.end;
21698                    intersects_range |= hunk.row_range.end == query_rows.start;
21699                }
21700                if intersects_range {
21701                    if !processed_buffer_rows
21702                        .entry(hunk.buffer_id)
21703                        .or_default()
21704                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21705                    {
21706                        continue;
21707                    }
21708                    hunks.push(hunk);
21709                }
21710            }
21711        }
21712
21713        hunks
21714    }
21715
21716    fn display_diff_hunks_for_rows<'a>(
21717        &'a self,
21718        display_rows: Range<DisplayRow>,
21719        folded_buffers: &'a HashSet<BufferId>,
21720    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21721        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21722        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21723
21724        self.buffer_snapshot
21725            .diff_hunks_in_range(buffer_start..buffer_end)
21726            .filter_map(|hunk| {
21727                if folded_buffers.contains(&hunk.buffer_id) {
21728                    return None;
21729                }
21730
21731                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21732                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21733
21734                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21735                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21736
21737                let display_hunk = if hunk_display_start.column() != 0 {
21738                    DisplayDiffHunk::Folded {
21739                        display_row: hunk_display_start.row(),
21740                    }
21741                } else {
21742                    let mut end_row = hunk_display_end.row();
21743                    if hunk_display_end.column() > 0 {
21744                        end_row.0 += 1;
21745                    }
21746                    let is_created_file = hunk.is_created_file();
21747                    DisplayDiffHunk::Unfolded {
21748                        status: hunk.status(),
21749                        diff_base_byte_range: hunk.diff_base_byte_range,
21750                        display_row_range: hunk_display_start.row()..end_row,
21751                        multi_buffer_range: Anchor::range_in_buffer(
21752                            hunk.excerpt_id,
21753                            hunk.buffer_id,
21754                            hunk.buffer_range,
21755                        ),
21756                        is_created_file,
21757                    }
21758                };
21759
21760                Some(display_hunk)
21761            })
21762    }
21763
21764    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21765        self.display_snapshot.buffer_snapshot.language_at(position)
21766    }
21767
21768    pub fn is_focused(&self) -> bool {
21769        self.is_focused
21770    }
21771
21772    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21773        self.placeholder_text.as_ref()
21774    }
21775
21776    pub fn scroll_position(&self) -> gpui::Point<f32> {
21777        self.scroll_anchor.scroll_position(&self.display_snapshot)
21778    }
21779
21780    fn gutter_dimensions(
21781        &self,
21782        font_id: FontId,
21783        font_size: Pixels,
21784        max_line_number_width: Pixels,
21785        cx: &App,
21786    ) -> Option<GutterDimensions> {
21787        if !self.show_gutter {
21788            return None;
21789        }
21790
21791        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21792        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21793
21794        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21795            matches!(
21796                ProjectSettings::get_global(cx).git.git_gutter,
21797                Some(GitGutterSetting::TrackedFiles)
21798            )
21799        });
21800        let gutter_settings = EditorSettings::get_global(cx).gutter;
21801        let show_line_numbers = self
21802            .show_line_numbers
21803            .unwrap_or(gutter_settings.line_numbers);
21804        let line_gutter_width = if show_line_numbers {
21805            // Avoid flicker-like gutter resizes when the line number gains another digit by
21806            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21807            let min_width_for_number_on_gutter =
21808                ch_advance * gutter_settings.min_line_number_digits as f32;
21809            max_line_number_width.max(min_width_for_number_on_gutter)
21810        } else {
21811            0.0.into()
21812        };
21813
21814        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21815        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21816
21817        let git_blame_entries_width =
21818            self.git_blame_gutter_max_author_length
21819                .map(|max_author_length| {
21820                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21821                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21822
21823                    /// The number of characters to dedicate to gaps and margins.
21824                    const SPACING_WIDTH: usize = 4;
21825
21826                    let max_char_count = max_author_length.min(renderer.max_author_length())
21827                        + ::git::SHORT_SHA_LENGTH
21828                        + MAX_RELATIVE_TIMESTAMP.len()
21829                        + SPACING_WIDTH;
21830
21831                    ch_advance * max_char_count
21832                });
21833
21834        let is_singleton = self.buffer_snapshot.is_singleton();
21835
21836        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21837        left_padding += if !is_singleton {
21838            ch_width * 4.0
21839        } else if show_runnables || show_breakpoints {
21840            ch_width * 3.0
21841        } else if show_git_gutter && show_line_numbers {
21842            ch_width * 2.0
21843        } else if show_git_gutter || show_line_numbers {
21844            ch_width
21845        } else {
21846            px(0.)
21847        };
21848
21849        let shows_folds = is_singleton && gutter_settings.folds;
21850
21851        let right_padding = if shows_folds && show_line_numbers {
21852            ch_width * 4.0
21853        } else if shows_folds || (!is_singleton && show_line_numbers) {
21854            ch_width * 3.0
21855        } else if show_line_numbers {
21856            ch_width
21857        } else {
21858            px(0.)
21859        };
21860
21861        Some(GutterDimensions {
21862            left_padding,
21863            right_padding,
21864            width: line_gutter_width + left_padding + right_padding,
21865            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21866            git_blame_entries_width,
21867        })
21868    }
21869
21870    pub fn render_crease_toggle(
21871        &self,
21872        buffer_row: MultiBufferRow,
21873        row_contains_cursor: bool,
21874        editor: Entity<Editor>,
21875        window: &mut Window,
21876        cx: &mut App,
21877    ) -> Option<AnyElement> {
21878        let folded = self.is_line_folded(buffer_row);
21879        let mut is_foldable = false;
21880
21881        if let Some(crease) = self
21882            .crease_snapshot
21883            .query_row(buffer_row, &self.buffer_snapshot)
21884        {
21885            is_foldable = true;
21886            match crease {
21887                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21888                    if let Some(render_toggle) = render_toggle {
21889                        let toggle_callback =
21890                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21891                                if folded {
21892                                    editor.update(cx, |editor, cx| {
21893                                        editor.fold_at(buffer_row, window, cx)
21894                                    });
21895                                } else {
21896                                    editor.update(cx, |editor, cx| {
21897                                        editor.unfold_at(buffer_row, window, cx)
21898                                    });
21899                                }
21900                            });
21901                        return Some((render_toggle)(
21902                            buffer_row,
21903                            folded,
21904                            toggle_callback,
21905                            window,
21906                            cx,
21907                        ));
21908                    }
21909                }
21910            }
21911        }
21912
21913        is_foldable |= self.starts_indent(buffer_row);
21914
21915        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21916            Some(
21917                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21918                    .toggle_state(folded)
21919                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21920                        if folded {
21921                            this.unfold_at(buffer_row, window, cx);
21922                        } else {
21923                            this.fold_at(buffer_row, window, cx);
21924                        }
21925                    }))
21926                    .into_any_element(),
21927            )
21928        } else {
21929            None
21930        }
21931    }
21932
21933    pub fn render_crease_trailer(
21934        &self,
21935        buffer_row: MultiBufferRow,
21936        window: &mut Window,
21937        cx: &mut App,
21938    ) -> Option<AnyElement> {
21939        let folded = self.is_line_folded(buffer_row);
21940        if let Crease::Inline { render_trailer, .. } = self
21941            .crease_snapshot
21942            .query_row(buffer_row, &self.buffer_snapshot)?
21943        {
21944            let render_trailer = render_trailer.as_ref()?;
21945            Some(render_trailer(buffer_row, folded, window, cx))
21946        } else {
21947            None
21948        }
21949    }
21950}
21951
21952impl Deref for EditorSnapshot {
21953    type Target = DisplaySnapshot;
21954
21955    fn deref(&self) -> &Self::Target {
21956        &self.display_snapshot
21957    }
21958}
21959
21960#[derive(Clone, Debug, PartialEq, Eq)]
21961pub enum EditorEvent {
21962    InputIgnored {
21963        text: Arc<str>,
21964    },
21965    InputHandled {
21966        utf16_range_to_replace: Option<Range<isize>>,
21967        text: Arc<str>,
21968    },
21969    ExcerptsAdded {
21970        buffer: Entity<Buffer>,
21971        predecessor: ExcerptId,
21972        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21973    },
21974    ExcerptsRemoved {
21975        ids: Vec<ExcerptId>,
21976        removed_buffer_ids: Vec<BufferId>,
21977    },
21978    BufferFoldToggled {
21979        ids: Vec<ExcerptId>,
21980        folded: bool,
21981    },
21982    ExcerptsEdited {
21983        ids: Vec<ExcerptId>,
21984    },
21985    ExcerptsExpanded {
21986        ids: Vec<ExcerptId>,
21987    },
21988    BufferEdited,
21989    Edited {
21990        transaction_id: clock::Lamport,
21991    },
21992    Reparsed(BufferId),
21993    Focused,
21994    FocusedIn,
21995    Blurred,
21996    DirtyChanged,
21997    Saved,
21998    TitleChanged,
21999    DiffBaseChanged,
22000    SelectionsChanged {
22001        local: bool,
22002    },
22003    ScrollPositionChanged {
22004        local: bool,
22005        autoscroll: bool,
22006    },
22007    Closed,
22008    TransactionUndone {
22009        transaction_id: clock::Lamport,
22010    },
22011    TransactionBegun {
22012        transaction_id: clock::Lamport,
22013    },
22014    Reloaded,
22015    CursorShapeChanged,
22016    PushedToNavHistory {
22017        anchor: Anchor,
22018        is_deactivate: bool,
22019    },
22020}
22021
22022impl EventEmitter<EditorEvent> for Editor {}
22023
22024impl Focusable for Editor {
22025    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22026        self.focus_handle.clone()
22027    }
22028}
22029
22030impl Render for Editor {
22031    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22032        let settings = ThemeSettings::get_global(cx);
22033
22034        let mut text_style = match self.mode {
22035            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22036                color: cx.theme().colors().editor_foreground,
22037                font_family: settings.ui_font.family.clone(),
22038                font_features: settings.ui_font.features.clone(),
22039                font_fallbacks: settings.ui_font.fallbacks.clone(),
22040                font_size: rems(0.875).into(),
22041                font_weight: settings.ui_font.weight,
22042                line_height: relative(settings.buffer_line_height.value()),
22043                ..Default::default()
22044            },
22045            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22046                color: cx.theme().colors().editor_foreground,
22047                font_family: settings.buffer_font.family.clone(),
22048                font_features: settings.buffer_font.features.clone(),
22049                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22050                font_size: settings.buffer_font_size(cx).into(),
22051                font_weight: settings.buffer_font.weight,
22052                line_height: relative(settings.buffer_line_height.value()),
22053                ..Default::default()
22054            },
22055        };
22056        if let Some(text_style_refinement) = &self.text_style_refinement {
22057            text_style.refine(text_style_refinement)
22058        }
22059
22060        let background = match self.mode {
22061            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22062            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22063            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22064            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22065        };
22066
22067        EditorElement::new(
22068            &cx.entity(),
22069            EditorStyle {
22070                background,
22071                local_player: cx.theme().players().local(),
22072                text: text_style,
22073                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22074                syntax: cx.theme().syntax().clone(),
22075                status: cx.theme().status().clone(),
22076                inlay_hints_style: make_inlay_hints_style(cx),
22077                inline_completion_styles: make_suggestion_styles(cx),
22078                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22079                show_underlines: !self.mode.is_minimap(),
22080            },
22081        )
22082    }
22083}
22084
22085impl EntityInputHandler for Editor {
22086    fn text_for_range(
22087        &mut self,
22088        range_utf16: Range<usize>,
22089        adjusted_range: &mut Option<Range<usize>>,
22090        _: &mut Window,
22091        cx: &mut Context<Self>,
22092    ) -> Option<String> {
22093        let snapshot = self.buffer.read(cx).read(cx);
22094        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22095        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22096        if (start.0..end.0) != range_utf16 {
22097            adjusted_range.replace(start.0..end.0);
22098        }
22099        Some(snapshot.text_for_range(start..end).collect())
22100    }
22101
22102    fn selected_text_range(
22103        &mut self,
22104        ignore_disabled_input: bool,
22105        _: &mut Window,
22106        cx: &mut Context<Self>,
22107    ) -> Option<UTF16Selection> {
22108        // Prevent the IME menu from appearing when holding down an alphabetic key
22109        // while input is disabled.
22110        if !ignore_disabled_input && !self.input_enabled {
22111            return None;
22112        }
22113
22114        let selection = self.selections.newest::<OffsetUtf16>(cx);
22115        let range = selection.range();
22116
22117        Some(UTF16Selection {
22118            range: range.start.0..range.end.0,
22119            reversed: selection.reversed,
22120        })
22121    }
22122
22123    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22124        let snapshot = self.buffer.read(cx).read(cx);
22125        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22126        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22127    }
22128
22129    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22130        self.clear_highlights::<InputComposition>(cx);
22131        self.ime_transaction.take();
22132    }
22133
22134    fn replace_text_in_range(
22135        &mut self,
22136        range_utf16: Option<Range<usize>>,
22137        text: &str,
22138        window: &mut Window,
22139        cx: &mut Context<Self>,
22140    ) {
22141        if !self.input_enabled {
22142            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22143            return;
22144        }
22145
22146        self.transact(window, cx, |this, window, cx| {
22147            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22148                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22149                Some(this.selection_replacement_ranges(range_utf16, cx))
22150            } else {
22151                this.marked_text_ranges(cx)
22152            };
22153
22154            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22155                let newest_selection_id = this.selections.newest_anchor().id;
22156                this.selections
22157                    .all::<OffsetUtf16>(cx)
22158                    .iter()
22159                    .zip(ranges_to_replace.iter())
22160                    .find_map(|(selection, range)| {
22161                        if selection.id == newest_selection_id {
22162                            Some(
22163                                (range.start.0 as isize - selection.head().0 as isize)
22164                                    ..(range.end.0 as isize - selection.head().0 as isize),
22165                            )
22166                        } else {
22167                            None
22168                        }
22169                    })
22170            });
22171
22172            cx.emit(EditorEvent::InputHandled {
22173                utf16_range_to_replace: range_to_replace,
22174                text: text.into(),
22175            });
22176
22177            if let Some(new_selected_ranges) = new_selected_ranges {
22178                this.change_selections(None, window, cx, |selections| {
22179                    selections.select_ranges(new_selected_ranges)
22180                });
22181                this.backspace(&Default::default(), window, cx);
22182            }
22183
22184            this.handle_input(text, window, cx);
22185        });
22186
22187        if let Some(transaction) = self.ime_transaction {
22188            self.buffer.update(cx, |buffer, cx| {
22189                buffer.group_until_transaction(transaction, cx);
22190            });
22191        }
22192
22193        self.unmark_text(window, cx);
22194    }
22195
22196    fn replace_and_mark_text_in_range(
22197        &mut self,
22198        range_utf16: Option<Range<usize>>,
22199        text: &str,
22200        new_selected_range_utf16: Option<Range<usize>>,
22201        window: &mut Window,
22202        cx: &mut Context<Self>,
22203    ) {
22204        if !self.input_enabled {
22205            return;
22206        }
22207
22208        let transaction = self.transact(window, cx, |this, window, cx| {
22209            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22210                let snapshot = this.buffer.read(cx).read(cx);
22211                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22212                    for marked_range in &mut marked_ranges {
22213                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22214                        marked_range.start.0 += relative_range_utf16.start;
22215                        marked_range.start =
22216                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22217                        marked_range.end =
22218                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22219                    }
22220                }
22221                Some(marked_ranges)
22222            } else if let Some(range_utf16) = range_utf16 {
22223                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22224                Some(this.selection_replacement_ranges(range_utf16, cx))
22225            } else {
22226                None
22227            };
22228
22229            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22230                let newest_selection_id = this.selections.newest_anchor().id;
22231                this.selections
22232                    .all::<OffsetUtf16>(cx)
22233                    .iter()
22234                    .zip(ranges_to_replace.iter())
22235                    .find_map(|(selection, range)| {
22236                        if selection.id == newest_selection_id {
22237                            Some(
22238                                (range.start.0 as isize - selection.head().0 as isize)
22239                                    ..(range.end.0 as isize - selection.head().0 as isize),
22240                            )
22241                        } else {
22242                            None
22243                        }
22244                    })
22245            });
22246
22247            cx.emit(EditorEvent::InputHandled {
22248                utf16_range_to_replace: range_to_replace,
22249                text: text.into(),
22250            });
22251
22252            if let Some(ranges) = ranges_to_replace {
22253                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22254            }
22255
22256            let marked_ranges = {
22257                let snapshot = this.buffer.read(cx).read(cx);
22258                this.selections
22259                    .disjoint_anchors()
22260                    .iter()
22261                    .map(|selection| {
22262                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22263                    })
22264                    .collect::<Vec<_>>()
22265            };
22266
22267            if text.is_empty() {
22268                this.unmark_text(window, cx);
22269            } else {
22270                this.highlight_text::<InputComposition>(
22271                    marked_ranges.clone(),
22272                    HighlightStyle {
22273                        underline: Some(UnderlineStyle {
22274                            thickness: px(1.),
22275                            color: None,
22276                            wavy: false,
22277                        }),
22278                        ..Default::default()
22279                    },
22280                    cx,
22281                );
22282            }
22283
22284            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22285            let use_autoclose = this.use_autoclose;
22286            let use_auto_surround = this.use_auto_surround;
22287            this.set_use_autoclose(false);
22288            this.set_use_auto_surround(false);
22289            this.handle_input(text, window, cx);
22290            this.set_use_autoclose(use_autoclose);
22291            this.set_use_auto_surround(use_auto_surround);
22292
22293            if let Some(new_selected_range) = new_selected_range_utf16 {
22294                let snapshot = this.buffer.read(cx).read(cx);
22295                let new_selected_ranges = marked_ranges
22296                    .into_iter()
22297                    .map(|marked_range| {
22298                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22299                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22300                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22301                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22302                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22303                    })
22304                    .collect::<Vec<_>>();
22305
22306                drop(snapshot);
22307                this.change_selections(None, window, cx, |selections| {
22308                    selections.select_ranges(new_selected_ranges)
22309                });
22310            }
22311        });
22312
22313        self.ime_transaction = self.ime_transaction.or(transaction);
22314        if let Some(transaction) = self.ime_transaction {
22315            self.buffer.update(cx, |buffer, cx| {
22316                buffer.group_until_transaction(transaction, cx);
22317            });
22318        }
22319
22320        if self.text_highlights::<InputComposition>(cx).is_none() {
22321            self.ime_transaction.take();
22322        }
22323    }
22324
22325    fn bounds_for_range(
22326        &mut self,
22327        range_utf16: Range<usize>,
22328        element_bounds: gpui::Bounds<Pixels>,
22329        window: &mut Window,
22330        cx: &mut Context<Self>,
22331    ) -> Option<gpui::Bounds<Pixels>> {
22332        let text_layout_details = self.text_layout_details(window);
22333        let gpui::Size {
22334            width: em_width,
22335            height: line_height,
22336        } = self.character_size(window);
22337
22338        let snapshot = self.snapshot(window, cx);
22339        let scroll_position = snapshot.scroll_position();
22340        let scroll_left = scroll_position.x * em_width;
22341
22342        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22343        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22344            + self.gutter_dimensions.width
22345            + self.gutter_dimensions.margin;
22346        let y = line_height * (start.row().as_f32() - scroll_position.y);
22347
22348        Some(Bounds {
22349            origin: element_bounds.origin + point(x, y),
22350            size: size(em_width, line_height),
22351        })
22352    }
22353
22354    fn character_index_for_point(
22355        &mut self,
22356        point: gpui::Point<Pixels>,
22357        _window: &mut Window,
22358        _cx: &mut Context<Self>,
22359    ) -> Option<usize> {
22360        let position_map = self.last_position_map.as_ref()?;
22361        if !position_map.text_hitbox.contains(&point) {
22362            return None;
22363        }
22364        let display_point = position_map.point_for_position(point).previous_valid;
22365        let anchor = position_map
22366            .snapshot
22367            .display_point_to_anchor(display_point, Bias::Left);
22368        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22369        Some(utf16_offset.0)
22370    }
22371}
22372
22373trait SelectionExt {
22374    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22375    fn spanned_rows(
22376        &self,
22377        include_end_if_at_line_start: bool,
22378        map: &DisplaySnapshot,
22379    ) -> Range<MultiBufferRow>;
22380}
22381
22382impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22383    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22384        let start = self
22385            .start
22386            .to_point(&map.buffer_snapshot)
22387            .to_display_point(map);
22388        let end = self
22389            .end
22390            .to_point(&map.buffer_snapshot)
22391            .to_display_point(map);
22392        if self.reversed {
22393            end..start
22394        } else {
22395            start..end
22396        }
22397    }
22398
22399    fn spanned_rows(
22400        &self,
22401        include_end_if_at_line_start: bool,
22402        map: &DisplaySnapshot,
22403    ) -> Range<MultiBufferRow> {
22404        let start = self.start.to_point(&map.buffer_snapshot);
22405        let mut end = self.end.to_point(&map.buffer_snapshot);
22406        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22407            end.row -= 1;
22408        }
22409
22410        let buffer_start = map.prev_line_boundary(start).0;
22411        let buffer_end = map.next_line_boundary(end).0;
22412        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22413    }
22414}
22415
22416impl<T: InvalidationRegion> InvalidationStack<T> {
22417    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22418    where
22419        S: Clone + ToOffset,
22420    {
22421        while let Some(region) = self.last() {
22422            let all_selections_inside_invalidation_ranges =
22423                if selections.len() == region.ranges().len() {
22424                    selections
22425                        .iter()
22426                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22427                        .all(|(selection, invalidation_range)| {
22428                            let head = selection.head().to_offset(buffer);
22429                            invalidation_range.start <= head && invalidation_range.end >= head
22430                        })
22431                } else {
22432                    false
22433                };
22434
22435            if all_selections_inside_invalidation_ranges {
22436                break;
22437            } else {
22438                self.pop();
22439            }
22440        }
22441    }
22442}
22443
22444impl<T> Default for InvalidationStack<T> {
22445    fn default() -> Self {
22446        Self(Default::default())
22447    }
22448}
22449
22450impl<T> Deref for InvalidationStack<T> {
22451    type Target = Vec<T>;
22452
22453    fn deref(&self) -> &Self::Target {
22454        &self.0
22455    }
22456}
22457
22458impl<T> DerefMut for InvalidationStack<T> {
22459    fn deref_mut(&mut self) -> &mut Self::Target {
22460        &mut self.0
22461    }
22462}
22463
22464impl InvalidationRegion for SnippetState {
22465    fn ranges(&self) -> &[Range<Anchor>] {
22466        &self.ranges[self.active_index]
22467    }
22468}
22469
22470fn inline_completion_edit_text(
22471    current_snapshot: &BufferSnapshot,
22472    edits: &[(Range<Anchor>, String)],
22473    edit_preview: &EditPreview,
22474    include_deletions: bool,
22475    cx: &App,
22476) -> HighlightedText {
22477    let edits = edits
22478        .iter()
22479        .map(|(anchor, text)| {
22480            (
22481                anchor.start.text_anchor..anchor.end.text_anchor,
22482                text.clone(),
22483            )
22484        })
22485        .collect::<Vec<_>>();
22486
22487    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22488}
22489
22490pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22491    match severity {
22492        lsp::DiagnosticSeverity::ERROR => colors.error,
22493        lsp::DiagnosticSeverity::WARNING => colors.warning,
22494        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22495        lsp::DiagnosticSeverity::HINT => colors.info,
22496        _ => colors.ignored,
22497    }
22498}
22499
22500pub fn styled_runs_for_code_label<'a>(
22501    label: &'a CodeLabel,
22502    syntax_theme: &'a theme::SyntaxTheme,
22503) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22504    let fade_out = HighlightStyle {
22505        fade_out: Some(0.35),
22506        ..Default::default()
22507    };
22508
22509    let mut prev_end = label.filter_range.end;
22510    label
22511        .runs
22512        .iter()
22513        .enumerate()
22514        .flat_map(move |(ix, (range, highlight_id))| {
22515            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22516                style
22517            } else {
22518                return Default::default();
22519            };
22520            let mut muted_style = style;
22521            muted_style.highlight(fade_out);
22522
22523            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22524            if range.start >= label.filter_range.end {
22525                if range.start > prev_end {
22526                    runs.push((prev_end..range.start, fade_out));
22527                }
22528                runs.push((range.clone(), muted_style));
22529            } else if range.end <= label.filter_range.end {
22530                runs.push((range.clone(), style));
22531            } else {
22532                runs.push((range.start..label.filter_range.end, style));
22533                runs.push((label.filter_range.end..range.end, muted_style));
22534            }
22535            prev_end = cmp::max(prev_end, range.end);
22536
22537            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22538                runs.push((prev_end..label.text.len(), fade_out));
22539            }
22540
22541            runs
22542        })
22543}
22544
22545pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22546    let mut prev_index = 0;
22547    let mut prev_codepoint: Option<char> = None;
22548    text.char_indices()
22549        .chain([(text.len(), '\0')])
22550        .filter_map(move |(index, codepoint)| {
22551            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22552            let is_boundary = index == text.len()
22553                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22554                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22555            if is_boundary {
22556                let chunk = &text[prev_index..index];
22557                prev_index = index;
22558                Some(chunk)
22559            } else {
22560                None
22561            }
22562        })
22563}
22564
22565pub trait RangeToAnchorExt: Sized {
22566    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22567
22568    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22569        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22570        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22571    }
22572}
22573
22574impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22575    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22576        let start_offset = self.start.to_offset(snapshot);
22577        let end_offset = self.end.to_offset(snapshot);
22578        if start_offset == end_offset {
22579            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22580        } else {
22581            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22582        }
22583    }
22584}
22585
22586pub trait RowExt {
22587    fn as_f32(&self) -> f32;
22588
22589    fn next_row(&self) -> Self;
22590
22591    fn previous_row(&self) -> Self;
22592
22593    fn minus(&self, other: Self) -> u32;
22594}
22595
22596impl RowExt for DisplayRow {
22597    fn as_f32(&self) -> f32 {
22598        self.0 as f32
22599    }
22600
22601    fn next_row(&self) -> Self {
22602        Self(self.0 + 1)
22603    }
22604
22605    fn previous_row(&self) -> Self {
22606        Self(self.0.saturating_sub(1))
22607    }
22608
22609    fn minus(&self, other: Self) -> u32 {
22610        self.0 - other.0
22611    }
22612}
22613
22614impl RowExt for MultiBufferRow {
22615    fn as_f32(&self) -> f32 {
22616        self.0 as f32
22617    }
22618
22619    fn next_row(&self) -> Self {
22620        Self(self.0 + 1)
22621    }
22622
22623    fn previous_row(&self) -> Self {
22624        Self(self.0.saturating_sub(1))
22625    }
22626
22627    fn minus(&self, other: Self) -> u32 {
22628        self.0 - other.0
22629    }
22630}
22631
22632trait RowRangeExt {
22633    type Row;
22634
22635    fn len(&self) -> usize;
22636
22637    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22638}
22639
22640impl RowRangeExt for Range<MultiBufferRow> {
22641    type Row = MultiBufferRow;
22642
22643    fn len(&self) -> usize {
22644        (self.end.0 - self.start.0) as usize
22645    }
22646
22647    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22648        (self.start.0..self.end.0).map(MultiBufferRow)
22649    }
22650}
22651
22652impl RowRangeExt for Range<DisplayRow> {
22653    type Row = DisplayRow;
22654
22655    fn len(&self) -> usize {
22656        (self.end.0 - self.start.0) as usize
22657    }
22658
22659    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22660        (self.start.0..self.end.0).map(DisplayRow)
22661    }
22662}
22663
22664/// If select range has more than one line, we
22665/// just point the cursor to range.start.
22666fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22667    if range.start.row == range.end.row {
22668        range
22669    } else {
22670        range.start..range.start
22671    }
22672}
22673pub struct KillRing(ClipboardItem);
22674impl Global for KillRing {}
22675
22676const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22677
22678enum BreakpointPromptEditAction {
22679    Log,
22680    Condition,
22681    HitCondition,
22682}
22683
22684struct BreakpointPromptEditor {
22685    pub(crate) prompt: Entity<Editor>,
22686    editor: WeakEntity<Editor>,
22687    breakpoint_anchor: Anchor,
22688    breakpoint: Breakpoint,
22689    edit_action: BreakpointPromptEditAction,
22690    block_ids: HashSet<CustomBlockId>,
22691    editor_margins: Arc<Mutex<EditorMargins>>,
22692    _subscriptions: Vec<Subscription>,
22693}
22694
22695impl BreakpointPromptEditor {
22696    const MAX_LINES: u8 = 4;
22697
22698    fn new(
22699        editor: WeakEntity<Editor>,
22700        breakpoint_anchor: Anchor,
22701        breakpoint: Breakpoint,
22702        edit_action: BreakpointPromptEditAction,
22703        window: &mut Window,
22704        cx: &mut Context<Self>,
22705    ) -> Self {
22706        let base_text = match edit_action {
22707            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22708            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22709            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22710        }
22711        .map(|msg| msg.to_string())
22712        .unwrap_or_default();
22713
22714        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22715        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22716
22717        let prompt = cx.new(|cx| {
22718            let mut prompt = Editor::new(
22719                EditorMode::AutoHeight {
22720                    min_lines: 1,
22721                    max_lines: Self::MAX_LINES as usize,
22722                },
22723                buffer,
22724                None,
22725                window,
22726                cx,
22727            );
22728            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22729            prompt.set_show_cursor_when_unfocused(false, cx);
22730            prompt.set_placeholder_text(
22731                match edit_action {
22732                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22733                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22734                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22735                },
22736                cx,
22737            );
22738
22739            prompt
22740        });
22741
22742        Self {
22743            prompt,
22744            editor,
22745            breakpoint_anchor,
22746            breakpoint,
22747            edit_action,
22748            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22749            block_ids: Default::default(),
22750            _subscriptions: vec![],
22751        }
22752    }
22753
22754    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22755        self.block_ids.extend(block_ids)
22756    }
22757
22758    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22759        if let Some(editor) = self.editor.upgrade() {
22760            let message = self
22761                .prompt
22762                .read(cx)
22763                .buffer
22764                .read(cx)
22765                .as_singleton()
22766                .expect("A multi buffer in breakpoint prompt isn't possible")
22767                .read(cx)
22768                .as_rope()
22769                .to_string();
22770
22771            editor.update(cx, |editor, cx| {
22772                editor.edit_breakpoint_at_anchor(
22773                    self.breakpoint_anchor,
22774                    self.breakpoint.clone(),
22775                    match self.edit_action {
22776                        BreakpointPromptEditAction::Log => {
22777                            BreakpointEditAction::EditLogMessage(message.into())
22778                        }
22779                        BreakpointPromptEditAction::Condition => {
22780                            BreakpointEditAction::EditCondition(message.into())
22781                        }
22782                        BreakpointPromptEditAction::HitCondition => {
22783                            BreakpointEditAction::EditHitCondition(message.into())
22784                        }
22785                    },
22786                    cx,
22787                );
22788
22789                editor.remove_blocks(self.block_ids.clone(), None, cx);
22790                cx.focus_self(window);
22791            });
22792        }
22793    }
22794
22795    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22796        self.editor
22797            .update(cx, |editor, cx| {
22798                editor.remove_blocks(self.block_ids.clone(), None, cx);
22799                window.focus(&editor.focus_handle);
22800            })
22801            .log_err();
22802    }
22803
22804    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22805        let settings = ThemeSettings::get_global(cx);
22806        let text_style = TextStyle {
22807            color: if self.prompt.read(cx).read_only(cx) {
22808                cx.theme().colors().text_disabled
22809            } else {
22810                cx.theme().colors().text
22811            },
22812            font_family: settings.buffer_font.family.clone(),
22813            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22814            font_size: settings.buffer_font_size(cx).into(),
22815            font_weight: settings.buffer_font.weight,
22816            line_height: relative(settings.buffer_line_height.value()),
22817            ..Default::default()
22818        };
22819        EditorElement::new(
22820            &self.prompt,
22821            EditorStyle {
22822                background: cx.theme().colors().editor_background,
22823                local_player: cx.theme().players().local(),
22824                text: text_style,
22825                ..Default::default()
22826            },
22827        )
22828    }
22829}
22830
22831impl Render for BreakpointPromptEditor {
22832    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22833        let editor_margins = *self.editor_margins.lock();
22834        let gutter_dimensions = editor_margins.gutter;
22835        h_flex()
22836            .key_context("Editor")
22837            .bg(cx.theme().colors().editor_background)
22838            .border_y_1()
22839            .border_color(cx.theme().status().info_border)
22840            .size_full()
22841            .py(window.line_height() / 2.5)
22842            .on_action(cx.listener(Self::confirm))
22843            .on_action(cx.listener(Self::cancel))
22844            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22845            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22846    }
22847}
22848
22849impl Focusable for BreakpointPromptEditor {
22850    fn focus_handle(&self, cx: &App) -> FocusHandle {
22851        self.prompt.focus_handle(cx)
22852    }
22853}
22854
22855fn all_edits_insertions_or_deletions(
22856    edits: &Vec<(Range<Anchor>, String)>,
22857    snapshot: &MultiBufferSnapshot,
22858) -> bool {
22859    let mut all_insertions = true;
22860    let mut all_deletions = true;
22861
22862    for (range, new_text) in edits.iter() {
22863        let range_is_empty = range.to_offset(&snapshot).is_empty();
22864        let text_is_empty = new_text.is_empty();
22865
22866        if range_is_empty != text_is_empty {
22867            if range_is_empty {
22868                all_deletions = false;
22869            } else {
22870                all_insertions = false;
22871            }
22872        } else {
22873            return false;
22874        }
22875
22876        if !all_insertions && !all_deletions {
22877            return false;
22878        }
22879    }
22880    all_insertions || all_deletions
22881}
22882
22883struct MissingEditPredictionKeybindingTooltip;
22884
22885impl Render for MissingEditPredictionKeybindingTooltip {
22886    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22887        ui::tooltip_container(window, cx, |container, _, cx| {
22888            container
22889                .flex_shrink_0()
22890                .max_w_80()
22891                .min_h(rems_from_px(124.))
22892                .justify_between()
22893                .child(
22894                    v_flex()
22895                        .flex_1()
22896                        .text_ui_sm(cx)
22897                        .child(Label::new("Conflict with Accept Keybinding"))
22898                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22899                )
22900                .child(
22901                    h_flex()
22902                        .pb_1()
22903                        .gap_1()
22904                        .items_end()
22905                        .w_full()
22906                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22907                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22908                        }))
22909                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22910                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22911                        })),
22912                )
22913        })
22914    }
22915}
22916
22917#[derive(Debug, Clone, Copy, PartialEq)]
22918pub struct LineHighlight {
22919    pub background: Background,
22920    pub border: Option<gpui::Hsla>,
22921    pub include_gutter: bool,
22922    pub type_id: Option<TypeId>,
22923}
22924
22925fn render_diff_hunk_controls(
22926    row: u32,
22927    status: &DiffHunkStatus,
22928    hunk_range: Range<Anchor>,
22929    is_created_file: bool,
22930    line_height: Pixels,
22931    editor: &Entity<Editor>,
22932    _window: &mut Window,
22933    cx: &mut App,
22934) -> AnyElement {
22935    h_flex()
22936        .h(line_height)
22937        .mr_1()
22938        .gap_1()
22939        .px_0p5()
22940        .pb_1()
22941        .border_x_1()
22942        .border_b_1()
22943        .border_color(cx.theme().colors().border_variant)
22944        .rounded_b_lg()
22945        .bg(cx.theme().colors().editor_background)
22946        .gap_1()
22947        .block_mouse_except_scroll()
22948        .shadow_md()
22949        .child(if status.has_secondary_hunk() {
22950            Button::new(("stage", row as u64), "Stage")
22951                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22952                .tooltip({
22953                    let focus_handle = editor.focus_handle(cx);
22954                    move |window, cx| {
22955                        Tooltip::for_action_in(
22956                            "Stage Hunk",
22957                            &::git::ToggleStaged,
22958                            &focus_handle,
22959                            window,
22960                            cx,
22961                        )
22962                    }
22963                })
22964                .on_click({
22965                    let editor = editor.clone();
22966                    move |_event, _window, cx| {
22967                        editor.update(cx, |editor, cx| {
22968                            editor.stage_or_unstage_diff_hunks(
22969                                true,
22970                                vec![hunk_range.start..hunk_range.start],
22971                                cx,
22972                            );
22973                        });
22974                    }
22975                })
22976        } else {
22977            Button::new(("unstage", row as u64), "Unstage")
22978                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22979                .tooltip({
22980                    let focus_handle = editor.focus_handle(cx);
22981                    move |window, cx| {
22982                        Tooltip::for_action_in(
22983                            "Unstage Hunk",
22984                            &::git::ToggleStaged,
22985                            &focus_handle,
22986                            window,
22987                            cx,
22988                        )
22989                    }
22990                })
22991                .on_click({
22992                    let editor = editor.clone();
22993                    move |_event, _window, cx| {
22994                        editor.update(cx, |editor, cx| {
22995                            editor.stage_or_unstage_diff_hunks(
22996                                false,
22997                                vec![hunk_range.start..hunk_range.start],
22998                                cx,
22999                            );
23000                        });
23001                    }
23002                })
23003        })
23004        .child(
23005            Button::new(("restore", row as u64), "Restore")
23006                .tooltip({
23007                    let focus_handle = editor.focus_handle(cx);
23008                    move |window, cx| {
23009                        Tooltip::for_action_in(
23010                            "Restore Hunk",
23011                            &::git::Restore,
23012                            &focus_handle,
23013                            window,
23014                            cx,
23015                        )
23016                    }
23017                })
23018                .on_click({
23019                    let editor = editor.clone();
23020                    move |_event, window, cx| {
23021                        editor.update(cx, |editor, cx| {
23022                            let snapshot = editor.snapshot(window, cx);
23023                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23024                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23025                        });
23026                    }
23027                })
23028                .disabled(is_created_file),
23029        )
23030        .when(
23031            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23032            |el| {
23033                el.child(
23034                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23035                        .shape(IconButtonShape::Square)
23036                        .icon_size(IconSize::Small)
23037                        // .disabled(!has_multiple_hunks)
23038                        .tooltip({
23039                            let focus_handle = editor.focus_handle(cx);
23040                            move |window, cx| {
23041                                Tooltip::for_action_in(
23042                                    "Next Hunk",
23043                                    &GoToHunk,
23044                                    &focus_handle,
23045                                    window,
23046                                    cx,
23047                                )
23048                            }
23049                        })
23050                        .on_click({
23051                            let editor = editor.clone();
23052                            move |_event, window, cx| {
23053                                editor.update(cx, |editor, cx| {
23054                                    let snapshot = editor.snapshot(window, cx);
23055                                    let position =
23056                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23057                                    editor.go_to_hunk_before_or_after_position(
23058                                        &snapshot,
23059                                        position,
23060                                        Direction::Next,
23061                                        window,
23062                                        cx,
23063                                    );
23064                                    editor.expand_selected_diff_hunks(cx);
23065                                });
23066                            }
23067                        }),
23068                )
23069                .child(
23070                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23071                        .shape(IconButtonShape::Square)
23072                        .icon_size(IconSize::Small)
23073                        // .disabled(!has_multiple_hunks)
23074                        .tooltip({
23075                            let focus_handle = editor.focus_handle(cx);
23076                            move |window, cx| {
23077                                Tooltip::for_action_in(
23078                                    "Previous Hunk",
23079                                    &GoToPreviousHunk,
23080                                    &focus_handle,
23081                                    window,
23082                                    cx,
23083                                )
23084                            }
23085                        })
23086                        .on_click({
23087                            let editor = editor.clone();
23088                            move |_event, window, cx| {
23089                                editor.update(cx, |editor, cx| {
23090                                    let snapshot = editor.snapshot(window, cx);
23091                                    let point =
23092                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23093                                    editor.go_to_hunk_before_or_after_position(
23094                                        &snapshot,
23095                                        point,
23096                                        Direction::Prev,
23097                                        window,
23098                                        cx,
23099                                    );
23100                                    editor.expand_selected_diff_hunks(cx);
23101                                });
23102                            }
23103                        }),
23104                )
23105            },
23106        )
23107        .into_any_element()
23108}